]> git.proxmox.com Git - mirror_ubuntu-kernels.git/commitdiff
UBUNTU: SAUCE: LSM: Ensure the correct LSM context releaser
authorCasey Schaufler <casey@schaufler-ca.com>
Thu, 20 Aug 2020 18:47:01 +0000 (11:47 -0700)
committerAndrea Righi <andrea.righi@canonical.com>
Thu, 9 Mar 2023 14:57:24 +0000 (15:57 +0100)
Add a new lsmcontext 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.

Reviewed-by: Kees Cook <keescook@chromium.org>
Reviewed-by: John Johansen <john.johansen@canonical.com>
Acked-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
Cc: linux-integrity@vger.kernel.org
Cc: netdev@vger.kernel.org
Signed-off-by: John Johansen <john.johansen@canonical.com>
Acked-by: Andrea Righi <andrea.righi@canonical.com>
Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
15 files changed:
drivers/android/binder.c
fs/ceph/xattr.c
fs/nfs/nfs4proc.c
fs/nfsd/nfs4xdr.c
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/security.c

index 60283870793495c5116e14de2e5b1af0529eeea2..eb87e2e061f73c02dec41131ffa90c67d5eb8754 100644 (file)
@@ -2898,6 +2898,7 @@ static void binder_transaction(struct binder_proc *proc,
        int t_debug_id = atomic_inc_return(&binder_last_id);
        char *secctx = NULL;
        u32 secctx_sz = 0;
+       struct lsmcontext scaff; /* scaffolding */
        struct list_head sgc_head;
        struct list_head pf_head;
        const void __user *user_buffer = (const void __user *)
@@ -3231,7 +3232,8 @@ static void binder_transaction(struct binder_proc *proc,
                        t->security_ctx = 0;
                        WARN_ON(1);
                }
-               security_release_secctx(secctx, secctx_sz);
+               lsmcontext_init(&scaff, secctx, secctx_sz, 0);
+               security_release_secctx(&scaff);
                secctx = NULL;
        }
        t->buffer->debug_id = t->debug_id;
@@ -3647,8 +3649,10 @@ 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 (secctx) {
+               lsmcontext_init(&scaff, secctx, secctx_sz, 0);
+               security_release_secctx(&scaff);
+       }
 err_get_secctx_failed:
        kfree(tcomplete);
        binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE);
index f31350cda960bb087fd3bfc1163f4db15f23858d..d943be72dfff67cd1cd7613717fb3a8bd56e1de9 100644 (file)
@@ -1395,12 +1395,16 @@ out:
 
 void ceph_release_acl_sec_ctx(struct ceph_acl_sec_ctx *as_ctx)
 {
+#ifdef CONFIG_CEPH_FS_SECURITY_LABEL
+       struct lsmcontext 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
        if (as_ctx->pagelist)
                ceph_pagelist_release(as_ctx->pagelist);
index 40d749f29ed3fe98de6c81f5bbd83eff9caa4a16..eadea6f56934704267a54b022b426a98bce0886d 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 lsmcontext 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 97edb32be77f187832c479a76ea3a29ffd7c80a6..e652552699db1530c7690b6fd6ffd0705a329b82 100644 (file)
@@ -2944,6 +2944,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;
 #endif
@@ -3452,8 +3453,10 @@ out_acl:
 
 out:
 #ifdef CONFIG_NFSD_V4_SECURITY_LABEL
-       if (context)
-               security_release_secctx(context, contextlen);
+       if (context) {
+               lsmcontext_init(&scaff, context, contextlen, 0); /*scaffolding*/
+               security_release_secctx(&scaff);
+       }
 #endif /* CONFIG_NFSD_V4_SECURITY_LABEL */
        kfree(acl);
        if (tempfh) {
index 0528559696875243383f536a70fe03b07b35d366..4f79dee964fb213e315bd500011f51537a06f26b 100644 (file)
@@ -139,6 +139,37 @@ enum lockdown_reason {
 
 extern const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX+1];
 
+/*
+ * 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 lsmcontext {
+       char    *context;       /* Provided by the module */
+       u32     len;
+       int     slot;           /* 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
+ * @slot: Which LSM provided the context
+ *
+ * Fill in the lsmcontext from the provided information.
+ * This is a scaffolding function that will be removed when
+ * lsmcontext integration is complete.
+ */
+static inline void lsmcontext_init(struct lsmcontext *cp, char *context,
+                                  u32 size, int slot)
+{
+       cp->slot = slot;
+       cp->context = context;
+       cp->len = size;
+}
+
 /*
  * Data exported by the security modules
  *
@@ -562,7 +593,7 @@ int security_ismaclabel(const char *name);
 int security_secid_to_secctx(struct lsmblob *blob, char **secdata, u32 *seclen);
 int security_secctx_to_secid(const char *secdata, u32 seclen,
                             struct lsmblob *blob);
-void security_release_secctx(char *secdata, u32 seclen);
+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);
@@ -1464,7 +1495,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 lsmcontext *cp)
 {
 }
 
index 31ae605fcc0ab43c1e7f392928087905e6c0ffb6..30ba801c91bdde7041877218ba20e2215832c75c 100644 (file)
@@ -92,6 +92,7 @@ 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)
 {
+       struct lsmcontext context;
        char *secdata;
        u32 seclen;
        int err;
@@ -102,7 +103,9 @@ static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct sc
 
                if (!err) {
                        put_cmsg(msg, SOL_SOCKET, SCM_SECURITY, seclen, secdata);
-                       security_release_secctx(secdata, seclen);
+                       /*scaffolding*/
+                       lsmcontext_init(&context, secdata, seclen, 0);
+                       security_release_secctx(&context);
                }
        }
 }
