]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
lsm: ensure the correct LSM context releaser
authorCasey Schaufler <casey@schaufler-ca.com>
Wed, 23 Oct 2024 21:21:54 +0000 (14:21 -0700)
committerPaul Moore <paul@paul-moore.com>
Wed, 4 Dec 2024 15:46:26 +0000 (10:46 -0500)
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.

Cc: linux-integrity@vger.kernel.org
Cc: netdev@vger.kernel.org
Cc: audit@vger.kernel.org
Cc: netfilter-devel@vger.kernel.org
To: Pablo Neira Ayuso <pablo@netfilter.org>
Cc: linux-nfs@vger.kernel.org
Cc: Todd Kjos <tkjos@google.com>
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
[PM: subject tweak]
Signed-off-by: Paul Moore <paul@paul-moore.com>
19 files changed:
drivers/android/binder.c
fs/ceph/xattr.c
fs/nfs/nfs4proc.c
fs/nfsd/nfs4xdr.c
include/linux/lsm_hook_defs.h
include/linux/security.h
include/net/scm.h
kernel/audit.c
kernel/auditsc.c
net/ipv4/ip_sockglue.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nf_conntrack_standalone.c
net/netfilter/nfnetlink_queue.c
net/netlabel/netlabel_unlabeled.c
net/netlabel/netlabel_user.c
security/apparmor/include/secid.h
security/apparmor/secid.c
security/security.c
security/selinux/hooks.c

index ef353ca13c356acac42b08e4e2fed41a360ccb4f..e8245df632891fc09f84e8495ecc104777d5ccf6 100644 (file)
@@ -3017,8 +3017,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 *)
@@ -3297,7 +3296,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);
@@ -3306,7 +3306,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",
@@ -3340,23 +3340,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;
@@ -3400,7 +3400,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)) {
@@ -3779,8 +3779,8 @@ err_copy_data_failed:
        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);
index 1a9f12204666637307d102815fb530bf0a84efc8..2a14335a4bb7e492e61e644f2fdce4f3e1b145a6 100644 (file)
@@ -1446,12 +1446,16 @@ out:
 
 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);
index 405f17e6e0b45b26cebae06c5bbe932895af9a56..2daeb6f663d9811058231675d1ff4a707068413a 100644 (file)
@@ -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)
 {
index 53fac037611c05ff8ba2618f9e324a9cb54c3890..95ec6a4b4da346d5d913546498e6bccf40a7fbcd 100644 (file)
@@ -3644,8 +3644,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) {
index eb2937599cb029004f491012b3bf5a3d6d2731df..c13df23132eb5186a436ca440bdd198881e4d14b 100644 (file)
@@ -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)
index cbdba435b798660130779d6919388779edd41d54..68e56935716b78a8ebae0c4cc7a19cd04267d70f 100644 (file)
@@ -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)
 {
 }
 
index 0d35c7c77a74c3f8afe06f288c935104ebf27078..f75449e1d876a8bceb0a9792c2c960127ba8b309 100644 (file)
@@ -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);
                }
        }
 }
index 6a95a6077953cc8e926017e90bd659dd64798f57..1d48d0654a4630eb343a3e7292967f49edcb9472 100644 (file)
@@ -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:
index 279ba5c420a4943bfed226b795aa4da7bb2bb93f..de8fac6c5bd39d3535d3771a5f8513faef605ad3 100644 (file)
@@ -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);
                }
        }
 
index cf377377b52d83fbc7ac979b02b5ca9a7d9abf4a..a8180dcc2a32b6fed5d70569c0df3449db692149 100644 (file)
@@ -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)
index 36168f8b6efa3c7d69320aa091df12e43179aec8..22f46be33f1ec06a04fe2c3fa07e1ad735bd236a 100644 (file)
@@ -357,10 +357,10 @@ nla_put_failure:
 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
index 7d4f0fa8b609d810164d458d7f22caf82b995b49..5f7fd23b7afe794510284d41c131590a1f9b7c14 100644 (file)
@@ -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)
index d2773ce9b58533f14d9a72050d2b0075ca4f61ac..37757cd77cf1bbe12cfaa5e18383634617bb3a88 100644 (file)
@@ -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 @@ nla_put_failure:
        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;
 }
 
index 1bc2d0890a9f1050d4592ea73bf4127b1b168620..921fa8eeb451df9336f670580c8cf54aff34a9d6 100644 (file)
@@ -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))
@@ -439,10 +438,10 @@ 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);
+                                            &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 +472,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,
@@ -495,9 +493,9 @@ static int netlbl_unlhsh_remove_addr4(struct net *net,
                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);
+                                            &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 +532,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);
@@ -555,9 +552,9 @@ static int netlbl_unlhsh_remove_addr6(struct net *net,
                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);
+                                            &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 +1066,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 +1123,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;
 
index 81635a13987b114af063f3c41c6fb847e40b0066..f5e7a9919df1fbff2e0b80099298207660e2a9ba 100644 (file)
@@ -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;
index f6a515640950ffee5b8ed911ab318805d90b179d..1bcde2f45f24256789ea8d093cf286c13185dd3b 100644 (file)
@@ -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);
index 47dc08fc583e9ac486909c0bf3f31dcef5600370..43e4dab7f6e64ea71ea2ddeb2e9f04a684dda15f 100644 (file)
@@ -106,9 +106,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);
 }
 
 /**
index 09664e09fec9a1d502a23847aa2e87a6d19837db..b7f8ec93f6f04b89748ff0d46d2eda351fbfdf7a 100644 (file)
@@ -4360,14 +4360,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);
 
index f5a08f94e09402b6b0b1538fae1a7a3f5af19fe6..aabc724f4d44224d3ccf05bb3aabd53afd9aecf6 100644 (file)
@@ -6657,9 +6657,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)