Re: [PATCH v2 1/6] LSM: Ensure the correct LSM context releaser

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, Oct 14, 2024 at 08:14:45AM -0700, Casey Schaufler wrote:
> Add a new lsm_context data structure to hold all the information about a
> "security context", including the string, its size and which LSM allocated
> the string. The allocation information is necessary because LSMs have
> different policies regarding the lifecycle of these strings. SELinux
> allocates and destroys them on each use, whereas Smack provides a pointer
> to an entry in a list that never goes away.
> 
> Update security_release_secctx() to use the lsm_context instead of a
> (char *, len) pair. Change its callers to do likewise.  The LSMs
> supporting this hook have had comments added to remind the developer
> that there is more work to be done.
> 
> The BPF security module provides all LSM hooks. While there has yet to
> be a known instance of a BPF configuration that uses security contexts,
> the possibility is real. In the existing implementation there is
> potential for multiple frees in that case.
> 
> Signed-off-by: Casey Schaufler <casey@xxxxxxxxxxxxxxxx>

Thanks.

Reviewed-by: Serge Hallyn <sergeh@xxxxxxxxxx>

for the set (as far as affects lsm, of course).

> Cc: linux-integrity@xxxxxxxxxxxxxxx
> Cc: netdev@xxxxxxxxxxxxxxx
> Cc: audit@xxxxxxxxxxxxxxx
> Cc: netfilter-devel@xxxxxxxxxxxxxxx
> To: Pablo Neira Ayuso <pablo@xxxxxxxxxxxxx>
> Cc: linux-nfs@xxxxxxxxxxxxxxx
> Cc: Todd Kjos <tkjos@xxxxxxxxxx>
> ---
>  drivers/android/binder.c                | 24 ++++++-------
>  fs/ceph/xattr.c                         |  6 +++-
>  fs/nfs/nfs4proc.c                       |  8 +++--
>  fs/nfsd/nfs4xdr.c                       |  8 +++--
>  include/linux/lsm_hook_defs.h           |  2 +-
>  include/linux/security.h                | 35 +++++++++++++++++--
>  include/net/scm.h                       | 11 +++---
>  kernel/audit.c                          | 30 ++++++++---------
>  kernel/auditsc.c                        | 23 +++++++------
>  net/ipv4/ip_sockglue.c                  | 10 +++---
>  net/netfilter/nf_conntrack_netlink.c    | 10 +++---
>  net/netfilter/nf_conntrack_standalone.c |  9 +++--
>  net/netfilter/nfnetlink_queue.c         | 13 ++++---
>  net/netlabel/netlabel_unlabeled.c       | 45 +++++++++++--------------
>  net/netlabel/netlabel_user.c            | 11 +++---
>  security/apparmor/include/secid.h       |  2 +-
>  security/apparmor/secid.c               | 11 ++++--
>  security/security.c                     |  8 ++---
>  security/selinux/hooks.c                | 11 ++++--
>  19 files changed, 167 insertions(+), 110 deletions(-)
> 
> diff --git a/drivers/android/binder.c b/drivers/android/binder.c
> index 978740537a1a..d4229bf6f789 100644
> --- a/drivers/android/binder.c
> +++ b/drivers/android/binder.c
> @@ -3011,8 +3011,7 @@ static void binder_transaction(struct binder_proc *proc,
>  	struct binder_context *context = proc->context;
>  	int t_debug_id = atomic_inc_return(&binder_last_id);
>  	ktime_t t_start_time = ktime_get();
> -	char *secctx = NULL;
> -	u32 secctx_sz = 0;
> +	struct lsm_context lsmctx;
>  	struct list_head sgc_head;
>  	struct list_head pf_head;
>  	const void __user *user_buffer = (const void __user *)
> @@ -3291,7 +3290,8 @@ static void binder_transaction(struct binder_proc *proc,
>  		size_t added_size;
>  
>  		security_cred_getsecid(proc->cred, &secid);
> -		ret = security_secid_to_secctx(secid, &secctx, &secctx_sz);
> +		ret = security_secid_to_secctx(secid, &lsmctx.context,
> +					       &lsmctx.len);
>  		if (ret) {
>  			binder_txn_error("%d:%d failed to get security context\n",
>  				thread->pid, proc->pid);
> @@ -3300,7 +3300,7 @@ static void binder_transaction(struct binder_proc *proc,
>  			return_error_line = __LINE__;
>  			goto err_get_secctx_failed;
>  		}
> -		added_size = ALIGN(secctx_sz, sizeof(u64));
> +		added_size = ALIGN(lsmctx.len, sizeof(u64));
>  		extra_buffers_size += added_size;
>  		if (extra_buffers_size < added_size) {
>  			binder_txn_error("%d:%d integer overflow of extra_buffers_size\n",
> @@ -3334,23 +3334,23 @@ static void binder_transaction(struct binder_proc *proc,
>  		t->buffer = NULL;
>  		goto err_binder_alloc_buf_failed;
>  	}
> -	if (secctx) {
> +	if (lsmctx.context) {
>  		int err;
>  		size_t buf_offset = ALIGN(tr->data_size, sizeof(void *)) +
>  				    ALIGN(tr->offsets_size, sizeof(void *)) +
>  				    ALIGN(extra_buffers_size, sizeof(void *)) -
> -				    ALIGN(secctx_sz, sizeof(u64));
> +				    ALIGN(lsmctx.len, sizeof(u64));
>  
>  		t->security_ctx = t->buffer->user_data + buf_offset;
>  		err = binder_alloc_copy_to_buffer(&target_proc->alloc,
>  						  t->buffer, buf_offset,
> -						  secctx, secctx_sz);
> +						  lsmctx.context, lsmctx.len);
>  		if (err) {
>  			t->security_ctx = 0;
>  			WARN_ON(1);
>  		}
> -		security_release_secctx(secctx, secctx_sz);
> -		secctx = NULL;
> +		security_release_secctx(&lsmctx);
> +		lsmctx.context = NULL;
>  	}
>  	t->buffer->debug_id = t->debug_id;
>  	t->buffer->transaction = t;
> @@ -3394,7 +3394,7 @@ static void binder_transaction(struct binder_proc *proc,
>  	off_end_offset = off_start_offset + tr->offsets_size;
>  	sg_buf_offset = ALIGN(off_end_offset, sizeof(void *));
>  	sg_buf_end_offset = sg_buf_offset + extra_buffers_size -
> -		ALIGN(secctx_sz, sizeof(u64));
> +		ALIGN(lsmctx.len, sizeof(u64));
>  	off_min = 0;
>  	for (buffer_offset = off_start_offset; buffer_offset < off_end_offset;
>  	     buffer_offset += sizeof(binder_size_t)) {
> @@ -3773,8 +3773,8 @@ static void binder_transaction(struct binder_proc *proc,
>  	binder_alloc_free_buf(&target_proc->alloc, t->buffer);
>  err_binder_alloc_buf_failed:
>  err_bad_extra_size:
> -	if (secctx)
> -		security_release_secctx(secctx, secctx_sz);
> +	if (lsmctx.context)
> +		security_release_secctx(&lsmctx);
>  err_get_secctx_failed:
>  	kfree(tcomplete);
>  	binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE);
> diff --git a/fs/ceph/xattr.c b/fs/ceph/xattr.c
> index e066a556eccb..f7996770cc2c 100644
> --- a/fs/ceph/xattr.c
> +++ b/fs/ceph/xattr.c
> @@ -1446,12 +1446,16 @@ int ceph_security_init_secctx(struct dentry *dentry, umode_t mode,
>  
>  void ceph_release_acl_sec_ctx(struct ceph_acl_sec_ctx *as_ctx)
>  {
> +#ifdef CONFIG_CEPH_FS_SECURITY_LABEL
> +	struct lsm_context scaff; /* scaffolding */
> +#endif
>  #ifdef CONFIG_CEPH_FS_POSIX_ACL
>  	posix_acl_release(as_ctx->acl);
>  	posix_acl_release(as_ctx->default_acl);
>  #endif
>  #ifdef CONFIG_CEPH_FS_SECURITY_LABEL
> -	security_release_secctx(as_ctx->sec_ctx, as_ctx->sec_ctxlen);
> +	lsmcontext_init(&scaff, as_ctx->sec_ctx, as_ctx->sec_ctxlen, 0);
> +	security_release_secctx(&scaff);
>  #endif
>  #ifdef CONFIG_FS_ENCRYPTION
>  	kfree(as_ctx->fscrypt_auth);
> diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
> index cd2fbde2e6d7..76776d716744 100644
> --- a/fs/nfs/nfs4proc.c
> +++ b/fs/nfs/nfs4proc.c
> @@ -138,8 +138,12 @@ nfs4_label_init_security(struct inode *dir, struct dentry *dentry,
>  static inline void
>  nfs4_label_release_security(struct nfs4_label *label)
>  {
> -	if (label)
> -		security_release_secctx(label->label, label->len);
> +	struct lsm_context scaff; /* scaffolding */
> +
> +	if (label) {
> +		lsmcontext_init(&scaff, label->label, label->len, 0);
> +		security_release_secctx(&scaff);
> +	}
>  }
>  static inline u32 *nfs4_bitmask(struct nfs_server *server, struct nfs4_label *label)
>  {
> diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
> index f118921250c3..537ad363d70a 100644
> --- a/fs/nfsd/nfs4xdr.c
> +++ b/fs/nfsd/nfs4xdr.c
> @@ -3653,8 +3653,12 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
>  
>  out:
>  #ifdef CONFIG_NFSD_V4_SECURITY_LABEL
> -	if (args.context)
> -		security_release_secctx(args.context, args.contextlen);
> +	if (args.context) {
> +		struct lsm_context scaff; /* scaffolding */
> +
> +		lsmcontext_init(&scaff, args.context, args.contextlen, 0);
> +		security_release_secctx(&scaff);
> +	}
>  #endif /* CONFIG_NFSD_V4_SECURITY_LABEL */
>  	kfree(args.acl);
>  	if (tempfh) {
> diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
> index eb2937599cb0..c13df23132eb 100644
> --- a/include/linux/lsm_hook_defs.h
> +++ b/include/linux/lsm_hook_defs.h
> @@ -300,7 +300,7 @@ LSM_HOOK(int, -EOPNOTSUPP, secid_to_secctx, u32 secid, char **secdata,
>  LSM_HOOK(int, -EOPNOTSUPP, lsmprop_to_secctx, struct lsm_prop *prop,
>  	 char **secdata, u32 *seclen)
>  LSM_HOOK(int, 0, secctx_to_secid, const char *secdata, u32 seclen, u32 *secid)
> -LSM_HOOK(void, LSM_RET_VOID, release_secctx, char *secdata, u32 seclen)
> +LSM_HOOK(void, LSM_RET_VOID, release_secctx, struct lsm_context *cp)
>  LSM_HOOK(void, LSM_RET_VOID, inode_invalidate_secctx, struct inode *inode)
>  LSM_HOOK(int, 0, inode_notifysecctx, struct inode *inode, void *ctx, u32 ctxlen)
>  LSM_HOOK(int, 0, inode_setsecctx, struct dentry *dentry, void *ctx, u32 ctxlen)
> diff --git a/include/linux/security.h b/include/linux/security.h
> index fd690fa73162..1a3ca02224e8 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -225,6 +225,37 @@ extern unsigned long dac_mmap_min_addr;
>  #define dac_mmap_min_addr	0UL
>  #endif
>  
> +/*
> + * A "security context" is the text representation of
> + * the information used by LSMs.
> + * This structure contains the string, its length, and which LSM
> + * it is useful for.
> + */
> +struct lsm_context {
> +	char	*context;	/* Provided by the module */
> +	u32	len;
> +	int	id;		/* Identifies the module */
> +};
> +
> +/**
> + * lsmcontext_init - initialize an lsmcontext structure.
> + * @cp: Pointer to the context to initialize
> + * @context: Initial context, or NULL
> + * @size: Size of context, or 0
> + * @id: Which LSM provided the context
> + *
> + * Fill in the lsmcontext from the provided information.
> + * This is a scaffolding function that will be removed when
> + * lsm_context integration is complete.
> + */
> +static inline void lsmcontext_init(struct lsm_context *cp, char *context,
> +				   u32 size, int id)
> +{
> +	cp->id = id;
> +	cp->context = context;
> +	cp->len = size;
> +}
> +
>  /*
>   * Values used in the task_security_ops calls
>   */
> @@ -556,7 +587,7 @@ int security_ismaclabel(const char *name);
>  int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
>  int security_lsmprop_to_secctx(struct lsm_prop *prop, char **secdata, u32 *seclen);
>  int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
> -void security_release_secctx(char *secdata, u32 seclen);
> +void security_release_secctx(struct lsm_context *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);
> @@ -1545,7 +1576,7 @@ static inline int security_secctx_to_secid(const char *secdata,
>  	return -EOPNOTSUPP;
>  }
>  
> -static inline void security_release_secctx(char *secdata, u32 seclen)
> +static inline void security_release_secctx(struct lsm_context *cp)
>  {
>  }
>  
> diff --git a/include/net/scm.h b/include/net/scm.h
> index 0d35c7c77a74..f75449e1d876 100644
> --- a/include/net/scm.h
> +++ b/include/net/scm.h
> @@ -105,16 +105,17 @@ static __inline__ int scm_send(struct socket *sock, struct msghdr *msg,
>  #ifdef CONFIG_SECURITY_NETWORK
>  static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm)
>  {
> -	char *secdata;
> -	u32 seclen;
> +	struct lsm_context ctx;
>  	int err;
>  
>  	if (test_bit(SOCK_PASSSEC, &sock->flags)) {
> -		err = security_secid_to_secctx(scm->secid, &secdata, &seclen);
> +		err = security_secid_to_secctx(scm->secid, &ctx.context,
> +					       &ctx.len);
>  
>  		if (!err) {
> -			put_cmsg(msg, SOL_SOCKET, SCM_SECURITY, seclen, secdata);
> -			security_release_secctx(secdata, seclen);
> +			put_cmsg(msg, SOL_SOCKET, SCM_SECURITY, ctx.len,
> +				 ctx.context);
> +			security_release_secctx(&ctx);
>  		}
>  	}
>  }
> diff --git a/kernel/audit.c b/kernel/audit.c
> index d2797e8fe182..bafd8fd2b1f3 100644
> --- a/kernel/audit.c
> +++ b/kernel/audit.c
> @@ -1221,8 +1221,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
>  	struct audit_buffer	*ab;
>  	u16			msg_type = nlh->nlmsg_type;
>  	struct audit_sig_info   *sig_data;
> -	char			*ctx = NULL;
> -	u32			len;
> +	struct lsm_context	lsmctx;
>  
>  	err = audit_netlink_ok(skb, msg_type);
>  	if (err)
> @@ -1472,27 +1471,29 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
>  		break;
>  	}
>  	case AUDIT_SIGNAL_INFO:
> -		len = 0;
>  		if (lsmprop_is_set(&audit_sig_lsm)) {
> -			err = security_lsmprop_to_secctx(&audit_sig_lsm, &ctx,
> -							 &len);
> +			err = security_lsmprop_to_secctx(&audit_sig_lsm,
> +							 &lsmctx.context,
> +							 &lsmctx.len);
>  			if (err)
>  				return err;
>  		}
> -		sig_data = kmalloc(struct_size(sig_data, ctx, len), GFP_KERNEL);
> +		sig_data = kmalloc(struct_size(sig_data, ctx, lsmctx.len),
> +				   GFP_KERNEL);
>  		if (!sig_data) {
>  			if (lsmprop_is_set(&audit_sig_lsm))
> -				security_release_secctx(ctx, len);
> +				security_release_secctx(&lsmctx);
>  			return -ENOMEM;
>  		}
>  		sig_data->uid = from_kuid(&init_user_ns, audit_sig_uid);
>  		sig_data->pid = audit_sig_pid;
>  		if (lsmprop_is_set(&audit_sig_lsm)) {
> -			memcpy(sig_data->ctx, ctx, len);
> -			security_release_secctx(ctx, len);
> +			memcpy(sig_data->ctx, lsmctx.context, lsmctx.len);
> +			security_release_secctx(&lsmctx);
>  		}
>  		audit_send_reply(skb, seq, AUDIT_SIGNAL_INFO, 0, 0,
> -				 sig_data, struct_size(sig_data, ctx, len));
> +				 sig_data, struct_size(sig_data, ctx,
> +						       lsmctx.len));
>  		kfree(sig_data);
>  		break;
>  	case AUDIT_TTY_GET: {
> @@ -2180,23 +2181,22 @@ void audit_log_key(struct audit_buffer *ab, char *key)
>  int audit_log_task_context(struct audit_buffer *ab)
>  {
>  	struct lsm_prop prop;
> -	char *ctx = NULL;
> -	unsigned len;
> +	struct lsm_context ctx;
>  	int error;
>  
>  	security_current_getlsmprop_subj(&prop);
>  	if (!lsmprop_is_set(&prop))
>  		return 0;
>  
> -	error = security_lsmprop_to_secctx(&prop, &ctx, &len);
> +	error = security_lsmprop_to_secctx(&prop, &ctx.context, &ctx.len);
>  	if (error) {
>  		if (error != -EINVAL)
>  			goto error_path;
>  		return 0;
>  	}
>  
> -	audit_log_format(ab, " subj=%s", ctx);
> -	security_release_secctx(ctx, len);
> +	audit_log_format(ab, " subj=%s", ctx.context);
> +	security_release_secctx(&ctx);
>  	return 0;
>  
>  error_path:
> diff --git a/kernel/auditsc.c b/kernel/auditsc.c
> index f28fd513d047..c196dd4c9b54 100644
> --- a/kernel/auditsc.c
> +++ b/kernel/auditsc.c
> @@ -1098,8 +1098,7 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
>  				 char *comm)
>  {
>  	struct audit_buffer *ab;
> -	char *ctx = NULL;
> -	u32 len;
> +	struct lsm_context ctx;
>  	int rc = 0;
>  
>  	ab = audit_log_start(context, GFP_KERNEL, AUDIT_OBJ_PID);
> @@ -1110,12 +1109,12 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
>  			 from_kuid(&init_user_ns, auid),
>  			 from_kuid(&init_user_ns, uid), sessionid);
>  	if (lsmprop_is_set(prop)) {
> -		if (security_lsmprop_to_secctx(prop, &ctx, &len)) {
> +		if (security_lsmprop_to_secctx(prop, &ctx.context, &ctx.len)) {
>  			audit_log_format(ab, " obj=(none)");
>  			rc = 1;
>  		} else {
> -			audit_log_format(ab, " obj=%s", ctx);
> -			security_release_secctx(ctx, len);
> +			audit_log_format(ab, " obj=%s", ctx.context);
> +			security_release_secctx(&ctx);
>  		}
>  	}
>  	audit_log_format(ab, " ocomm=");
> @@ -1371,6 +1370,7 @@ static void audit_log_time(struct audit_context *context, struct audit_buffer **
>  
>  static void show_special(struct audit_context *context, int *call_panic)
>  {
> +	struct lsm_context lsmcxt;
>  	struct audit_buffer *ab;
>  	int i;
>  
> @@ -1401,7 +1401,8 @@ static void show_special(struct audit_context *context, int *call_panic)
>  				*call_panic = 1;
>  			} else {
>  				audit_log_format(ab, " obj=%s", ctx);
> -				security_release_secctx(ctx, len);
> +				lsmcontext_init(&lsmcxt, ctx, len, 0);
> +				security_release_secctx(&lsmcxt);
>  			}
>  		}
>  		if (context->ipc.has_perm) {
> @@ -1560,15 +1561,15 @@ static void audit_log_name(struct audit_context *context, struct audit_names *n,
>  				 MAJOR(n->rdev),
>  				 MINOR(n->rdev));
>  	if (lsmprop_is_set(&n->oprop)) {
> -		char *ctx = NULL;
> -		u32 len;
> +		struct lsm_context ctx;
>  
> -		if (security_lsmprop_to_secctx(&n->oprop, &ctx, &len)) {
> +		if (security_lsmprop_to_secctx(&n->oprop, &ctx.context,
> +					       &ctx.len)) {
>  			if (call_panic)
>  				*call_panic = 2;
>  		} else {
> -			audit_log_format(ab, " obj=%s", ctx);
> -			security_release_secctx(ctx, len);
> +			audit_log_format(ab, " obj=%s", ctx.context);
> +			security_release_secctx(&ctx);
>  		}
>  	}
>  
> diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
> index cf377377b52d..a8180dcc2a32 100644
> --- a/net/ipv4/ip_sockglue.c
> +++ b/net/ipv4/ip_sockglue.c
> @@ -128,20 +128,20 @@ static void ip_cmsg_recv_checksum(struct msghdr *msg, struct sk_buff *skb,
>  
>  static void ip_cmsg_recv_security(struct msghdr *msg, struct sk_buff *skb)
>  {
> -	char *secdata;
> -	u32 seclen, secid;
> +	struct lsm_context ctx;
> +	u32 secid;
>  	int err;
>  
>  	err = security_socket_getpeersec_dgram(NULL, skb, &secid);
>  	if (err)
>  		return;
>  
> -	err = security_secid_to_secctx(secid, &secdata, &seclen);
> +	err = security_secid_to_secctx(secid, &ctx.context, &ctx.len);
>  	if (err)
>  		return;
>  
> -	put_cmsg(msg, SOL_IP, SCM_SECURITY, seclen, secdata);
> -	security_release_secctx(secdata, seclen);
> +	put_cmsg(msg, SOL_IP, SCM_SECURITY, ctx.len, ctx.context);
> +	security_release_secctx(&ctx);
>  }
>  
>  static void ip_cmsg_recv_dstaddr(struct msghdr *msg, struct sk_buff *skb)
> diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
> index 6a1239433830..86a57a3afdd6 100644
> --- a/net/netfilter/nf_conntrack_netlink.c
> +++ b/net/netfilter/nf_conntrack_netlink.c
> @@ -357,10 +357,10 @@ static int ctnetlink_dump_mark(struct sk_buff *skb, const struct nf_conn *ct,
>  static int ctnetlink_dump_secctx(struct sk_buff *skb, const struct nf_conn *ct)
>  {
>  	struct nlattr *nest_secctx;
> -	int len, ret;
> -	char *secctx;
> +	struct lsm_context ctx;
> +	int ret;
>  
> -	ret = security_secid_to_secctx(ct->secmark, &secctx, &len);
> +	ret = security_secid_to_secctx(ct->secmark, &ctx.context, &ctx.len);
>  	if (ret)
>  		return 0;
>  
> @@ -369,13 +369,13 @@ static int ctnetlink_dump_secctx(struct sk_buff *skb, const struct nf_conn *ct)
>  	if (!nest_secctx)
>  		goto nla_put_failure;
>  
> -	if (nla_put_string(skb, CTA_SECCTX_NAME, secctx))
> +	if (nla_put_string(skb, CTA_SECCTX_NAME, ctx.context))
>  		goto nla_put_failure;
>  	nla_nest_end(skb, nest_secctx);
>  
>  	ret = 0;
>  nla_put_failure:
> -	security_release_secctx(secctx, len);
> +	security_release_secctx(&ctx);
>  	return ret;
>  }
>  #else
> diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c
> index 7d4f0fa8b609..5f7fd23b7afe 100644
> --- a/net/netfilter/nf_conntrack_standalone.c
> +++ b/net/netfilter/nf_conntrack_standalone.c
> @@ -172,17 +172,16 @@ static void ct_seq_stop(struct seq_file *s, void *v)
>  #ifdef CONFIG_NF_CONNTRACK_SECMARK
>  static void ct_show_secctx(struct seq_file *s, const struct nf_conn *ct)
>  {
> +	struct lsm_context ctx;
>  	int ret;
> -	u32 len;
> -	char *secctx;
>  
> -	ret = security_secid_to_secctx(ct->secmark, &secctx, &len);
> +	ret = security_secid_to_secctx(ct->secmark, &ctx.context, &ctx.len);
>  	if (ret)
>  		return;
>  
> -	seq_printf(s, "secctx=%s ", secctx);
> +	seq_printf(s, "secctx=%s ", ctx.context);
>  
> -	security_release_secctx(secctx, len);
> +	security_release_secctx(&ctx);
>  }
>  #else
>  static inline void ct_show_secctx(struct seq_file *s, const struct nf_conn *ct)
> diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
> index d2773ce9b585..37757cd77cf1 100644
> --- a/net/netfilter/nfnetlink_queue.c
> +++ b/net/netfilter/nfnetlink_queue.c
> @@ -567,6 +567,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
>  	enum ip_conntrack_info ctinfo = 0;
>  	const struct nfnl_ct_hook *nfnl_ct;
>  	bool csum_verify;
> +	struct lsm_context scaff; /* scaffolding */
>  	char *secdata = NULL;
>  	u32 seclen = 0;
>  	ktime_t tstamp;
> @@ -810,8 +811,10 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
>  	}
>  
>  	nlh->nlmsg_len = skb->len;
> -	if (seclen)
> -		security_release_secctx(secdata, seclen);
> +	if (seclen) {
> +		lsmcontext_init(&scaff, secdata, seclen, 0);
> +		security_release_secctx(&scaff);
> +	}
>  	return skb;
>  
>  nla_put_failure:
> @@ -819,8 +822,10 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
>  	kfree_skb(skb);
>  	net_err_ratelimited("nf_queue: error creating packet message\n");
>  nlmsg_failure:
> -	if (seclen)
> -		security_release_secctx(secdata, seclen);
> +	if (seclen) {
> +		lsmcontext_init(&scaff, secdata, seclen, 0);
> +		security_release_secctx(&scaff);
> +	}
>  	return NULL;
>  }
>  
> diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c
> index 1bc2d0890a9f..8303bbcfc543 100644
> --- a/net/netlabel/netlabel_unlabeled.c
> +++ b/net/netlabel/netlabel_unlabeled.c
> @@ -374,8 +374,7 @@ int netlbl_unlhsh_add(struct net *net,
>  	struct net_device *dev;
>  	struct netlbl_unlhsh_iface *iface;
>  	struct audit_buffer *audit_buf = NULL;
> -	char *secctx = NULL;
> -	u32 secctx_len;
> +	struct lsm_context ctx;
>  
>  	if (addr_len != sizeof(struct in_addr) &&
>  	    addr_len != sizeof(struct in6_addr))
> @@ -438,11 +437,10 @@ int netlbl_unlhsh_add(struct net *net,
>  unlhsh_add_return:
>  	rcu_read_unlock();
>  	if (audit_buf != NULL) {
> -		if (security_secid_to_secctx(secid,
> -					     &secctx,
> -					     &secctx_len) == 0) {
> -			audit_log_format(audit_buf, " sec_obj=%s", secctx);
> -			security_release_secctx(secctx, secctx_len);
> +		if (security_secid_to_secctx(secid, &ctx.context,
> +					     &ctx.len) == 0) {
> +			audit_log_format(audit_buf, " sec_obj=%s", ctx.context);
> +			security_release_secctx(&ctx);
>  		}
>  		audit_log_format(audit_buf, " res=%u", ret_val == 0 ? 1 : 0);
>  		audit_log_end(audit_buf);
> @@ -473,8 +471,7 @@ static int netlbl_unlhsh_remove_addr4(struct net *net,
>  	struct netlbl_unlhsh_addr4 *entry;
>  	struct audit_buffer *audit_buf;
>  	struct net_device *dev;
> -	char *secctx;
> -	u32 secctx_len;
> +	struct lsm_context ctx;
>  
>  	spin_lock(&netlbl_unlhsh_lock);
>  	list_entry = netlbl_af4list_remove(addr->s_addr, mask->s_addr,
> @@ -494,10 +491,10 @@ static int netlbl_unlhsh_remove_addr4(struct net *net,
>  					  addr->s_addr, mask->s_addr);
>  		dev_put(dev);
>  		if (entry != NULL &&
> -		    security_secid_to_secctx(entry->secid,
> -					     &secctx, &secctx_len) == 0) {
> -			audit_log_format(audit_buf, " sec_obj=%s", secctx);
> -			security_release_secctx(secctx, secctx_len);
> +		    security_secid_to_secctx(entry->secid, &ctx.context,
> +					     &ctx.len) == 0) {
> +			audit_log_format(audit_buf, " sec_obj=%s", ctx.context);
> +			security_release_secctx(&ctx);
>  		}
>  		audit_log_format(audit_buf, " res=%u", entry != NULL ? 1 : 0);
>  		audit_log_end(audit_buf);
> @@ -534,8 +531,7 @@ static int netlbl_unlhsh_remove_addr6(struct net *net,
>  	struct netlbl_unlhsh_addr6 *entry;
>  	struct audit_buffer *audit_buf;
>  	struct net_device *dev;
> -	char *secctx;
> -	u32 secctx_len;
> +	struct lsm_context ctx;
>  
>  	spin_lock(&netlbl_unlhsh_lock);
>  	list_entry = netlbl_af6list_remove(addr, mask, &iface->addr6_list);
> @@ -554,10 +550,10 @@ static int netlbl_unlhsh_remove_addr6(struct net *net,
>  					  addr, mask);
>  		dev_put(dev);
>  		if (entry != NULL &&
> -		    security_secid_to_secctx(entry->secid,
> -					     &secctx, &secctx_len) == 0) {
> -			audit_log_format(audit_buf, " sec_obj=%s", secctx);
> -			security_release_secctx(secctx, secctx_len);
> +		    security_secid_to_secctx(entry->secid, &ctx.context,
> +					     &ctx.len) == 0) {
> +			audit_log_format(audit_buf, " sec_obj=%s", ctx.context);
> +			security_release_secctx(&ctx);
>  		}
>  		audit_log_format(audit_buf, " res=%u", entry != NULL ? 1 : 0);
>  		audit_log_end(audit_buf);
> @@ -1069,10 +1065,9 @@ static int netlbl_unlabel_staticlist_gen(u32 cmd,
>  	int ret_val = -ENOMEM;
>  	struct netlbl_unlhsh_walk_arg *cb_arg = arg;
>  	struct net_device *dev;
> +	struct lsm_context ctx;
>  	void *data;
>  	u32 secid;
> -	char *secctx;
> -	u32 secctx_len;
>  
>  	data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).portid,
>  			   cb_arg->seq, &netlbl_unlabel_gnl_family,
> @@ -1127,14 +1122,14 @@ static int netlbl_unlabel_staticlist_gen(u32 cmd,
>  		secid = addr6->secid;
>  	}
>  
> -	ret_val = security_secid_to_secctx(secid, &secctx, &secctx_len);
> +	ret_val = security_secid_to_secctx(secid, &ctx.context, &ctx.len);
>  	if (ret_val != 0)
>  		goto list_cb_failure;
>  	ret_val = nla_put(cb_arg->skb,
>  			  NLBL_UNLABEL_A_SECCTX,
> -			  secctx_len,
> -			  secctx);
> -	security_release_secctx(secctx, secctx_len);
> +			  ctx.len,
> +			  ctx.context);
> +	security_release_secctx(&ctx);
>  	if (ret_val != 0)
>  		goto list_cb_failure;
>  
> diff --git a/net/netlabel/netlabel_user.c b/net/netlabel/netlabel_user.c
> index 81635a13987b..f5e7a9919df1 100644
> --- a/net/netlabel/netlabel_user.c
> +++ b/net/netlabel/netlabel_user.c
> @@ -84,8 +84,7 @@ struct audit_buffer *netlbl_audit_start_common(int type,
>  					       struct netlbl_audit *audit_info)
>  {
>  	struct audit_buffer *audit_buf;
> -	char *secctx;
> -	u32 secctx_len;
> +	struct lsm_context ctx;
>  
>  	if (audit_enabled == AUDIT_OFF)
>  		return NULL;
> @@ -99,10 +98,10 @@ struct audit_buffer *netlbl_audit_start_common(int type,
>  			 audit_info->sessionid);
>  
>  	if (lsmprop_is_set(&audit_info->prop) &&
> -	    security_lsmprop_to_secctx(&audit_info->prop, &secctx,
> -				       &secctx_len) == 0) {
> -		audit_log_format(audit_buf, " subj=%s", secctx);
> -		security_release_secctx(secctx, secctx_len);
> +	    security_lsmprop_to_secctx(&audit_info->prop, &ctx.context,
> +				       &ctx.len) == 0) {
> +		audit_log_format(audit_buf, " subj=%s", ctx.context);
> +		security_release_secctx(&ctx);
>  	}
>  
>  	return audit_buf;
> diff --git a/security/apparmor/include/secid.h b/security/apparmor/include/secid.h
> index cc6d1c9f4a47..8b92f90b6921 100644
> --- a/security/apparmor/include/secid.h
> +++ b/security/apparmor/include/secid.h
> @@ -29,7 +29,7 @@ int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
>  int apparmor_lsmprop_to_secctx(struct lsm_prop *prop, char **secdata,
>  			       u32 *seclen);
>  int apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
> -void apparmor_release_secctx(char *secdata, u32 seclen);
> +void apparmor_release_secctx(struct lsm_context *cp);
>  
>  
>  int aa_alloc_secid(struct aa_label *label, gfp_t gfp);
> diff --git a/security/apparmor/secid.c b/security/apparmor/secid.c
> index 6350d107013a..8d9ced8cdffd 100644
> --- a/security/apparmor/secid.c
> +++ b/security/apparmor/secid.c
> @@ -120,9 +120,16 @@ int apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
>  	return 0;
>  }
>  
> -void apparmor_release_secctx(char *secdata, u32 seclen)
> +void apparmor_release_secctx(struct lsm_context *cp)
>  {
> -	kfree(secdata);
> +	/*
> +	 * stacking scaffolding:
> +	 * When it is possible for more than one LSM to provide a
> +	 * release hook, do this check:
> +	 * if (cp->id == LSM_ID_APPARMOR || cp->id == LSM_ID_UNDEF)
> +	 */
> +
> +	kfree(cp->context);
>  }
>  
>  /**
> diff --git a/security/security.c b/security/security.c
> index 0003d5ace5cc..0c9c3a02704b 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -4365,14 +4365,14 @@ EXPORT_SYMBOL(security_secctx_to_secid);
>  
>  /**
>   * security_release_secctx() - Free a secctx buffer
> - * @secdata: secctx
> - * @seclen: length of secctx
> + * @cp: the security context
>   *
>   * Release the security context.
>   */
> -void security_release_secctx(char *secdata, u32 seclen)
> +void security_release_secctx(struct lsm_context *cp)
>  {
> -	call_void_hook(release_secctx, secdata, seclen);
> +	call_void_hook(release_secctx, cp);
> +	memset(cp, 0, sizeof(*cp));
>  }
>  EXPORT_SYMBOL(security_release_secctx);
>  
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index 025b60c5b605..1503d398c87d 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -6624,9 +6624,16 @@ static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
>  				       secid, GFP_KERNEL);
>  }
>  
> -static void selinux_release_secctx(char *secdata, u32 seclen)
> +static void selinux_release_secctx(struct lsm_context *cp)
>  {
> -	kfree(secdata);
> +	/*
> +	 * stacking scaffolding:
> +	 * When it is possible for more than one LSM to provide a
> +	 * release hook, do this check:
> +	 * if (cp->id == LSM_ID_SELINUX || cp->id == LSM_ID_UNDEF)
> +	 */
> +
> +	kfree(cp->context);
>  }
>  
>  static void selinux_inode_invalidate_secctx(struct inode *inode)
> -- 
> 2.46.0
> 




[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux Kernel]     [Linux Kernel Hardening]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux SCSI]

  Powered by Linux