index ae1fca128fb613d3c433152c4916bdeaa62aa2a7..bf081623a94b6094d118e3a208bcb45882ef6729 100644 (file)
@@ -1212,6 +1212,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
        struct audit_sig_info   *sig_data;
        char                    *ctx = NULL;
        u32                     len;
+       struct lsmcontext       scaff; /* scaffolding */
 
        err = audit_netlink_ok(skb, msg_type);
        if (err)
@@ -1469,15 +1470,18 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                }
                sig_data = kmalloc(struct_size(sig_data, ctx, len), GFP_KERNEL);
                if (!sig_data) {
-                       if (lsmblob_is_set(&audit_sig_lsm))
-                               security_release_secctx(ctx, len);
+                       if (lsmblob_is_set(&audit_sig_lsm)) {
+                               lsmcontext_init(&scaff, ctx, len, 0);
+                               security_release_secctx(&scaff);
+                       }
                        return -ENOMEM;
                }
                sig_data->uid = from_kuid(&init_user_ns, audit_sig_uid);
                sig_data->pid = audit_sig_pid;
                if (lsmblob_is_set(&audit_sig_lsm)) {
                        memcpy(sig_data->ctx, ctx, len);
-                       security_release_secctx(ctx, len);
+                       lsmcontext_init(&scaff, ctx, len, 0);
+                       security_release_secctx(&scaff);
                }
                audit_send_reply(skb, seq, AUDIT_SIGNAL_INFO, 0, 0,
                                 sig_data, struct_size(sig_data, ctx, len));
@@ -2170,6 +2174,7 @@ int audit_log_task_context(struct audit_buffer *ab)
        int error;
        u32 sid;
        struct lsmblob blob;
+       struct lsmcontext scaff; /* scaffolding */
 
        security_current_getsecid_subj(&blob);
        if (!lsmblob_is_set(&blob))
@@ -2183,7 +2188,8 @@ int audit_log_task_context(struct audit_buffer *ab)
        }
 
        audit_log_format(ab, " subj=%s", ctx);
-       security_release_secctx(ctx, len);
+       lsmcontext_init(&scaff, ctx, len, 0);
+       security_release_secctx(&scaff);
        return 0;
 
 error_path:
index 89d4e4518489f158ac932cf853175ef1aad511f4..ae4fe60d7e75dd741de61fbfd65b7630306ac62f 100644 (file)
@@ -1102,6 +1102,7 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
                                 struct lsmblob *blob, char *comm)
 {
        struct audit_buffer *ab;
+       struct lsmcontext lsmcxt;
        char *ctx = NULL;
        u32 len;
        int rc = 0;
@@ -1119,7 +1120,8 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
                        rc = 1;
                } else {
                        audit_log_format(ab, " obj=%s", ctx);
-                       security_release_secctx(ctx, len);
+                       lsmcontext_init(&lsmcxt, ctx, len, 0); /*scaffolding*/
+                       security_release_secctx(&lsmcxt);
                }
        }
        audit_log_format(ab, " ocomm=");
@@ -1379,6 +1381,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 lsmcontext lsmcxt;
        struct audit_buffer *ab;
        int i;
 
