On Mon, Apr 06, 2020 at 05:01:56PM -0700, Casey Schaufler wrote: > Create a new audit record type to contain the subject information > when there are multiple security modules that require such data. > This record is emitted before the other records for the event, but > is linked with the same timestamp and serial number. > > Signed-off-by: Casey Schaufler <casey@xxxxxxxxxxxxxxxx> Reviewed-by: Kees Cook <keescook@xxxxxxxxxxxx> -Kees > Cc: linux-audit@xxxxxxxxxx > --- > drivers/android/binder.c | 2 +- > include/linux/security.h | 9 +++- > include/net/scm.h | 3 +- > include/uapi/linux/audit.h | 1 + > kernel/audit.c | 56 +++++++++++++++++++------ > kernel/auditsc.c | 7 ++-- > net/ipv4/ip_sockglue.c | 2 +- > net/netfilter/nf_conntrack_netlink.c | 4 +- > net/netfilter/nf_conntrack_standalone.c | 2 +- > net/netfilter/nfnetlink_queue.c | 2 +- > net/netlabel/netlabel_unlabeled.c | 11 +++-- > net/netlabel/netlabel_user.c | 2 +- > security/security.c | 51 ++++++++++++++++++++-- > 13 files changed, 118 insertions(+), 34 deletions(-) > > diff --git a/drivers/android/binder.c b/drivers/android/binder.c > index c76fc2abd091..e79c4948ab12 100644 > --- a/drivers/android/binder.c > +++ b/drivers/android/binder.c > @@ -3109,7 +3109,7 @@ static void binder_transaction(struct binder_proc *proc, > size_t added_size; > > security_task_getsecid(proc->tsk, &blob); > - ret = security_secid_to_secctx(&blob, &lsmctx); > + ret = security_secid_to_secctx(&blob, &lsmctx, LSMBLOB_DISPLAY); > if (ret) { > return_error = BR_FAILED_REPLY; > return_error_param = ret; > diff --git a/include/linux/security.h b/include/linux/security.h > index fac5547dd89e..896b939f5d62 100644 > --- a/include/linux/security.h > +++ b/include/linux/security.h > @@ -178,6 +178,8 @@ struct lsmblob { > #define LSMBLOB_INVALID -1 /* Not a valid LSM slot number */ > #define LSMBLOB_NEEDED -2 /* Slot requested on initialization */ > #define LSMBLOB_NOT_NEEDED -3 /* Slot not requested */ > +#define LSMBLOB_DISPLAY -4 /* Use the "display" slot */ > +#define LSMBLOB_FIRST -5 /* Use the default "display" slot */ > > /** > * lsmblob_init - initialize an lsmblob structure. > @@ -240,6 +242,8 @@ static inline u32 lsmblob_value(const struct lsmblob *blob) > return 0; > } > > +const char *security_lsm_slot_name(int slot); > + > /* These functions are in security/commoncap.c */ > extern int cap_capable(const struct cred *cred, struct user_namespace *ns, > int cap, unsigned int opts); > @@ -549,7 +553,8 @@ int security_setprocattr(const char *lsm, const char *name, void *value, > size_t size); > int security_netlink_send(struct sock *sk, struct sk_buff *skb); > int security_ismaclabel(const char *name); > -int security_secid_to_secctx(struct lsmblob *blob, struct lsmcontext *cp); > +int security_secid_to_secctx(struct lsmblob *blob, struct lsmcontext *cp, > + int display); > int security_secctx_to_secid(const char *secdata, u32 seclen, > struct lsmblob *blob); > void security_release_secctx(struct lsmcontext *cp); > @@ -1354,7 +1359,7 @@ static inline int security_ismaclabel(const char *name) > } > > static inline int security_secid_to_secctx(struct lsmblob *blob, > - struct lsmcontext *cp) > + struct lsmcontext *cp, int display) > { > return -EOPNOTSUPP; > } > diff --git a/include/net/scm.h b/include/net/scm.h > index 4a6ad8caf423..8b5a4737e1b8 100644 > --- a/include/net/scm.h > +++ b/include/net/scm.h > @@ -96,7 +96,8 @@ static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct sc > int err; > > if (test_bit(SOCK_PASSSEC, &sock->flags)) { > - err = security_secid_to_secctx(&scm->lsmblob, &context); > + err = security_secid_to_secctx(&scm->lsmblob, &context, > + LSMBLOB_DISPLAY); > > if (!err) { > put_cmsg(msg, SOL_SOCKET, SCM_SECURITY, > diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h > index a534d71e689a..2e6dbf907ee3 100644 > --- a/include/uapi/linux/audit.h > +++ b/include/uapi/linux/audit.h > @@ -138,6 +138,7 @@ > #define AUDIT_MAC_UNLBL_STCDEL 1417 /* NetLabel: del a static label */ > #define AUDIT_MAC_CALIPSO_ADD 1418 /* NetLabel: add CALIPSO DOI entry */ > #define AUDIT_MAC_CALIPSO_DEL 1419 /* NetLabel: del CALIPSO DOI entry */ > +#define AUDIT_MAC_TASK_CONTEXTS 1420 /* Multiple LSM contexts */ > > #define AUDIT_FIRST_KERN_ANOM_MSG 1700 > #define AUDIT_LAST_KERN_ANOM_MSG 1799 > diff --git a/kernel/audit.c b/kernel/audit.c > index 013a90dd2bd5..00a4fbecfdf7 100644 > --- a/kernel/audit.c > +++ b/kernel/audit.c > @@ -1419,7 +1419,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) > case AUDIT_SIGNAL_INFO: > if (lsmblob_is_set(&audit_sig_lsm)) { > err = security_secid_to_secctx(&audit_sig_lsm, > - &context); > + &context, LSMBLOB_FIRST); > if (err) > return err; > } > @@ -2058,28 +2058,58 @@ void audit_log_key(struct audit_buffer *ab, char *key) > > int audit_log_task_context(struct audit_buffer *ab) > { > + int i; > int error; > + bool sep = false; > struct lsmblob blob; > - struct lsmcontext context; > + struct lsmcontext lsmdata; > + struct audit_buffer *lsmab = NULL; > + struct audit_context *context = NULL; > > security_task_getsecid(current, &blob); > if (!lsmblob_is_set(&blob)) > return 0; > > - error = security_secid_to_secctx(&blob, &context); > - if (error) { > - if (error != -EINVAL) > - goto error_path; > - return 0; > + /* > + * If there is more than one security module that has a > + * subject "context" it's necessary to put the subject data > + * into a separate record to maintain compatibility. > + */ > + if (security_lsm_slot_name(1) != NULL) { > + audit_log_format(ab, " subj=?"); > + context = ab->ctx; > + if (context) > + lsmab = audit_log_start(context, GFP_KERNEL, > + AUDIT_MAC_TASK_CONTEXTS); > } > > - audit_log_format(ab, " subj=%s", context.context); > - security_release_secctx(&context); > - return 0; > + for (i = 0; i < LSMBLOB_ENTRIES; i++) { > + if (blob.secid[i] == 0) > + continue; > + error = security_secid_to_secctx(&blob, &lsmdata, i); > + if (error && error != -EINVAL) { > + audit_panic("error in audit_log_task_context"); > + return error; > + } > + > + if (context) { > + audit_log_format(lsmab, "%ssubj_%s=%s", > + sep ? " " : "", > + security_lsm_slot_name(i), > + lsmdata.context); > + sep = true; > + } else > + audit_log_format(ab, " subj=%s", lsmdata.context); > + > + security_release_secctx(&lsmdata); > + if (!context) > + break; > + } > + > + if (context) > + audit_log_end(lsmab); > > -error_path: > - audit_panic("error in audit_log_task_context"); > - return error; > + return 0; > } > EXPORT_SYMBOL(audit_log_task_context); > > diff --git a/kernel/auditsc.c b/kernel/auditsc.c > index b7275860ba5f..4df540c32581 100644 > --- a/kernel/auditsc.c > +++ b/kernel/auditsc.c > @@ -980,7 +980,7 @@ 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 (lsmblob_is_set(blob)) { > - if (security_secid_to_secctx(blob, &lsmctx)) { > + if (security_secid_to_secctx(blob, &lsmctx, LSMBLOB_FIRST)) { > audit_log_format(ab, " obj=(none)"); > rc = 1; > } else { > @@ -1225,7 +1225,8 @@ static void show_special(struct audit_context *context, int *call_panic) > struct lsmblob blob; > > lsmblob_init(&blob, osid); > - if (security_secid_to_secctx(&blob, &lsmcxt)) { > + if (security_secid_to_secctx(&blob, &lsmcxt, > + LSMBLOB_FIRST)) { > audit_log_format(ab, " osid=%u", osid); > *call_panic = 1; > } else { > @@ -1377,7 +1378,7 @@ static void audit_log_name(struct audit_context *context, struct audit_names *n, > struct lsmcontext lsmctx; > > lsmblob_init(&blob, n->osid); > - if (security_secid_to_secctx(&blob, &lsmctx)) { > + if (security_secid_to_secctx(&blob, &lsmctx, LSMBLOB_FIRST)) { > audit_log_format(ab, " osid=%u", n->osid); > if (call_panic) > *call_panic = 2; > diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c > index 27af7a6b8780..10b418029cdd 100644 > --- a/net/ipv4/ip_sockglue.c > +++ b/net/ipv4/ip_sockglue.c > @@ -138,7 +138,7 @@ static void ip_cmsg_recv_security(struct msghdr *msg, struct sk_buff *skb) > if (err) > return; > > - err = security_secid_to_secctx(&lb, &context); > + err = security_secid_to_secctx(&lb, &context, LSMBLOB_DISPLAY); > if (err) > return; > > diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c > index 2fa1e5bd781d..cd559fada596 100644 > --- a/net/netfilter/nf_conntrack_netlink.c > +++ b/net/netfilter/nf_conntrack_netlink.c > @@ -337,7 +337,7 @@ static int ctnetlink_dump_secctx(struct sk_buff *skb, const struct nf_conn *ct) > * security_secid_to_secctx() will know which security module > * to use to create the secctx. */ > lsmblob_init(&blob, ct->secmark); > - ret = security_secid_to_secctx(&blob, &context); > + ret = security_secid_to_secctx(&blob, &context, LSMBLOB_DISPLAY); > if (ret) > return 0; > > @@ -651,7 +651,7 @@ static inline int ctnetlink_secctx_size(const struct nf_conn *ct) > struct lsmblob blob; > struct lsmcontext context; > > - ret = security_secid_to_secctx(&blob, &context); > + ret = security_secid_to_secctx(&blob, &context, LSMBLOB_DISPLAY); > if (ret) > return 0; > > diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c > index 383a4f44be63..9551e8be6ca4 100644 > --- a/net/netfilter/nf_conntrack_standalone.c > +++ b/net/netfilter/nf_conntrack_standalone.c > @@ -177,7 +177,7 @@ static void ct_show_secctx(struct seq_file *s, const struct nf_conn *ct) > struct lsmcontext context; > > lsmblob_init(&blob, ct->secmark); > - ret = security_secid_to_secctx(&blob, &context); > + ret = security_secid_to_secctx(&blob, &context, LSMBLOB_DISPLAY); > if (ret) > return; > > diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c > index d07900c317fd..dc8902f8cea2 100644 > --- a/net/netfilter/nfnetlink_queue.c > +++ b/net/netfilter/nfnetlink_queue.c > @@ -316,7 +316,7 @@ static u32 nfqnl_get_sk_secctx(struct sk_buff *skb, struct lsmcontext *context) > * blob. security_secid_to_secctx() will know which security > * module to use to create the secctx. */ > lsmblob_init(&blob, skb->secmark); > - security_secid_to_secctx(&blob, context); > + security_secid_to_secctx(&blob, context, LSMBLOB_DISPLAY); > } > > read_unlock_bh(&skb->sk->sk_callback_lock); > diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c > index c14a485ff045..d816909866cc 100644 > --- a/net/netlabel/netlabel_unlabeled.c > +++ b/net/netlabel/netlabel_unlabeled.c > @@ -437,7 +437,8 @@ int netlbl_unlhsh_add(struct net *net, > unlhsh_add_return: > rcu_read_unlock(); > if (audit_buf != NULL) { > - if (security_secid_to_secctx(lsmblob, &context) == 0) { > + if (security_secid_to_secctx(lsmblob, &context, > + LSMBLOB_FIRST) == 0) { > audit_log_format(audit_buf, " sec_obj=%s", > context.context); > security_release_secctx(&context); > @@ -492,7 +493,8 @@ static int netlbl_unlhsh_remove_addr4(struct net *net, > if (dev != NULL) > dev_put(dev); > if (entry != NULL && > - security_secid_to_secctx(&entry->lsmblob, &context) == 0) { > + security_secid_to_secctx(&entry->lsmblob, &context, > + LSMBLOB_FIRST) == 0) { > audit_log_format(audit_buf, " sec_obj=%s", > context.context); > security_release_secctx(&context); > @@ -552,7 +554,8 @@ static int netlbl_unlhsh_remove_addr6(struct net *net, > if (dev != NULL) > dev_put(dev); > if (entry != NULL && > - security_secid_to_secctx(&entry->lsmblob, &context) == 0) { > + security_secid_to_secctx(&entry->lsmblob, &context, > + LSMBLOB_FIRST) == 0) { > audit_log_format(audit_buf, " sec_obj=%s", > context.context); > security_release_secctx(&context); > @@ -1122,7 +1125,7 @@ static int netlbl_unlabel_staticlist_gen(u32 cmd, > lsmb = (struct lsmblob *)&addr6->lsmblob; > } > > - ret_val = security_secid_to_secctx(lsmb, &context); > + ret_val = security_secid_to_secctx(lsmb, &context, LSMBLOB_FIRST); > if (ret_val != 0) > goto list_cb_failure; > ret_val = nla_put(cb_arg->skb, > diff --git a/net/netlabel/netlabel_user.c b/net/netlabel/netlabel_user.c > index 951ba0639d20..1941877fd16f 100644 > --- a/net/netlabel/netlabel_user.c > +++ b/net/netlabel/netlabel_user.c > @@ -100,7 +100,7 @@ struct audit_buffer *netlbl_audit_start_common(int type, > > lsmblob_init(&blob, audit_info->secid); > if (audit_info->secid != 0 && > - security_secid_to_secctx(&blob, &context) == 0) { > + security_secid_to_secctx(&blob, &context, LSMBLOB_FIRST) == 0) { > audit_log_format(audit_buf, " subj=%s", context.context); > security_release_secctx(&context); > } > diff --git a/security/security.c b/security/security.c > index b7c2ed1eee42..d3bf71d66724 100644 > --- a/security/security.c > +++ b/security/security.c > @@ -480,7 +480,31 @@ static int lsm_append(const char *new, char **result) > * Pointers to the LSM id structures for local use. > */ > static int lsm_slot __lsm_ro_after_init; > -static struct lsm_id *lsm_slotlist[LSMBLOB_ENTRIES]; > +static struct lsm_id *lsm_slotlist[LSMBLOB_ENTRIES] __lsm_ro_after_init; > + > +/** > + * security_lsm_slot_name - Get the name of the security module in a slot > + * @slot: index into the "display" slot list. > + * > + * Provide the name of the security module associated with > + * a display slot. > + * > + * If @slot is LSMBLOB_INVALID return the value > + * for slot 0 if it has been set, otherwise NULL. > + * > + * Returns a pointer to the name string or NULL. > + */ > +const char *security_lsm_slot_name(int slot) > +{ > + if (slot == LSMBLOB_INVALID) > + slot = 0; > + else if (slot >= LSMBLOB_ENTRIES || slot < 0) > + return NULL; > + > + if (lsm_slotlist[slot] == NULL) > + return NULL; > + return lsm_slotlist[slot]->lsm; > +} > > /** > * security_add_hooks - Add a modules hooks to the hook lists. > @@ -2169,13 +2193,32 @@ int security_ismaclabel(const char *name) > } > EXPORT_SYMBOL(security_ismaclabel); > > -int security_secid_to_secctx(struct lsmblob *blob, struct lsmcontext *cp) > +int security_secid_to_secctx(struct lsmblob *blob, struct lsmcontext *cp, > + int display) > { > struct security_hook_list *hp; > - int display = lsm_task_display(current); > > memset(cp, 0, sizeof(*cp)); > > + /* > + * display either is the slot number use for formatting > + * or an instruction on which relative slot to use. > + */ > + if (display == LSMBLOB_DISPLAY) > + display = lsm_task_display(current); > + else if (display == LSMBLOB_FIRST) > + display = LSMBLOB_INVALID; > + else if (display < 0) { > + WARN_ONCE(true, > + "LSM: %s unknown display\n", __func__); > + display = LSMBLOB_INVALID; > + } else if (display >= lsm_slot) { > + WARN_ONCE(true, > + "LSM: %s invalid display\n", __func__); > + display = LSMBLOB_INVALID; > + } > + > + > hlist_for_each_entry(hp, &security_hook_heads.secid_to_secctx, list) { > if (WARN_ON(hp->lsmid->slot < 0 || hp->lsmid->slot >= lsm_slot)) > continue; > @@ -2186,7 +2229,7 @@ int security_secid_to_secctx(struct lsmblob *blob, struct lsmcontext *cp) > &cp->context, &cp->len); > } > } > - return 0; > + return -EOPNOTSUPP; > } > EXPORT_SYMBOL(security_secid_to_secctx); > > -- > 2.24.1 > -- Kees Cook