On 7/24/20 1:32 PM, Casey Schaufler wrote:
 Change the security_inode_getsecctx() interface to fill
 a lsmcontext structure instead of data and length pointers.
 This provides the information about which LSM created the
 context so that security_release_secctx() can use the
 correct hook.
  
Reviewed-by: John Johansen <john.johansen(a)canonical.com>
 Acked-by: Stephen Smalley <sds(a)tycho.nsa.gov>
 Signed-off-by: Casey Schaufler <casey(a)schaufler-ca.com>
 ---
  fs/nfsd/nfs4xdr.c        | 23 +++++++++--------------
  include/linux/security.h |  5 +++--
  security/security.c      | 13 +++++++++++--
  3 files changed, 23 insertions(+), 18 deletions(-)
 
 diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
 index 61d6b8a0e8f0..6673221d5606 100644
 --- a/fs/nfsd/nfs4xdr.c
 +++ b/fs/nfsd/nfs4xdr.c
 @@ -2379,11 +2379,11 @@ nfsd4_encode_layout_types(struct xdr_stream *xdr, u32
layout_types)
  #ifdef CONFIG_NFSD_V4_SECURITY_LABEL
  static inline __be32
  nfsd4_encode_security_label(struct xdr_stream *xdr, struct svc_rqst *rqstp,
 -			    void *context, int len)
 +			    struct lsmcontext *context)
  {
  	__be32 *p;
  
 -	p = xdr_reserve_space(xdr, len + 4 + 4 + 4);
 +	p = xdr_reserve_space(xdr, context->len + 4 + 4 + 4);
  	if (!p)
  		return nfserr_resource;
  
 @@ -2393,13 +2393,13 @@ nfsd4_encode_security_label(struct xdr_stream *xdr, struct
svc_rqst *rqstp,
  	 */
  	*p++ = cpu_to_be32(0); /* lfs */
  	*p++ = cpu_to_be32(0); /* pi */
 -	p = xdr_encode_opaque(p, context, len);
 +	p = xdr_encode_opaque(p, context->context, context->len);
  	return 0;
  }
  #else
  static inline __be32
  nfsd4_encode_security_label(struct xdr_stream *xdr, struct svc_rqst *rqstp,
 -			    void *context, int len)
 +			    struct lsmcontext *context)
  { return 0; }
  #endif
  
 @@ -2496,9 +2496,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
  	int err;
  	struct nfs4_acl *acl = NULL;
  #ifdef CONFIG_NFSD_V4_SECURITY_LABEL
 -	struct lsmcontext scaff; /* scaffolding */
 -	void *context = NULL;
 -	int contextlen;
 +	struct lsmcontext context = { };
  #endif
  	bool contextsupport = false;
  	struct nfsd4_compoundres *resp = rqstp->rq_resp;
 @@ -2556,7 +2554,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
  	     bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) {
  		if (exp->ex_flags & NFSEXP_SECURITY_LABEL)
  			err = security_inode_getsecctx(d_inode(dentry),
 -						&context, &contextlen);
 +						       &context);
  		else
  			err = -EOPNOTSUPP;
  		contextsupport = (err == 0);
 @@ -2986,8 +2984,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
  
  #ifdef CONFIG_NFSD_V4_SECURITY_LABEL
  	if (bmval2 & FATTR4_WORD2_SECURITY_LABEL) {
 -		status = nfsd4_encode_security_label(xdr, rqstp, context,
 -								contextlen);
 +		status = nfsd4_encode_security_label(xdr, rqstp, &context);
  		if (status)
  			goto out;
  	}
 @@ -2999,10 +2996,8 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
  
  out:
  #ifdef CONFIG_NFSD_V4_SECURITY_LABEL
 -	if (context) {
 -		lsmcontext_init(&scaff, context, contextlen, 0); /*scaffolding*/
 -		security_release_secctx(&scaff);
 -	}
 +	if (context.context)
 +		security_release_secctx(&context);
  #endif /* CONFIG_NFSD_V4_SECURITY_LABEL */
  	kfree(acl);
  	if (tempfh) {
 diff --git a/include/linux/security.h b/include/linux/security.h
 index 43f8a2660d37..02dc3b5ef57b 100644
 --- a/include/linux/security.h
 +++ b/include/linux/security.h
 @@ -560,7 +560,7 @@ void security_release_secctx(struct lsmcontext *cp);
  void security_inode_invalidate_secctx(struct inode *inode);
  int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen);
  int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen);
 -int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen);
 +int security_inode_getsecctx(struct inode *inode, struct lsmcontext *cp);
  int security_locked_down(enum lockdown_reason what);
  #else /* CONFIG_SECURITY */
  
 @@ -1399,7 +1399,8 @@ static inline int security_inode_setsecctx(struct dentry *dentry,
void *ctx, u32
  {
  	return -EOPNOTSUPP;
  }
 -static inline int security_inode_getsecctx(struct inode *inode, void **ctx, u32
*ctxlen)
 +static inline int security_inode_getsecctx(struct inode *inode,
 +					   struct lsmcontext *cp)
  {
  	return -EOPNOTSUPP;
  }
 diff --git a/security/security.c b/security/security.c
 index 862f0bc2f114..ddbaf2073b02 100644
 --- a/security/security.c
 +++ b/security/security.c
 @@ -2263,9 +2263,18 @@ int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32
ctxlen)
  }
  EXPORT_SYMBOL(security_inode_setsecctx);
  
 -int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
 +int security_inode_getsecctx(struct inode *inode, struct lsmcontext *cp)
  {
 -	return call_int_hook(inode_getsecctx, -EOPNOTSUPP, inode, ctx, ctxlen);
 +	struct security_hook_list *hp;
 +
 +	memset(cp, 0, sizeof(*cp));
 +
 +	hlist_for_each_entry(hp, &security_hook_heads.inode_getsecctx, list) {
 +		cp->slot = hp->lsmid->slot;
 +		return hp->hook.inode_getsecctx(inode, (void **)&cp->context,
 +						&cp->len);
 +	}
 +	return -EOPNOTSUPP;
  }
  EXPORT_SYMBOL(security_inode_getsecctx);