@@ -1413,7 +1416,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) {
@@ -1575,6 +1579,7 @@ static void audit_log_name(struct audit_context *context, struct audit_names *n,
                char *ctx = NULL;
                u32 len;
                struct lsmblob blob;
+               struct lsmcontext lsmcxt;
 
                lsmblob_init(&blob, n->osid);
                if (security_secid_to_secctx(&blob, &ctx, &len)) {
@@ -1583,7 +1588,8 @@ static void audit_log_name(struct audit_context *context, struct audit_names *n,
                                *call_panic = 2;
                } else {
                        audit_log_format(ab, " obj=%s", ctx);
-                       security_release_secctx(ctx, len);
+                       lsmcontext_init(&lsmcxt, ctx, len, 0); /* scaffolding */
+                       security_release_secctx(&lsmcxt);
                }
        }
 
index 47a369400d370e23f85216bc7a12ef46a13f2b91..00ca33187f391f4010013a5098c1b0196205d49d 100644 (file)
@@ -130,6 +130,7 @@ 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)
 {
+       struct lsmcontext context;
        struct lsmblob lb;
        char *secdata;
        u32 seclen;
@@ -144,7 +145,8 @@ static void ip_cmsg_recv_security(struct msghdr *msg, struct sk_buff *skb)
                return;
 
        put_cmsg(msg, SOL_IP, SCM_SECURITY, seclen, secdata);
-       security_release_secctx(secdata, seclen);
+       lsmcontext_init(&context, secdata, seclen, 0); /* scaffolding */
+       security_release_secctx(&context);
 }
 
 static void ip_cmsg_recv_dstaddr(struct msghdr *msg, struct sk_buff *skb)
index e5a34d80ac939a997655cfedef0e5151db08fe71..e93eff6e0b49c68f387443ca232603541a68db5d 100644 (file)
@@ -353,6 +353,7 @@ static int ctnetlink_dump_secctx(struct sk_buff *skb, const struct nf_conn *ct)
        int len, ret;
        char *secctx;
        struct lsmblob blob;
+       struct lsmcontext context;
 
        /* lsmblob_init() puts ct->secmark into all of the secids in blob.
         * security_secid_to_secctx() will know which security module
@@ -373,7 +374,8 @@ static int ctnetlink_dump_secctx(struct sk_buff *skb, const struct nf_conn *ct)
 
        ret = 0;
 nla_put_failure:
-       security_release_secctx(secctx, len);
+       lsmcontext_init(&context, secctx, len, 0); /* scaffolding */
+       security_release_secctx(&context);
        return ret;
 }
 #else
index f99b9ac57bfb328884578d475e6d32a831702b12..c1a1ca47901b0cff7d640038aa8ced0f389405f8 100644 (file)
@@ -179,6 +179,7 @@ static void ct_show_secctx(struct seq_file *s, const struct nf_conn *ct)
        u32 len;
        char *secctx;
        struct lsmblob blob;
+       struct lsmcontext context;
 
        lsmblob_init(&blob, ct->secmark);
        ret = security_secid_to_secctx(&blob, &secctx, &len);
@@ -187,7 +188,8 @@ static void ct_show_secctx(struct seq_file *s, const struct nf_conn *ct)
 
        seq_printf(s, "secctx=%s ", secctx);
 
-       security_release_secctx(secctx, len);
+       lsmcontext_init(&context, secctx, len, 0); /* scaffolding */
+       security_release_secctx(&context);
 }
 #else
 static inline void ct_show_secctx(struct seq_file *s, const struct nf_conn *ct)
index bc25d49575e4da8a0db4400ce2b1bb34ab52cfe9..1416f8b2fc8314700ef17684fb5f55e6094b8484 100644 (file)
@@ -397,6 +397,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 lsmcontext scaff; /* scaffolding */
        char *secdata = NULL;
        u32 seclen = 0;
        ktime_t tstamp;
@@ -634,8 +635,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:
@@ -643,8 +646,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 2d550c3d19b46ab82dd206210ceed69762f1349d..e6fa1f61f9ea92a10efec96c7d65f3959a2d3cc3 100644 (file)
@@ -374,6 +374,7 @@ int netlbl_unlhsh_add(struct net *net,
        struct net_device *dev;
        struct netlbl_unlhsh_iface *iface;
        struct audit_buffer *audit_buf = NULL;
+       struct lsmcontext context;
        char *secctx = NULL;
        u32 secctx_len;
        struct lsmblob blob;
@@ -447,7 +448,9 @@ unlhsh_add_return:
                                             &secctx,
                                             &secctx_len) == 0) {
                        audit_log_format(audit_buf, " sec_obj=%s", secctx);
-                       security_release_secctx(secctx, secctx_len);
+                       /* scaffolding */
+                       lsmcontext_init(&context, secctx, secctx_len, 0);
+                       security_release_secctx(&context);
                }
                audit_log_format(audit_buf, " res=%u", ret_val == 0 ? 1 : 0);
                audit_log_end(audit_buf);
@@ -478,6 +481,7 @@ static int netlbl_unlhsh_remove_addr4(struct net *net,
        struct netlbl_unlhsh_addr4 *entry;
        struct audit_buffer *audit_buf;
        struct net_device *dev;
+       struct lsmcontext context;
        char *secctx;
        u32 secctx_len;
        struct lsmblob blob;
@@ -508,7 +512,9 @@ static int netlbl_unlhsh_remove_addr4(struct net *net,
                    security_secid_to_secctx(&blob,
                                             &secctx, &secctx_len) == 0) {
                        audit_log_format(audit_buf, " sec_obj=%s", secctx);
-                       security_release_secctx(secctx, secctx_len);
+                       /* scaffolding */
+                       lsmcontext_init(&context, secctx, secctx_len, 0);
+                       security_release_secctx(&context);
                }
                audit_log_format(audit_buf, " res=%u", entry != NULL ? 1 : 0);
                audit_log_end(audit_buf);
@@ -545,6 +551,7 @@ static int netlbl_unlhsh_remove_addr6(struct net *net,
        struct netlbl_unlhsh_addr6 *entry;
        struct audit_buffer *audit_buf;
        struct net_device *dev;
+       struct lsmcontext context;
        char *secctx;
        u32 secctx_len;
        struct lsmblob blob;
@@ -574,7 +581,8 @@ static int netlbl_unlhsh_remove_addr6(struct net *net,
                    security_secid_to_secctx(&blob,
                                             &secctx, &secctx_len) == 0) {
                        audit_log_format(audit_buf, " sec_obj=%s", secctx);
-                       security_release_secctx(secctx, secctx_len);
+                       lsmcontext_init(&context, secctx, secctx_len, 0);
+                       security_release_secctx(&context);
                }
                audit_log_format(audit_buf, " res=%u", entry != NULL ? 1 : 0);
                audit_log_end(audit_buf);
@@ -1093,6 +1101,7 @@ 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 lsmcontext context;
        void *data;
        u32 secid;
        char *secctx;
@@ -1163,7 +1172,9 @@ static int netlbl_unlabel_staticlist_gen(u32 cmd,
                          NLBL_UNLABEL_A_SECCTX,
                          secctx_len,
                          secctx);
-       security_release_secctx(secctx, secctx_len);
+       /* scaffolding */
+       lsmcontext_init(&context, secctx, secctx_len, 0);
+       security_release_secctx(&context);
        if (ret_val != 0)
                goto list_cb_failure;
 
index 893301ae013142678b7b96125622b81c0776781a..ef139d8ae7cd60b9d9729ca6f1a787376a9bd349 100644 (file)
@@ -84,6 +84,7 @@ struct audit_buffer *netlbl_audit_start_common(int type,
                                               struct netlbl_audit *audit_info)
 {
        struct audit_buffer *audit_buf;
+       struct lsmcontext context;
        char *secctx;
        u32 secctx_len;
        struct lsmblob blob;
@@ -103,7 +104,8 @@ struct audit_buffer *netlbl_audit_start_common(int type,
        if (audit_info->secid != 0 &&
            security_secid_to_secctx(&blob, &secctx, &secctx_len) == 0) {
                audit_log_format(audit_buf, " subj=%s", secctx);
-               security_release_secctx(secctx, secctx_len);
+               lsmcontext_init(&context, secctx, secctx_len, 0);/*scaffolding*/
+               security_release_secctx(&context);
        }
 
        return audit_buf;
index 60c257d8f285e3d55ea47a1c896430f026c1d3b3..f23c5a1495f2629194b60fa42dee5eea3ea03246 100644 (file)
@@ -2418,16 +2418,17 @@ int security_secctx_to_secid(const char *secdata, u32 seclen,
 }
 EXPORT_SYMBOL(security_secctx_to_secid);
 
-void security_release_secctx(char *secdata, u32 seclen)
+void security_release_secctx(struct lsmcontext *cp)
 {
        struct security_hook_list *hp;
-       int display = lsm_task_display(current);
 
        hlist_for_each_entry(hp, &security_hook_heads.release_secctx, list)
-               if (display == LSMBLOB_INVALID || display == hp->lsmid->slot) {
-                       hp->hook.release_secctx(secdata, seclen);
-                       return;
+               if (cp->slot == hp->lsmid->slot) {
+                       hp->hook.release_secctx(cp->context, cp->len);
+                       break;
                }
+
+       memset(cp, 0, sizeof(*cp));
 }
 EXPORT_SYMBOL(security_release_secctx);