diff mbox series

[v20,20/23] Audit: Add new record for multiple process LSM attributes

Message ID 20200826145247.10029-21-casey@schaufler-ca.com
State New
Headers show
Series LSM: Module stacking for AppArmor | expand

Commit Message

Casey Schaufler Aug. 26, 2020, 2:52 p.m. UTC
Create a new audit record type to contain the subject information
when there are multiple security modules that require such data.
This record is linked with the same timestamp and serial number.
The record is produced only in cases where there is more than one
security module with a process "context".

Before this change the only audit events that required multiple
records were syscall events. Several non-syscall events include
subject contexts, so the use of audit_context data has been expanded
as necessary.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
Cc: linux-audit@redhat.com
---
 drivers/android/binder.c                |  2 +-
 include/linux/audit.h                   | 13 +++-
 include/linux/security.h                | 18 ++++-
 include/net/netlabel.h                  |  2 +-
 include/net/scm.h                       |  3 +-
 include/net/xfrm.h                      |  4 +-
 include/uapi/linux/audit.h              |  1 +
 kernel/audit.c                          | 89 ++++++++++++++++++-------
 kernel/auditfilter.c                    |  2 +-
 kernel/auditsc.c                        | 87 ++++++++++++++++++++++--
 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       | 16 ++---
 net/netlabel/netlabel_user.c            | 12 ++--
 net/netlabel/netlabel_user.h            |  6 +-
 security/integrity/integrity_audit.c    |  2 +-
 security/security.c                     | 73 +++++++++++++++-----
 security/smack/smackfs.c                |  3 +-
 20 files changed, 259 insertions(+), 84 deletions(-)

Comments

James Morris Sept. 3, 2020, 4:32 p.m. UTC | #1
On Wed, 26 Aug 2020, 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 linked with the same timestamp and serial number.
> The record is produced only in cases where there is more than one
> security module with a process "context".
> 
> Before this change the only audit events that required multiple
> records were syscall events. Several non-syscall events include
> subject contexts, so the use of audit_context data has been expanded
> as necessary.
> 
> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> Cc: linux-audit@redhat.com

Paul, can you review/ack the audit changes?

> ---
>  drivers/android/binder.c                |  2 +-
>  include/linux/audit.h                   | 13 +++-
>  include/linux/security.h                | 18 ++++-
>  include/net/netlabel.h                  |  2 +-
>  include/net/scm.h                       |  3 +-
>  include/net/xfrm.h                      |  4 +-
>  include/uapi/linux/audit.h              |  1 +
>  kernel/audit.c                          | 89 ++++++++++++++++++-------
>  kernel/auditfilter.c                    |  2 +-
>  kernel/auditsc.c                        | 87 ++++++++++++++++++++++--
>  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       | 16 ++---
>  net/netlabel/netlabel_user.c            | 12 ++--
>  net/netlabel/netlabel_user.h            |  6 +-
>  security/integrity/integrity_audit.c    |  2 +-
>  security/security.c                     | 73 +++++++++++++++-----
>  security/smack/smackfs.c                |  3 +-
>  20 files changed, 259 insertions(+), 84 deletions(-)
> 
> diff --git a/drivers/android/binder.c b/drivers/android/binder.c
> index 0bde1b96680e..93781dad0c28 100644
> --- a/drivers/android/binder.c
> +++ b/drivers/android/binder.c
> @@ -3113,7 +3113,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/audit.h b/include/linux/audit.h
> index ba1cd38d601b..fe027df0d9a8 100644
> --- a/include/linux/audit.h
> +++ b/include/linux/audit.h
> @@ -186,7 +186,9 @@ extern void		    audit_log_path_denied(int type,
>  						  const char *operation);
>  extern void		    audit_log_lost(const char *message);
>  
> -extern int audit_log_task_context(struct audit_buffer *ab);
> +extern void audit_log_lsm(struct lsmblob *blob, bool exiting);
> +extern int audit_log_task_context(struct audit_buffer *ab,
> +				  struct lsmblob *blob);
>  extern void audit_log_task_info(struct audit_buffer *ab);
>  
>  extern int		    audit_update_lsm_rules(void);
> @@ -246,7 +248,10 @@ static inline void audit_log_key(struct audit_buffer *ab, char *key)
>  { }
>  static inline void audit_log_path_denied(int type, const char *operation)
>  { }
> -static inline int audit_log_task_context(struct audit_buffer *ab)
> +static inline void audit_log_lsm(struct lsmblob *blob, bool exiting)
> +{ }
> +static inline int audit_log_task_context(struct audit_buffer *ab,
> +					 struct lsmblob *blob);
>  {
>  	return 0;
>  }
> @@ -305,6 +310,7 @@ extern void audit_seccomp(unsigned long syscall, long signr, int code);
>  extern void audit_seccomp_actions_logged(const char *names,
>  					 const char *old_names, int res);
>  extern void __audit_ptrace(struct task_struct *t);
> +extern void audit_stamp_context(struct audit_context *ctx);
>  
>  static inline void audit_set_context(struct task_struct *task, struct audit_context *ctx)
>  {
> @@ -682,6 +688,9 @@ static inline void audit_ntp_log(const struct audit_ntp_data *ad)
>  static inline void audit_ptrace(struct task_struct *t)
>  { }
>  
> +static inline void audit_stamp_context(struct audit_context *ctx)
> +{ }
> +
>  static inline void audit_log_nfcfg(const char *name, u8 af,
>  				   unsigned int nentries,
>  				   enum audit_nfcfgop op, gfp_t gfp)
> diff --git a/include/linux/security.h b/include/linux/security.h
> index 40260bfc3a0d..3cbe24be1563 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -180,6 +180,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.
> @@ -242,6 +244,17 @@ static inline u32 lsmblob_value(const struct lsmblob *blob)
>  	return 0;
>  }
>  
> +const char *security_lsm_slot_name(int slot);
> +
> +static inline bool lsm_multiple_contexts(void)
> +{
> +#ifdef CONFIG_SECURITY
> +	return security_lsm_slot_name(1) != NULL;
> +#else
> +	return false;
> +#endif
> +}
> +
>  /* These functions are in security/commoncap.c */
>  extern int cap_capable(const struct cred *cred, struct user_namespace *ns,
>  		       int cap, unsigned int opts);
> @@ -554,7 +567,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);
> @@ -1372,7 +1386,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/netlabel.h b/include/net/netlabel.h
> index 73fc25b4042b..216cb1ffc8f0 100644
> --- a/include/net/netlabel.h
> +++ b/include/net/netlabel.h
> @@ -97,7 +97,7 @@ struct calipso_doi;
>  
>  /* NetLabel audit information */
>  struct netlbl_audit {
> -	u32 secid;
> +	struct lsmblob lsmdata;
>  	kuid_t loginuid;
>  	unsigned int sessionid;
>  };
> 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/net/xfrm.h b/include/net/xfrm.h
> index 2737d24ec244..9e8cac6228b4 100644
> --- a/include/net/xfrm.h
> +++ b/include/net/xfrm.h
> @@ -675,11 +675,13 @@ static inline struct audit_buffer *xfrm_audit_start(const char *op)
>  
>  	if (audit_enabled == AUDIT_OFF)
>  		return NULL;
> +	audit_stamp_context(audit_context());
>  	audit_buf = audit_log_start(audit_context(), GFP_ATOMIC,
>  				    AUDIT_MAC_IPSEC_EVENT);
>  	if (audit_buf == NULL)
>  		return NULL;
>  	audit_log_format(audit_buf, "op=%s", op);
> +	audit_log_lsm(NULL, false);
>  	return audit_buf;
>  }
>  
> @@ -693,7 +695,7 @@ static inline void xfrm_audit_helper_usrinfo(bool task_valid,
>  		AUDIT_SID_UNSET;
>  
>  	audit_log_format(audit_buf, " auid=%u ses=%u", auid, ses);
> -	audit_log_task_context(audit_buf);
> +	audit_log_task_context(audit_buf, NULL);
>  }
>  
>  void xfrm_audit_policy_add(struct xfrm_policy *xp, int result, bool task_valid);
> diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h
> index cd2d8279a5e4..2a63720e56f6 100644
> --- a/include/uapi/linux/audit.h
> +++ b/include/uapi/linux/audit.h
> @@ -139,6 +139,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 594b42fc88ff..0e7831c9f321 100644
> --- a/kernel/audit.c
> +++ b/kernel/audit.c
> @@ -394,10 +394,11 @@ static int audit_log_config_change(char *function_name, u32 new, u32 old,
>  		return rc;
>  	audit_log_format(ab, "op=set %s=%u old=%u ", function_name, new, old);
>  	audit_log_session_info(ab);
> -	rc = audit_log_task_context(ab);
> +	rc = audit_log_task_context(ab, NULL);
>  	if (rc)
>  		allow_changes = 0; /* Something weird, deny request */
>  	audit_log_format(ab, " res=%d", allow_changes);
> +	audit_log_lsm(NULL, false);
>  	audit_log_end(ab);
>  	return rc;
>  }
> @@ -1070,13 +1071,31 @@ static void audit_log_common_recv_msg(struct audit_context *context,
>  		return;
>  	audit_log_format(*ab, "pid=%d uid=%u ", pid, uid);
>  	audit_log_session_info(*ab);
> -	audit_log_task_context(*ab);
> +	audit_log_task_context(*ab, NULL);
>  }
>  
>  static inline void audit_log_user_recv_msg(struct audit_buffer **ab,
>  					   u16 msg_type)
>  {
> -	audit_log_common_recv_msg(NULL, ab, msg_type);
> +	struct audit_context *context;
> +
> +	if (!lsm_multiple_contexts()) {
> +		audit_log_common_recv_msg(NULL, ab, msg_type);
> +		return;
> +	}
> +
> +	context = audit_context();
> +	if (context) {
> +		if (!context->in_syscall)
> +			audit_stamp_context(context);
> +		audit_log_common_recv_msg(context, ab, msg_type);
> +		return;
> +	}
> +
> +	audit_alloc(current);
> +	context = audit_context();
> +
> +	audit_log_common_recv_msg(context, ab, msg_type);
>  }
>  
>  int is_audit_feature_set(int i)
> @@ -1372,6 +1391,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
>  				audit_log_n_untrustedstring(ab, str, data_len);
>  			}
>  			audit_log_end(ab);
> +			audit_log_lsm(NULL, false);
>  		}
>  		break;
>  	case AUDIT_ADD_RULE:
> @@ -1444,7 +1464,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
>  
>  		if (lsmblob_is_set(&audit_sig_lsm)) {
>  			err = security_secid_to_secctx(&audit_sig_lsm,
> -						       &context);
> +						       &context, LSMBLOB_FIRST);
>  			if (err)
>  				return err;
>  		}
> @@ -1572,7 +1592,7 @@ static void audit_log_multicast(int group, const char *op, int err)
>  			 tty ? tty_name(tty) : "(none)",
>  			 audit_get_sessionid(current));
>  	audit_put_tty(tty);
> -	audit_log_task_context(ab); /* subj= */
> +	audit_log_task_context(ab, NULL); /* subj= */
>  	audit_log_format(ab, " comm=");
>  	audit_log_untrustedstring(ab, get_task_comm(comm, current));
>  	audit_log_d_path_exe(ab, current->mm); /* exe= */
> @@ -1869,6 +1889,10 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
>  	}
>  
>  	audit_get_stamp(ab->ctx, &t, &serial);
> +	if (type == AUDIT_MAC_TASK_CONTEXTS && ab->ctx->serial == 0) {
> +		audit_stamp_context(ab->ctx);
> +		audit_get_stamp(ab->ctx, &t, &serial);
> +	}
>  	audit_log_format(ab, "audit(%llu.%03lu:%u): ",
>  			 (unsigned long long)t.tv_sec, t.tv_nsec/1000000, serial);
>  
> @@ -2126,30 +2150,47 @@ void audit_log_key(struct audit_buffer *ab, char *key)
>  		audit_log_format(ab, "(null)");
>  }
>  
> -int audit_log_task_context(struct audit_buffer *ab)
> +int audit_log_task_context(struct audit_buffer *ab, struct lsmblob *blob)
>  {
> +	int i;
>  	int error;
> -	struct lsmblob blob;
> -	struct lsmcontext context;
> +	struct lsmblob localblob;
> +	struct lsmcontext lsmdata;
>  
> -	security_task_getsecid(current, &blob);
> -	if (!lsmblob_is_set(&blob))
> +	/*
> +	 * 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 (lsm_multiple_contexts()) {
> +		audit_log_format(ab, " subj=?");
>  		return 0;
> +	}
>  
> -	error = security_secid_to_secctx(&blob, &context);
> -	if (error) {
> -		if (error != -EINVAL)
> -			goto error_path;
> -		return 0;
> +	if (blob == NULL) {
> +		security_task_getsecid(current, &localblob);
> +		if (!lsmblob_is_set(&localblob)) {
> +			audit_log_format(ab, " subj=?");
> +			return 0;
> +		}
> +		blob = &localblob;
>  	}
>  
> -	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;
> +		}
>  
> -error_path:
> -	audit_panic("error in audit_log_task_context");
> -	return error;
> +		audit_log_format(ab, " subj=%s", lsmdata.context);
> +		security_release_secctx(&lsmdata);
> +		break;
> +	}
> +
> +	return 0;
>  }
>  EXPORT_SYMBOL(audit_log_task_context);
>  
> @@ -2221,7 +2262,7 @@ void audit_log_task_info(struct audit_buffer *ab)
>  	audit_log_format(ab, " comm=");
>  	audit_log_untrustedstring(ab, get_task_comm(comm, current));
>  	audit_log_d_path_exe(ab, current->mm);
> -	audit_log_task_context(ab);
> +	audit_log_task_context(ab, NULL);
>  }
>  EXPORT_SYMBOL(audit_log_task_info);
>  
> @@ -2279,6 +2320,7 @@ static void audit_log_set_loginuid(kuid_t koldloginuid, kuid_t kloginuid,
>  	if (!audit_enabled)
>  		return;
>  
> +	audit_stamp_context(audit_context());
>  	ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_LOGIN);
>  	if (!ab)
>  		return;
> @@ -2289,11 +2331,12 @@ static void audit_log_set_loginuid(kuid_t koldloginuid, kuid_t kloginuid,
>  	tty = audit_get_tty();
>  
>  	audit_log_format(ab, "pid=%d uid=%u", task_tgid_nr(current), uid);
> -	audit_log_task_context(ab);
> +	audit_log_task_context(ab, NULL);
>  	audit_log_format(ab, " old-auid=%u auid=%u tty=%s old-ses=%u ses=%u res=%d",
>  			 oldloginuid, loginuid, tty ? tty_name(tty) : "(none)",
>  			 oldsessionid, sessionid, !rc);
>  	audit_put_tty(tty);
> +	audit_log_lsm(NULL, true);
>  	audit_log_end(ab);
>  }
>  
> diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
> index 31732023b689..6c03e463668e 100644
> --- a/kernel/auditfilter.c
> +++ b/kernel/auditfilter.c
> @@ -1107,7 +1107,7 @@ static void audit_log_rule_change(char *action, struct audit_krule *rule, int re
>  	if (!ab)
>  		return;
>  	audit_log_session_info(ab);
> -	audit_log_task_context(ab);
> +	audit_log_task_context(ab, NULL);
>  	audit_log_format(ab, " op=%s", action);
>  	audit_log_key(ab, rule->filterkey);
>  	audit_log_format(ab, " list=%d res=%d", rule->listnr, res);
> diff --git a/kernel/auditsc.c b/kernel/auditsc.c
> index 4af5861bcb9a..cf5dbd0e3a3d 100644
> --- a/kernel/auditsc.c
> +++ b/kernel/auditsc.c
> @@ -473,7 +473,7 @@ static int audit_filter_rules(struct task_struct *tsk,
>  {
>  	const struct cred *cred;
>  	int i, need_sid = 1;
> -	struct lsmblob blob;
> +	struct lsmblob blob = { };
>  	unsigned int sessionid;
>  
>  	cred = rcu_dereference_check(tsk->cred, tsk == current || task_creation);
> @@ -962,10 +962,12 @@ int audit_alloc(struct task_struct *tsk)
>  		return 0; /* Return if not auditing. */
>  
>  	state = audit_filter_task(tsk, &key);
> -	if (state == AUDIT_DISABLED) {
> +	if (!lsm_multiple_contexts() && state == AUDIT_DISABLED) {
>  		clear_tsk_thread_flag(tsk, TIF_SYSCALL_AUDIT);
>  		return 0;
>  	}
> +	if (state == AUDIT_DISABLED)
> +		clear_tsk_thread_flag(tsk, TIF_SYSCALL_AUDIT);
>  
>  	if (!(context = audit_alloc_context(state))) {
>  		kfree(key);
> @@ -1009,7 +1011,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 {
> @@ -1254,7 +1256,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 {
> @@ -1406,7 +1409,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;
> @@ -1483,6 +1486,52 @@ static void audit_log_proctitle(void)
>  	audit_log_end(ab);
>  }
>  
> +void audit_log_lsm(struct lsmblob *blob, bool exiting)
> +{
> +	struct audit_context *context = audit_context();
> +	struct lsmcontext lsmdata;
> +	struct audit_buffer *ab;
> +	struct lsmblob localblob;
> +	bool sep = false;
> +	int error;
> +	int i;
> +
> +	if (!lsm_multiple_contexts())
> +		return;
> +
> +	if (context && context->in_syscall && !exiting)
> +		return;
> +
> +	ab = audit_log_start(context, GFP_ATOMIC, AUDIT_MAC_TASK_CONTEXTS);
> +	if (!ab)
> +		return;	/* audit_panic or being filtered */
> +
> +	if (blob == NULL) {
> +		security_task_getsecid(current, &localblob);
> +		if (!lsmblob_is_set(&localblob))
> +			return;
> +		blob = &localblob;
> +	}
> +
> +	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_lsm");
> +			return;
> +		}
> +
> +		audit_log_format(ab, "%ssubj_%s=%s", sep ? " " : "",
> +				 security_lsm_slot_name(i), lsmdata.context);
> +		sep = true;
> +
> +		security_release_secctx(&lsmdata);
> +	}
> +
> +	audit_log_end(ab);
> +}
> +
>  static void audit_log_exit(void)
>  {
>  	int i, call_panic = 0;
> @@ -1606,6 +1655,7 @@ static void audit_log_exit(void)
>  	}
>  
>  	audit_log_proctitle();
> +	audit_log_lsm(NULL, true);
>  
>  	/* Send end of event record to help user space know we are finished */
>  	ab = audit_log_start(context, GFP_KERNEL, AUDIT_EOE);
> @@ -2217,6 +2267,21 @@ void __audit_inode_child(struct inode *parent,
>  }
>  EXPORT_SYMBOL_GPL(__audit_inode_child);
>  
> +/**
> + * audit_stamp_context - set the timestamp+serial in an audit context
> + * @ctx: audit_context to set
> + */
> +void audit_stamp_context(struct audit_context *ctx)
> +{
> +	/* ctx will be NULL unless lsm_multiple_contexts() is true */
> +	if (!ctx)
> +		return;
> +
> +	ktime_get_coarse_real_ts64(&ctx->ctime);
> +	ctx->serial = audit_serial();
> +	ctx->current_state = AUDIT_BUILD_CONTEXT;
> +}
> + 
>  /**
>   * auditsc_get_stamp - get local copies of audit_context values
>   * @ctx: audit_context for the task
> @@ -2228,6 +2293,12 @@ EXPORT_SYMBOL_GPL(__audit_inode_child);
>  int auditsc_get_stamp(struct audit_context *ctx,
>  		       struct timespec64 *t, unsigned int *serial)
>  {
> +	if (ctx->serial && !ctx->in_syscall) {
> +		t->tv_sec  = ctx->ctime.tv_sec;
> +		t->tv_nsec = ctx->ctime.tv_nsec;
> +		*serial    = ctx->serial;
> +		return 1;
> +	}
>  	if (!ctx->in_syscall)
>  		return 0;
>  	if (!ctx->serial)
> @@ -2622,7 +2693,7 @@ void __audit_log_nfcfg(const char *name, u8 af, unsigned int nentries,
>  			 name, af, nentries, audit_nfcfgs[op].s);
>  
>  	audit_log_format(ab, " pid=%u", task_pid_nr(current));
> -	audit_log_task_context(ab); /* subj= */
> +	audit_log_task_context(ab, NULL); /* subj= */
>  	audit_log_format(ab, " comm=");
>  	audit_log_untrustedstring(ab, get_task_comm(comm, current));
>  	audit_log_end(ab);
> @@ -2645,7 +2716,7 @@ static void audit_log_task(struct audit_buffer *ab)
>  			 from_kuid(&init_user_ns, uid),
>  			 from_kgid(&init_user_ns, gid),
>  			 sessionid);
> -	audit_log_task_context(ab);
> +	audit_log_task_context(ab, NULL);
>  	audit_log_format(ab, " pid=%d comm=", task_tgid_nr(current));
>  	audit_log_untrustedstring(ab, get_task_comm(comm, current));
>  	audit_log_d_path_exe(ab, current->mm);
> @@ -2668,11 +2739,13 @@ void audit_core_dumps(long signr)
>  	if (signr == SIGQUIT)	/* don't care for those */
>  		return;
>  
> +	audit_stamp_context(audit_context());
>  	ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_ANOM_ABEND);
>  	if (unlikely(!ab))
>  		return;
>  	audit_log_task(ab);
>  	audit_log_format(ab, " sig=%ld res=1", signr);
> +	audit_log_lsm(NULL, true);
>  	audit_log_end(ab);
>  }
>  
> diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
> index 58bf1f3532ae..16fa8f1fb4e0 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 e38b5182e301..3c90b9a488d5 100644
> --- a/net/netfilter/nf_conntrack_netlink.c
> +++ b/net/netfilter/nf_conntrack_netlink.c
> @@ -339,7 +339,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;
>  
> @@ -655,7 +655,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 71bec249d23b..ca01bf2b73c2 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 c830401f7792..9c557f9091ab 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..99579fa49293 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,
> @@ -1521,14 +1524,11 @@ int __init netlbl_unlabel_defconf(void)
>  	int ret_val;
>  	struct netlbl_dom_map *entry;
>  	struct netlbl_audit audit_info;
> -	struct lsmblob blob;
>  
>  	/* Only the kernel is allowed to call this function and the only time
>  	 * it is called is at bootup before the audit subsystem is reporting
>  	 * messages so don't worry to much about these values. */
> -	security_task_getsecid(current, &blob);
> -	/* scaffolding until audit_info.secid is converted */
> -	audit_info.secid = blob.secid[0];
> +	security_task_getsecid(current, &audit_info.lsmdata);
>  	audit_info.loginuid = GLOBAL_ROOT_UID;
>  	audit_info.sessionid = 0;
>  
> diff --git a/net/netlabel/netlabel_user.c b/net/netlabel/netlabel_user.c
> index 951ba0639d20..4e9064754b5f 100644
> --- a/net/netlabel/netlabel_user.c
> +++ b/net/netlabel/netlabel_user.c
> @@ -84,12 +84,12 @@ struct audit_buffer *netlbl_audit_start_common(int type,
>  					       struct netlbl_audit *audit_info)
>  {
>  	struct audit_buffer *audit_buf;
> -	struct lsmcontext context;
> -	struct lsmblob blob;
>  
>  	if (audit_enabled == AUDIT_OFF)
>  		return NULL;
>  
> +	audit_stamp_context(audit_context());
> +
>  	audit_buf = audit_log_start(audit_context(), GFP_ATOMIC, type);
>  	if (audit_buf == NULL)
>  		return NULL;
> @@ -98,12 +98,8 @@ struct audit_buffer *netlbl_audit_start_common(int type,
>  			 from_kuid(&init_user_ns, audit_info->loginuid),
>  			 audit_info->sessionid);
>  
> -	lsmblob_init(&blob, audit_info->secid);
> -	if (audit_info->secid != 0 &&
> -	    security_secid_to_secctx(&blob, &context) == 0) {
> -		audit_log_format(audit_buf, " subj=%s", context.context);
> -		security_release_secctx(&context);
> -	}
> +	audit_log_task_context(audit_buf, &audit_info->lsmdata);
> +	audit_log_lsm(&audit_info->lsmdata, false);
>  
>  	return audit_buf;
>  }
> diff --git a/net/netlabel/netlabel_user.h b/net/netlabel/netlabel_user.h
> index 438b5db6c714..bd4335443b87 100644
> --- a/net/netlabel/netlabel_user.h
> +++ b/net/netlabel/netlabel_user.h
> @@ -34,11 +34,7 @@
>  static inline void netlbl_netlink_auditinfo(struct sk_buff *skb,
>  					    struct netlbl_audit *audit_info)
>  {
> -	struct lsmblob blob;
> -
> -	security_task_getsecid(current, &blob);
> -	/* scaffolding until secid is converted */
> -	audit_info->secid = blob.secid[0];
> +	security_task_getsecid(current, &audit_info->lsmdata);
>  	audit_info->loginuid = audit_get_loginuid(current);
>  	audit_info->sessionid = audit_get_sessionid(current);
>  }
> diff --git a/security/integrity/integrity_audit.c b/security/integrity/integrity_audit.c
> index f25e7df099c8..418f7e45753d 100644
> --- a/security/integrity/integrity_audit.c
> +++ b/security/integrity/integrity_audit.c
> @@ -50,7 +50,7 @@ void integrity_audit_message(int audit_msgno, struct inode *inode,
>  			 from_kuid(&init_user_ns, current_cred()->uid),
>  			 from_kuid(&init_user_ns, audit_get_loginuid(current)),
>  			 audit_get_sessionid(current));
> -	audit_log_task_context(ab);
> +	audit_log_task_context(ab, NULL);
>  	audit_log_format(ab, " op=%s cause=%s comm=", op, cause);
>  	audit_log_untrustedstring(ab, get_task_comm(name, current));
>  	if (fname) {
> diff --git a/security/security.c b/security/security.c
> index 95b48721fb17..4752291376bf 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.
> @@ -2175,7 +2199,7 @@ int security_setprocattr(const char *lsm, const char *name, void *value,
>  		hlist_for_each_entry(hp, &security_hook_heads.setprocattr,
>  				     list) {
>  			rc = hp->hook.setprocattr(name, value, size);
> -			if (rc < 0)
> +			if (rc < 0 && rc != -EINVAL)
>  				return rc;
>  		}
>  
> @@ -2220,13 +2244,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;
> @@ -2256,7 +2299,7 @@ int security_secctx_to_secid(const char *secdata, u32 seclen,
>  			return hp->hook.secctx_to_secid(secdata, seclen,
>  						&blob->secid[hp->lsmid->slot]);
>  	}
> -	return 0;
> +	return -EOPNOTSUPP;
>  }
>  EXPORT_SYMBOL(security_secctx_to_secid);
>  
> @@ -2757,23 +2800,17 @@ int security_key_getsecurity(struct key *key, char **_buffer)
>  int security_audit_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule)
>  {
>  	struct security_hook_list *hp;
> -	bool one_is_good = false;
> -	int rc = 0;
> -	int trc;
> +	int display = lsm_task_display(current);
>  
>  	hlist_for_each_entry(hp, &security_hook_heads.audit_rule_init, list) {
>  		if (WARN_ON(hp->lsmid->slot < 0 || hp->lsmid->slot >= lsm_slot))
>  			continue;
> -		trc = hp->hook.audit_rule_init(field, op, rulestr,
> -					       &lsmrule[hp->lsmid->slot]);
> -		if (trc == 0)
> -			one_is_good = true;
> -		else
> -			rc = trc;
> +		if (display != LSMBLOB_INVALID && display != hp->lsmid->slot)
> +			continue;
> +		return hp->hook.audit_rule_init(field, op, rulestr,
> +						&lsmrule[hp->lsmid->slot]);
>  	}
> -	if (one_is_good)
> -		return 0;
> -	return rc;
> +	return 0;
>  }
>  
>  int security_audit_rule_known(struct audit_krule *krule)
> @@ -2805,6 +2842,8 @@ int security_audit_rule_match(struct lsmblob *blob, u32 field, u32 op,
>  			continue;
>  		if (lsmrule[hp->lsmid->slot] == NULL)
>  			continue;
> +		if (lsmrule[hp->lsmid->slot] == NULL)
> +			continue;
>  		rc = hp->hook.audit_rule_match(blob->secid[hp->lsmid->slot],
>  					       field, op,
>  					       &lsmrule[hp->lsmid->slot]);
> diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
> index dcabf6bd8faa..15fa4b7eb2e6 100644
> --- a/security/smack/smackfs.c
> +++ b/security/smack/smackfs.c
> @@ -185,7 +185,8 @@ static void smk_netlabel_audit_set(struct netlbl_audit *nap)
>  
>  	nap->loginuid = audit_get_loginuid(current);
>  	nap->sessionid = audit_get_sessionid(current);
> -	nap->secid = skp->smk_secid;
> +	lsmblob_init(&nap->lsmdata, 0);
> +	nap->lsmdata.secid[smack_lsmid.slot] = skp->smk_secid;
>  }
>  
>  /*
>
John Johansen Sept. 3, 2020, 5 p.m. UTC | #2
On 9/3/20 9:32 AM, James Morris wrote:
> On Wed, 26 Aug 2020, 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 linked with the same timestamp and serial number.
>> The record is produced only in cases where there is more than one
>> security module with a process "context".
>>
>> Before this change the only audit events that required multiple
>> records were syscall events. Several non-syscall events include
>> subject contexts, so the use of audit_context data has been expanded
>> as necessary.
>>
>> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
>> Cc: linux-audit@redhat.com
> 
> Paul, can you review/ack the audit changes?
> 
I am working on reviewing them as well, but I can't/won't ack them.


>> ---
>>  drivers/android/binder.c                |  2 +-
>>  include/linux/audit.h                   | 13 +++-
>>  include/linux/security.h                | 18 ++++-
>>  include/net/netlabel.h                  |  2 +-
>>  include/net/scm.h                       |  3 +-
>>  include/net/xfrm.h                      |  4 +-
>>  include/uapi/linux/audit.h              |  1 +
>>  kernel/audit.c                          | 89 ++++++++++++++++++-------
>>  kernel/auditfilter.c                    |  2 +-
>>  kernel/auditsc.c                        | 87 ++++++++++++++++++++++--
>>  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       | 16 ++---
>>  net/netlabel/netlabel_user.c            | 12 ++--
>>  net/netlabel/netlabel_user.h            |  6 +-
>>  security/integrity/integrity_audit.c    |  2 +-
>>  security/security.c                     | 73 +++++++++++++++-----
>>  security/smack/smackfs.c                |  3 +-
>>  20 files changed, 259 insertions(+), 84 deletions(-)
>>
>> diff --git a/drivers/android/binder.c b/drivers/android/binder.c
>> index 0bde1b96680e..93781dad0c28 100644
>> --- a/drivers/android/binder.c
>> +++ b/drivers/android/binder.c
>> @@ -3113,7 +3113,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/audit.h b/include/linux/audit.h
>> index ba1cd38d601b..fe027df0d9a8 100644
>> --- a/include/linux/audit.h
>> +++ b/include/linux/audit.h
>> @@ -186,7 +186,9 @@ extern void		    audit_log_path_denied(int type,
>>  						  const char *operation);
>>  extern void		    audit_log_lost(const char *message);
>>  
>> -extern int audit_log_task_context(struct audit_buffer *ab);
>> +extern void audit_log_lsm(struct lsmblob *blob, bool exiting);
>> +extern int audit_log_task_context(struct audit_buffer *ab,
>> +				  struct lsmblob *blob);
>>  extern void audit_log_task_info(struct audit_buffer *ab);
>>  
>>  extern int		    audit_update_lsm_rules(void);
>> @@ -246,7 +248,10 @@ static inline void audit_log_key(struct audit_buffer *ab, char *key)
>>  { }
>>  static inline void audit_log_path_denied(int type, const char *operation)
>>  { }
>> -static inline int audit_log_task_context(struct audit_buffer *ab)
>> +static inline void audit_log_lsm(struct lsmblob *blob, bool exiting)
>> +{ }
>> +static inline int audit_log_task_context(struct audit_buffer *ab,
>> +					 struct lsmblob *blob);
>>  {
>>  	return 0;
>>  }
>> @@ -305,6 +310,7 @@ extern void audit_seccomp(unsigned long syscall, long signr, int code);
>>  extern void audit_seccomp_actions_logged(const char *names,
>>  					 const char *old_names, int res);
>>  extern void __audit_ptrace(struct task_struct *t);
>> +extern void audit_stamp_context(struct audit_context *ctx);
>>  
>>  static inline void audit_set_context(struct task_struct *task, struct audit_context *ctx)
>>  {
>> @@ -682,6 +688,9 @@ static inline void audit_ntp_log(const struct audit_ntp_data *ad)
>>  static inline void audit_ptrace(struct task_struct *t)
>>  { }
>>  
>> +static inline void audit_stamp_context(struct audit_context *ctx)
>> +{ }
>> +
>>  static inline void audit_log_nfcfg(const char *name, u8 af,
>>  				   unsigned int nentries,
>>  				   enum audit_nfcfgop op, gfp_t gfp)
>> diff --git a/include/linux/security.h b/include/linux/security.h
>> index 40260bfc3a0d..3cbe24be1563 100644
>> --- a/include/linux/security.h
>> +++ b/include/linux/security.h
>> @@ -180,6 +180,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.
>> @@ -242,6 +244,17 @@ static inline u32 lsmblob_value(const struct lsmblob *blob)
>>  	return 0;
>>  }
>>  
>> +const char *security_lsm_slot_name(int slot);
>> +
>> +static inline bool lsm_multiple_contexts(void)
>> +{
>> +#ifdef CONFIG_SECURITY
>> +	return security_lsm_slot_name(1) != NULL;
>> +#else
>> +	return false;
>> +#endif
>> +}
>> +
>>  /* These functions are in security/commoncap.c */
>>  extern int cap_capable(const struct cred *cred, struct user_namespace *ns,
>>  		       int cap, unsigned int opts);
>> @@ -554,7 +567,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);
>> @@ -1372,7 +1386,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/netlabel.h b/include/net/netlabel.h
>> index 73fc25b4042b..216cb1ffc8f0 100644
>> --- a/include/net/netlabel.h
>> +++ b/include/net/netlabel.h
>> @@ -97,7 +97,7 @@ struct calipso_doi;
>>  
>>  /* NetLabel audit information */
>>  struct netlbl_audit {
>> -	u32 secid;
>> +	struct lsmblob lsmdata;
>>  	kuid_t loginuid;
>>  	unsigned int sessionid;
>>  };
>> 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/net/xfrm.h b/include/net/xfrm.h
>> index 2737d24ec244..9e8cac6228b4 100644
>> --- a/include/net/xfrm.h
>> +++ b/include/net/xfrm.h
>> @@ -675,11 +675,13 @@ static inline struct audit_buffer *xfrm_audit_start(const char *op)
>>  
>>  	if (audit_enabled == AUDIT_OFF)
>>  		return NULL;
>> +	audit_stamp_context(audit_context());
>>  	audit_buf = audit_log_start(audit_context(), GFP_ATOMIC,
>>  				    AUDIT_MAC_IPSEC_EVENT);
>>  	if (audit_buf == NULL)
>>  		return NULL;
>>  	audit_log_format(audit_buf, "op=%s", op);
>> +	audit_log_lsm(NULL, false);
>>  	return audit_buf;
>>  }
>>  
>> @@ -693,7 +695,7 @@ static inline void xfrm_audit_helper_usrinfo(bool task_valid,
>>  		AUDIT_SID_UNSET;
>>  
>>  	audit_log_format(audit_buf, " auid=%u ses=%u", auid, ses);
>> -	audit_log_task_context(audit_buf);
>> +	audit_log_task_context(audit_buf, NULL);
>>  }
>>  
>>  void xfrm_audit_policy_add(struct xfrm_policy *xp, int result, bool task_valid);
>> diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h
>> index cd2d8279a5e4..2a63720e56f6 100644
>> --- a/include/uapi/linux/audit.h
>> +++ b/include/uapi/linux/audit.h
>> @@ -139,6 +139,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 594b42fc88ff..0e7831c9f321 100644
>> --- a/kernel/audit.c
>> +++ b/kernel/audit.c
>> @@ -394,10 +394,11 @@ static int audit_log_config_change(char *function_name, u32 new, u32 old,
>>  		return rc;
>>  	audit_log_format(ab, "op=set %s=%u old=%u ", function_name, new, old);
>>  	audit_log_session_info(ab);
>> -	rc = audit_log_task_context(ab);
>> +	rc = audit_log_task_context(ab, NULL);
>>  	if (rc)
>>  		allow_changes = 0; /* Something weird, deny request */
>>  	audit_log_format(ab, " res=%d", allow_changes);
>> +	audit_log_lsm(NULL, false);
>>  	audit_log_end(ab);
>>  	return rc;
>>  }
>> @@ -1070,13 +1071,31 @@ static void audit_log_common_recv_msg(struct audit_context *context,
>>  		return;
>>  	audit_log_format(*ab, "pid=%d uid=%u ", pid, uid);
>>  	audit_log_session_info(*ab);
>> -	audit_log_task_context(*ab);
>> +	audit_log_task_context(*ab, NULL);
>>  }
>>  
>>  static inline void audit_log_user_recv_msg(struct audit_buffer **ab,
>>  					   u16 msg_type)
>>  {
>> -	audit_log_common_recv_msg(NULL, ab, msg_type);
>> +	struct audit_context *context;
>> +
>> +	if (!lsm_multiple_contexts()) {
>> +		audit_log_common_recv_msg(NULL, ab, msg_type);
>> +		return;
>> +	}
>> +
>> +	context = audit_context();
>> +	if (context) {
>> +		if (!context->in_syscall)
>> +			audit_stamp_context(context);
>> +		audit_log_common_recv_msg(context, ab, msg_type);
>> +		return;
>> +	}
>> +
>> +	audit_alloc(current);
>> +	context = audit_context();
>> +
>> +	audit_log_common_recv_msg(context, ab, msg_type);
>>  }
>>  
>>  int is_audit_feature_set(int i)
>> @@ -1372,6 +1391,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
>>  				audit_log_n_untrustedstring(ab, str, data_len);
>>  			}
>>  			audit_log_end(ab);
>> +			audit_log_lsm(NULL, false);
>>  		}
>>  		break;
>>  	case AUDIT_ADD_RULE:
>> @@ -1444,7 +1464,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
>>  
>>  		if (lsmblob_is_set(&audit_sig_lsm)) {
>>  			err = security_secid_to_secctx(&audit_sig_lsm,
>> -						       &context);
>> +						       &context, LSMBLOB_FIRST);
>>  			if (err)
>>  				return err;
>>  		}
>> @@ -1572,7 +1592,7 @@ static void audit_log_multicast(int group, const char *op, int err)
>>  			 tty ? tty_name(tty) : "(none)",
>>  			 audit_get_sessionid(current));
>>  	audit_put_tty(tty);
>> -	audit_log_task_context(ab); /* subj= */
>> +	audit_log_task_context(ab, NULL); /* subj= */
>>  	audit_log_format(ab, " comm=");
>>  	audit_log_untrustedstring(ab, get_task_comm(comm, current));
>>  	audit_log_d_path_exe(ab, current->mm); /* exe= */
>> @@ -1869,6 +1889,10 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
>>  	}
>>  
>>  	audit_get_stamp(ab->ctx, &t, &serial);
>> +	if (type == AUDIT_MAC_TASK_CONTEXTS && ab->ctx->serial == 0) {
>> +		audit_stamp_context(ab->ctx);
>> +		audit_get_stamp(ab->ctx, &t, &serial);
>> +	}
>>  	audit_log_format(ab, "audit(%llu.%03lu:%u): ",
>>  			 (unsigned long long)t.tv_sec, t.tv_nsec/1000000, serial);
>>  
>> @@ -2126,30 +2150,47 @@ void audit_log_key(struct audit_buffer *ab, char *key)
>>  		audit_log_format(ab, "(null)");
>>  }
>>  
>> -int audit_log_task_context(struct audit_buffer *ab)
>> +int audit_log_task_context(struct audit_buffer *ab, struct lsmblob *blob)
>>  {
>> +	int i;
>>  	int error;
>> -	struct lsmblob blob;
>> -	struct lsmcontext context;
>> +	struct lsmblob localblob;
>> +	struct lsmcontext lsmdata;
>>  
>> -	security_task_getsecid(current, &blob);
>> -	if (!lsmblob_is_set(&blob))
>> +	/*
>> +	 * 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 (lsm_multiple_contexts()) {
>> +		audit_log_format(ab, " subj=?");
>>  		return 0;
>> +	}
>>  
>> -	error = security_secid_to_secctx(&blob, &context);
>> -	if (error) {
>> -		if (error != -EINVAL)
>> -			goto error_path;
>> -		return 0;
>> +	if (blob == NULL) {
>> +		security_task_getsecid(current, &localblob);
>> +		if (!lsmblob_is_set(&localblob)) {
>> +			audit_log_format(ab, " subj=?");
>> +			return 0;
>> +		}
>> +		blob = &localblob;
>>  	}
>>  
>> -	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;
>> +		}
>>  
>> -error_path:
>> -	audit_panic("error in audit_log_task_context");
>> -	return error;
>> +		audit_log_format(ab, " subj=%s", lsmdata.context);
>> +		security_release_secctx(&lsmdata);
>> +		break;
>> +	}
>> +
>> +	return 0;
>>  }
>>  EXPORT_SYMBOL(audit_log_task_context);
>>  
>> @@ -2221,7 +2262,7 @@ void audit_log_task_info(struct audit_buffer *ab)
>>  	audit_log_format(ab, " comm=");
>>  	audit_log_untrustedstring(ab, get_task_comm(comm, current));
>>  	audit_log_d_path_exe(ab, current->mm);
>> -	audit_log_task_context(ab);
>> +	audit_log_task_context(ab, NULL);
>>  }
>>  EXPORT_SYMBOL(audit_log_task_info);
>>  
>> @@ -2279,6 +2320,7 @@ static void audit_log_set_loginuid(kuid_t koldloginuid, kuid_t kloginuid,
>>  	if (!audit_enabled)
>>  		return;
>>  
>> +	audit_stamp_context(audit_context());
>>  	ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_LOGIN);
>>  	if (!ab)
>>  		return;
>> @@ -2289,11 +2331,12 @@ static void audit_log_set_loginuid(kuid_t koldloginuid, kuid_t kloginuid,
>>  	tty = audit_get_tty();
>>  
>>  	audit_log_format(ab, "pid=%d uid=%u", task_tgid_nr(current), uid);
>> -	audit_log_task_context(ab);
>> +	audit_log_task_context(ab, NULL);
>>  	audit_log_format(ab, " old-auid=%u auid=%u tty=%s old-ses=%u ses=%u res=%d",
>>  			 oldloginuid, loginuid, tty ? tty_name(tty) : "(none)",
>>  			 oldsessionid, sessionid, !rc);
>>  	audit_put_tty(tty);
>> +	audit_log_lsm(NULL, true);
>>  	audit_log_end(ab);
>>  }
>>  
>> diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
>> index 31732023b689..6c03e463668e 100644
>> --- a/kernel/auditfilter.c
>> +++ b/kernel/auditfilter.c
>> @@ -1107,7 +1107,7 @@ static void audit_log_rule_change(char *action, struct audit_krule *rule, int re
>>  	if (!ab)
>>  		return;
>>  	audit_log_session_info(ab);
>> -	audit_log_task_context(ab);
>> +	audit_log_task_context(ab, NULL);
>>  	audit_log_format(ab, " op=%s", action);
>>  	audit_log_key(ab, rule->filterkey);
>>  	audit_log_format(ab, " list=%d res=%d", rule->listnr, res);
>> diff --git a/kernel/auditsc.c b/kernel/auditsc.c
>> index 4af5861bcb9a..cf5dbd0e3a3d 100644
>> --- a/kernel/auditsc.c
>> +++ b/kernel/auditsc.c
>> @@ -473,7 +473,7 @@ static int audit_filter_rules(struct task_struct *tsk,
>>  {
>>  	const struct cred *cred;
>>  	int i, need_sid = 1;
>> -	struct lsmblob blob;
>> +	struct lsmblob blob = { };
>>  	unsigned int sessionid;
>>  
>>  	cred = rcu_dereference_check(tsk->cred, tsk == current || task_creation);
>> @@ -962,10 +962,12 @@ int audit_alloc(struct task_struct *tsk)
>>  		return 0; /* Return if not auditing. */
>>  
>>  	state = audit_filter_task(tsk, &key);
>> -	if (state == AUDIT_DISABLED) {
>> +	if (!lsm_multiple_contexts() && state == AUDIT_DISABLED) {
>>  		clear_tsk_thread_flag(tsk, TIF_SYSCALL_AUDIT);
>>  		return 0;
>>  	}
>> +	if (state == AUDIT_DISABLED)
>> +		clear_tsk_thread_flag(tsk, TIF_SYSCALL_AUDIT);
>>  
>>  	if (!(context = audit_alloc_context(state))) {
>>  		kfree(key);
>> @@ -1009,7 +1011,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 {
>> @@ -1254,7 +1256,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 {
>> @@ -1406,7 +1409,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;
>> @@ -1483,6 +1486,52 @@ static void audit_log_proctitle(void)
>>  	audit_log_end(ab);
>>  }
>>  
>> +void audit_log_lsm(struct lsmblob *blob, bool exiting)
>> +{
>> +	struct audit_context *context = audit_context();
>> +	struct lsmcontext lsmdata;
>> +	struct audit_buffer *ab;
>> +	struct lsmblob localblob;
>> +	bool sep = false;
>> +	int error;
>> +	int i;
>> +
>> +	if (!lsm_multiple_contexts())
>> +		return;
>> +
>> +	if (context && context->in_syscall && !exiting)
>> +		return;
>> +
>> +	ab = audit_log_start(context, GFP_ATOMIC, AUDIT_MAC_TASK_CONTEXTS);
>> +	if (!ab)
>> +		return;	/* audit_panic or being filtered */
>> +
>> +	if (blob == NULL) {
>> +		security_task_getsecid(current, &localblob);
>> +		if (!lsmblob_is_set(&localblob))
>> +			return;
>> +		blob = &localblob;
>> +	}
>> +
>> +	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_lsm");
>> +			return;
>> +		}
>> +
>> +		audit_log_format(ab, "%ssubj_%s=%s", sep ? " " : "",
>> +				 security_lsm_slot_name(i), lsmdata.context);
>> +		sep = true;
>> +
>> +		security_release_secctx(&lsmdata);
>> +	}
>> +
>> +	audit_log_end(ab);
>> +}
>> +
>>  static void audit_log_exit(void)
>>  {
>>  	int i, call_panic = 0;
>> @@ -1606,6 +1655,7 @@ static void audit_log_exit(void)
>>  	}
>>  
>>  	audit_log_proctitle();
>> +	audit_log_lsm(NULL, true);
>>  
>>  	/* Send end of event record to help user space know we are finished */
>>  	ab = audit_log_start(context, GFP_KERNEL, AUDIT_EOE);
>> @@ -2217,6 +2267,21 @@ void __audit_inode_child(struct inode *parent,
>>  }
>>  EXPORT_SYMBOL_GPL(__audit_inode_child);
>>  
>> +/**
>> + * audit_stamp_context - set the timestamp+serial in an audit context
>> + * @ctx: audit_context to set
>> + */
>> +void audit_stamp_context(struct audit_context *ctx)
>> +{
>> +	/* ctx will be NULL unless lsm_multiple_contexts() is true */
>> +	if (!ctx)
>> +		return;
>> +
>> +	ktime_get_coarse_real_ts64(&ctx->ctime);
>> +	ctx->serial = audit_serial();
>> +	ctx->current_state = AUDIT_BUILD_CONTEXT;
>> +}
>> + 
>>  /**
>>   * auditsc_get_stamp - get local copies of audit_context values
>>   * @ctx: audit_context for the task
>> @@ -2228,6 +2293,12 @@ EXPORT_SYMBOL_GPL(__audit_inode_child);
>>  int auditsc_get_stamp(struct audit_context *ctx,
>>  		       struct timespec64 *t, unsigned int *serial)
>>  {
>> +	if (ctx->serial && !ctx->in_syscall) {
>> +		t->tv_sec  = ctx->ctime.tv_sec;
>> +		t->tv_nsec = ctx->ctime.tv_nsec;
>> +		*serial    = ctx->serial;
>> +		return 1;
>> +	}
>>  	if (!ctx->in_syscall)
>>  		return 0;
>>  	if (!ctx->serial)
>> @@ -2622,7 +2693,7 @@ void __audit_log_nfcfg(const char *name, u8 af, unsigned int nentries,
>>  			 name, af, nentries, audit_nfcfgs[op].s);
>>  
>>  	audit_log_format(ab, " pid=%u", task_pid_nr(current));
>> -	audit_log_task_context(ab); /* subj= */
>> +	audit_log_task_context(ab, NULL); /* subj= */
>>  	audit_log_format(ab, " comm=");
>>  	audit_log_untrustedstring(ab, get_task_comm(comm, current));
>>  	audit_log_end(ab);
>> @@ -2645,7 +2716,7 @@ static void audit_log_task(struct audit_buffer *ab)
>>  			 from_kuid(&init_user_ns, uid),
>>  			 from_kgid(&init_user_ns, gid),
>>  			 sessionid);
>> -	audit_log_task_context(ab);
>> +	audit_log_task_context(ab, NULL);
>>  	audit_log_format(ab, " pid=%d comm=", task_tgid_nr(current));
>>  	audit_log_untrustedstring(ab, get_task_comm(comm, current));
>>  	audit_log_d_path_exe(ab, current->mm);
>> @@ -2668,11 +2739,13 @@ void audit_core_dumps(long signr)
>>  	if (signr == SIGQUIT)	/* don't care for those */
>>  		return;
>>  
>> +	audit_stamp_context(audit_context());
>>  	ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_ANOM_ABEND);
>>  	if (unlikely(!ab))
>>  		return;
>>  	audit_log_task(ab);
>>  	audit_log_format(ab, " sig=%ld res=1", signr);
>> +	audit_log_lsm(NULL, true);
>>  	audit_log_end(ab);
>>  }
>>  
>> diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
>> index 58bf1f3532ae..16fa8f1fb4e0 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 e38b5182e301..3c90b9a488d5 100644
>> --- a/net/netfilter/nf_conntrack_netlink.c
>> +++ b/net/netfilter/nf_conntrack_netlink.c
>> @@ -339,7 +339,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;
>>  
>> @@ -655,7 +655,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 71bec249d23b..ca01bf2b73c2 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 c830401f7792..9c557f9091ab 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..99579fa49293 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,
>> @@ -1521,14 +1524,11 @@ int __init netlbl_unlabel_defconf(void)
>>  	int ret_val;
>>  	struct netlbl_dom_map *entry;
>>  	struct netlbl_audit audit_info;
>> -	struct lsmblob blob;
>>  
>>  	/* Only the kernel is allowed to call this function and the only time
>>  	 * it is called is at bootup before the audit subsystem is reporting
>>  	 * messages so don't worry to much about these values. */
>> -	security_task_getsecid(current, &blob);
>> -	/* scaffolding until audit_info.secid is converted */
>> -	audit_info.secid = blob.secid[0];
>> +	security_task_getsecid(current, &audit_info.lsmdata);
>>  	audit_info.loginuid = GLOBAL_ROOT_UID;
>>  	audit_info.sessionid = 0;
>>  
>> diff --git a/net/netlabel/netlabel_user.c b/net/netlabel/netlabel_user.c
>> index 951ba0639d20..4e9064754b5f 100644
>> --- a/net/netlabel/netlabel_user.c
>> +++ b/net/netlabel/netlabel_user.c
>> @@ -84,12 +84,12 @@ struct audit_buffer *netlbl_audit_start_common(int type,
>>  					       struct netlbl_audit *audit_info)
>>  {
>>  	struct audit_buffer *audit_buf;
>> -	struct lsmcontext context;
>> -	struct lsmblob blob;
>>  
>>  	if (audit_enabled == AUDIT_OFF)
>>  		return NULL;
>>  
>> +	audit_stamp_context(audit_context());
>> +
>>  	audit_buf = audit_log_start(audit_context(), GFP_ATOMIC, type);
>>  	if (audit_buf == NULL)
>>  		return NULL;
>> @@ -98,12 +98,8 @@ struct audit_buffer *netlbl_audit_start_common(int type,
>>  			 from_kuid(&init_user_ns, audit_info->loginuid),
>>  			 audit_info->sessionid);
>>  
>> -	lsmblob_init(&blob, audit_info->secid);
>> -	if (audit_info->secid != 0 &&
>> -	    security_secid_to_secctx(&blob, &context) == 0) {
>> -		audit_log_format(audit_buf, " subj=%s", context.context);
>> -		security_release_secctx(&context);
>> -	}
>> +	audit_log_task_context(audit_buf, &audit_info->lsmdata);
>> +	audit_log_lsm(&audit_info->lsmdata, false);
>>  
>>  	return audit_buf;
>>  }
>> diff --git a/net/netlabel/netlabel_user.h b/net/netlabel/netlabel_user.h
>> index 438b5db6c714..bd4335443b87 100644
>> --- a/net/netlabel/netlabel_user.h
>> +++ b/net/netlabel/netlabel_user.h
>> @@ -34,11 +34,7 @@
>>  static inline void netlbl_netlink_auditinfo(struct sk_buff *skb,
>>  					    struct netlbl_audit *audit_info)
>>  {
>> -	struct lsmblob blob;
>> -
>> -	security_task_getsecid(current, &blob);
>> -	/* scaffolding until secid is converted */
>> -	audit_info->secid = blob.secid[0];
>> +	security_task_getsecid(current, &audit_info->lsmdata);
>>  	audit_info->loginuid = audit_get_loginuid(current);
>>  	audit_info->sessionid = audit_get_sessionid(current);
>>  }
>> diff --git a/security/integrity/integrity_audit.c b/security/integrity/integrity_audit.c
>> index f25e7df099c8..418f7e45753d 100644
>> --- a/security/integrity/integrity_audit.c
>> +++ b/security/integrity/integrity_audit.c
>> @@ -50,7 +50,7 @@ void integrity_audit_message(int audit_msgno, struct inode *inode,
>>  			 from_kuid(&init_user_ns, current_cred()->uid),
>>  			 from_kuid(&init_user_ns, audit_get_loginuid(current)),
>>  			 audit_get_sessionid(current));
>> -	audit_log_task_context(ab);
>> +	audit_log_task_context(ab, NULL);
>>  	audit_log_format(ab, " op=%s cause=%s comm=", op, cause);
>>  	audit_log_untrustedstring(ab, get_task_comm(name, current));
>>  	if (fname) {
>> diff --git a/security/security.c b/security/security.c
>> index 95b48721fb17..4752291376bf 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.
>> @@ -2175,7 +2199,7 @@ int security_setprocattr(const char *lsm, const char *name, void *value,
>>  		hlist_for_each_entry(hp, &security_hook_heads.setprocattr,
>>  				     list) {
>>  			rc = hp->hook.setprocattr(name, value, size);
>> -			if (rc < 0)
>> +			if (rc < 0 && rc != -EINVAL)
>>  				return rc;
>>  		}
>>  
>> @@ -2220,13 +2244,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;
>> @@ -2256,7 +2299,7 @@ int security_secctx_to_secid(const char *secdata, u32 seclen,
>>  			return hp->hook.secctx_to_secid(secdata, seclen,
>>  						&blob->secid[hp->lsmid->slot]);
>>  	}
>> -	return 0;
>> +	return -EOPNOTSUPP;
>>  }
>>  EXPORT_SYMBOL(security_secctx_to_secid);
>>  
>> @@ -2757,23 +2800,17 @@ int security_key_getsecurity(struct key *key, char **_buffer)
>>  int security_audit_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule)
>>  {
>>  	struct security_hook_list *hp;
>> -	bool one_is_good = false;
>> -	int rc = 0;
>> -	int trc;
>> +	int display = lsm_task_display(current);
>>  
>>  	hlist_for_each_entry(hp, &security_hook_heads.audit_rule_init, list) {
>>  		if (WARN_ON(hp->lsmid->slot < 0 || hp->lsmid->slot >= lsm_slot))
>>  			continue;
>> -		trc = hp->hook.audit_rule_init(field, op, rulestr,
>> -					       &lsmrule[hp->lsmid->slot]);
>> -		if (trc == 0)
>> -			one_is_good = true;
>> -		else
>> -			rc = trc;
>> +		if (display != LSMBLOB_INVALID && display != hp->lsmid->slot)
>> +			continue;
>> +		return hp->hook.audit_rule_init(field, op, rulestr,
>> +						&lsmrule[hp->lsmid->slot]);
>>  	}
>> -	if (one_is_good)
>> -		return 0;
>> -	return rc;
>> +	return 0;
>>  }
>>  
>>  int security_audit_rule_known(struct audit_krule *krule)
>> @@ -2805,6 +2842,8 @@ int security_audit_rule_match(struct lsmblob *blob, u32 field, u32 op,
>>  			continue;
>>  		if (lsmrule[hp->lsmid->slot] == NULL)
>>  			continue;
>> +		if (lsmrule[hp->lsmid->slot] == NULL)
>> +			continue;
>>  		rc = hp->hook.audit_rule_match(blob->secid[hp->lsmid->slot],
>>  					       field, op,
>>  					       &lsmrule[hp->lsmid->slot]);
>> diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
>> index dcabf6bd8faa..15fa4b7eb2e6 100644
>> --- a/security/smack/smackfs.c
>> +++ b/security/smack/smackfs.c
>> @@ -185,7 +185,8 @@ static void smk_netlabel_audit_set(struct netlbl_audit *nap)
>>  
>>  	nap->loginuid = audit_get_loginuid(current);
>>  	nap->sessionid = audit_get_sessionid(current);
>> -	nap->secid = skp->smk_secid;
>> +	lsmblob_init(&nap->lsmdata, 0);
>> +	nap->lsmdata.secid[smack_lsmid.slot] = skp->smk_secid;
>>  }
>>  
>>  /*
>>
>
Paul Moore Sept. 3, 2020, 9:49 p.m. UTC | #3
On Thu, Sep 3, 2020 at 12:32 PM James Morris <jmorris@namei.org> wrote:
> On Wed, 26 Aug 2020, 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 linked with the same timestamp and serial number.
> > The record is produced only in cases where there is more than one
> > security module with a process "context".
> >
> > Before this change the only audit events that required multiple
> > records were syscall events. Several non-syscall events include
> > subject contexts, so the use of audit_context data has been expanded
> > as necessary.
> >
> > Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> > Cc: linux-audit@redhat.com
>
> Paul, can you review/ack the audit changes?

I did a previous version at some point in the past, I'll take a look
at v20 tomorrow or this weekend.
Paul Moore Sept. 6, 2020, 4:32 p.m. UTC | #4
On Wed, Aug 26, 2020 at 11:23 AM Casey Schaufler <casey@schaufler-ca.com> 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 linked with the same timestamp and serial number.
> The record is produced only in cases where there is more than one
> security module with a process "context".
>
> Before this change the only audit events that required multiple
> records were syscall events. Several non-syscall events include
> subject contexts, so the use of audit_context data has been expanded
> as necessary.
>
> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> Cc: linux-audit@redhat.com
> ---
>  drivers/android/binder.c                |  2 +-
>  include/linux/audit.h                   | 13 +++-
>  include/linux/security.h                | 18 ++++-
>  include/net/netlabel.h                  |  2 +-
>  include/net/scm.h                       |  3 +-
>  include/net/xfrm.h                      |  4 +-
>  include/uapi/linux/audit.h              |  1 +
>  kernel/audit.c                          | 89 ++++++++++++++++++-------
>  kernel/auditfilter.c                    |  2 +-
>  kernel/auditsc.c                        | 87 ++++++++++++++++++++++--
>  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       | 16 ++---
>  net/netlabel/netlabel_user.c            | 12 ++--
>  net/netlabel/netlabel_user.h            |  6 +-
>  security/integrity/integrity_audit.c    |  2 +-
>  security/security.c                     | 73 +++++++++++++++-----
>  security/smack/smackfs.c                |  3 +-
>  20 files changed, 259 insertions(+), 84 deletions(-)

Regardless of the code, the audit folks generally ask for an example
of the new audit record in the commit description; it make it easier
for the people not familiar with the kernel to review the record
format/information.

I've also been requiring that a test is added to the audit test suite
for new features added to the kernel.  I recognize this is a big ask
for something like this, but it is something we have been doing for
several years now and I think the benefits far outweigh the costs.

* https://github.com/linux-audit/audit-testsuite

> diff --git a/include/linux/audit.h b/include/linux/audit.h
> index ba1cd38d601b..fe027df0d9a8 100644
> --- a/include/linux/audit.h
> +++ b/include/linux/audit.h
> @@ -186,7 +186,9 @@ extern void             audit_log_path_denied(int type,
>                                                   const char *operation);
>  extern void                audit_log_lost(const char *message);
>
> -extern int audit_log_task_context(struct audit_buffer *ab);
> +extern void audit_log_lsm(struct lsmblob *blob, bool exiting);
> +extern int audit_log_task_context(struct audit_buffer *ab,
> +                                 struct lsmblob *blob);

The audit functions tend to get abused, and this is mostly due to a
rather poor design, so I'd prefer to see audit_log_task_context()
remain with just a single argument: the audit buffer.  I believe this
covers the vast majority of the cases and should remain the preferred
option for callers.  This should help shrink the patch and focus it a
bit more.

For the handful of callers that do need to specify a separate task
context, you can create a __audit_log_task_context(ab, blob) that
allows the caller to specify the blob (and obviously you can write
audit_log_task_context() as a one line wrapper around this function).

> diff --git a/include/net/xfrm.h b/include/net/xfrm.h
> index 2737d24ec244..9e8cac6228b4 100644
> --- a/include/net/xfrm.h
> +++ b/include/net/xfrm.h
> @@ -675,11 +675,13 @@ static inline struct audit_buffer *xfrm_audit_start(const char *op)
>
>         if (audit_enabled == AUDIT_OFF)
>                 return NULL;
> +       audit_stamp_context(audit_context());
>         audit_buf = audit_log_start(audit_context(), GFP_ATOMIC,
>                                     AUDIT_MAC_IPSEC_EVENT);

Is audit_stamp_context() necessary here?  Generally if the first
argument to audit_log_start() is not NULL then you shouldn't need to
create a "local" audit context.

I wonder if you might be getting mixed up in testing by not having
audit properly enabled (see link below)?  Make sure you don't have any
audit disable rules loaded into the kernel, and you can even add
"audit=1" to the kernel command line.

https://github.com/linux-audit/audit-documentation/wiki/HOWTO-Fedora-Enable-Auditing

>         if (audit_buf == NULL)
>                 return NULL;
>         audit_log_format(audit_buf, "op=%s", op);
> +       audit_log_lsm(NULL, false);
>         return audit_buf;
>  }

...

> diff --git a/kernel/audit.c b/kernel/audit.c
> index 594b42fc88ff..0e7831c9f321 100644
> --- a/kernel/audit.c
> +++ b/kernel/audit.c
> @@ -1070,13 +1071,31 @@ static void audit_log_common_recv_msg(struct audit_context *context,
>                 return;
>         audit_log_format(*ab, "pid=%d uid=%u ", pid, uid);
>         audit_log_session_info(*ab);
> -       audit_log_task_context(*ab);
> +       audit_log_task_context(*ab, NULL);
>  }
>
>  static inline void audit_log_user_recv_msg(struct audit_buffer **ab,
>                                            u16 msg_type)
>  {
> -       audit_log_common_recv_msg(NULL, ab, msg_type);
> +       struct audit_context *context;
> +
> +       if (!lsm_multiple_contexts()) {
> +               audit_log_common_recv_msg(NULL, ab, msg_type);
> +               return;
> +       }
> +
> +       context = audit_context();
> +       if (context) {
> +               if (!context->in_syscall)
> +                       audit_stamp_context(context);
> +               audit_log_common_recv_msg(context, ab, msg_type);
> +               return;
> +       }
> +
> +       audit_alloc(current);
> +       context = audit_context();
> +
> +       audit_log_common_recv_msg(context, ab, msg_type);
>  }

Hmm.  Take a look at Richard's patch for adding the audit container ID
record to audit user records, it should give you a better idea of how
to approach this.  The above changes in audit_log_user_recv_msg() are
not really what we want.

https://lore.kernel.org/linux-audit/4a5019ed3cfab416aeb6549b791ac6d8cc9fb8b7.1593198710.git.rgb@redhat.com

> @@ -1869,6 +1889,10 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
>         }
>
>         audit_get_stamp(ab->ctx, &t, &serial);
> +       if (type == AUDIT_MAC_TASK_CONTEXTS && ab->ctx->serial == 0) {
> +               audit_stamp_context(ab->ctx);
> +               audit_get_stamp(ab->ctx, &t, &serial);
> +       }
>         audit_log_format(ab, "audit(%llu.%03lu:%u): ",
>                          (unsigned long long)t.tv_sec, t.tv_nsec/1000000, serial);

Can you walk me through what you are trying to do here?  This doesn't
seem right to me, but I'm sure you put it here for a reason.

> @@ -2126,30 +2150,47 @@ void audit_log_key(struct audit_buffer *ab, char *key)
>                 audit_log_format(ab, "(null)");
>  }
>
> -int audit_log_task_context(struct audit_buffer *ab)
> +int audit_log_task_context(struct audit_buffer *ab, struct lsmblob *blob)
>  {
> +       int i;
>         int error;
> -       struct lsmblob blob;
> -       struct lsmcontext context;
> +       struct lsmblob localblob;
> +       struct lsmcontext lsmdata;
>
> -       security_task_getsecid(current, &blob);
> -       if (!lsmblob_is_set(&blob))
> +       /*
> +        * 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 (lsm_multiple_contexts()) {
> +               audit_log_format(ab, " subj=?");
>                 return 0;
> +       }
>
> -       error = security_secid_to_secctx(&blob, &context);
> -       if (error) {
> -               if (error != -EINVAL)
> -                       goto error_path;
> -               return 0;
> +       if (blob == NULL) {
> +               security_task_getsecid(current, &localblob);

Why is localblob necessary?  You know blob is NULL here, just use it
directly and skip the assignment later in this code block.

> +               if (!lsmblob_is_set(&localblob)) {
> +                       audit_log_format(ab, " subj=?");
> +                       return 0;
> +               }
> +               blob = &localblob;
>         }
>
> -       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;
> +               }
>
> -error_path:
> -       audit_panic("error in audit_log_task_context");
> -       return error;
> +               audit_log_format(ab, " subj=%s", lsmdata.context);
> +               security_release_secctx(&lsmdata);
> +               break;
> +       }
> +
> +       return 0;
>  }
>  EXPORT_SYMBOL(audit_log_task_context);

...

> @@ -2279,6 +2320,7 @@ static void audit_log_set_loginuid(kuid_t koldloginuid, kuid_t kloginuid,
>         if (!audit_enabled)
>                 return;
>
> +       audit_stamp_context(audit_context());
>         ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_LOGIN);
>         if (!ab)
>                 return;

Similar to above, I'm not sure audit_stamp_context() is what we want here.

> diff --git a/kernel/auditsc.c b/kernel/auditsc.c
> index 4af5861bcb9a..cf5dbd0e3a3d 100644
> --- a/kernel/auditsc.c
> +++ b/kernel/auditsc.c
> @@ -962,10 +962,12 @@ int audit_alloc(struct task_struct *tsk)
>                 return 0; /* Return if not auditing. */
>
>         state = audit_filter_task(tsk, &key);
> -       if (state == AUDIT_DISABLED) {
> +       if (!lsm_multiple_contexts() && state == AUDIT_DISABLED) {
>                 clear_tsk_thread_flag(tsk, TIF_SYSCALL_AUDIT);
>                 return 0;
>         }
> +       if (state == AUDIT_DISABLED)
> +               clear_tsk_thread_flag(tsk, TIF_SYSCALL_AUDIT);

Hmmm.  I think we've hit critical mass on the amount of hacks in the
audit subsystem for this code ... Let's back up a bit and start with
some basic requirements (correct me if I'm wrong on any of these):

1. This patch only deals with LSM process/task/subject contexts.
2. Multiple LSMs may, or may not exist; audit logs and behavior should
remain unchanged in the single LSM case.
3. If multiple LSMs are present, the subject field in existing records
should take the form of "subj=?" and a new audit record is created
containing fields of the format "subj_<LSM>=<context>".

Assuming all of that is true, why not simply keep the basic logic in
audit_log_task_context(), but also stash a lsmblob struct in the
audit_context for later use by audit_log_exit()?  Stashing of the
lsmblob would really only be necessary to handle the few cases where
the current task is not the proper subject.

> @@ -1483,6 +1486,52 @@ static void audit_log_proctitle(void)
>         audit_log_end(ab);
>  }
>
> +void audit_log_lsm(struct lsmblob *blob, bool exiting)
> +{
> +       struct audit_context *context = audit_context();
> +       struct lsmcontext lsmdata;
> +       struct audit_buffer *ab;
> +       struct lsmblob localblob;
> +       bool sep = false;
> +       int error;
> +       int i;
> +
> +       if (!lsm_multiple_contexts())
> +               return;
> +
> +       if (context && context->in_syscall && !exiting)
> +               return;

I think the "!lsm_multiple_contexts()" and "!exiting" checks fit well
with my comments about generating the AUDIT_MAC_TASK_CONTEXT record in
audit_log_exit.  This code needs a rethink.

> +       ab = audit_log_start(context, GFP_ATOMIC, AUDIT_MAC_TASK_CONTEXTS);
> +       if (!ab)
> +               return; /* audit_panic or being filtered */
> +
> +       if (blob == NULL) {
> +               security_task_getsecid(current, &localblob);
> +               if (!lsmblob_is_set(&localblob))
> +                       return;
> +               blob = &localblob;
> +       }
> +
> +       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_lsm");
> +                       return; fits well with a
> +               }
> +
> +               audit_log_format(ab, "%ssubj_%s=%s", sep ? " " : "",
> +                                security_lsm_slot_name(i), lsmdata.context);
> +               sep = true;
> +
> +               security_release_secctx(&lsmdata);
> +       }
> +
> +       audit_log_end(ab);
> +}

...

> @@ -2217,6 +2267,21 @@ void __audit_inode_child(struct inode *parent,
>  }
>  EXPORT_SYMBOL_GPL(__audit_inode_child);
>
> +/**
> + * audit_stamp_context - set the timestamp+serial in an audit context
> + * @ctx: audit_context to set
> + */
> +void audit_stamp_context(struct audit_context *ctx)
> +{
> +       /* ctx will be NULL unless lsm_multiple_contexts() is true */
> +       if (!ctx)
> +               return;
> +
> +       ktime_get_coarse_real_ts64(&ctx->ctime);
> +       ctx->serial = audit_serial();
> +       ctx->current_state = AUDIT_BUILD_CONTEXT;
> +}

Based on previous discussions and what I *think* you are trying to do
in this patchset, I believe Richard's audit_alloc_local()
implementation (link below) is a better and cleaner solution.  His
latest revisions needs some minor tweaks (see my feeback), but I think
you could probably work with him to pull that single patch into your
patchset.

To be clear, I'm talking about just that one patch; I'm a firm
believer that tying the LSM stacking and audit container ID patches
beyond this would be a disaster.  I can deal with any merge conflicts
that arise whenever the different patchsets land.

* Richard's audit_alloc_local() patch (07/13 of the latest audit
container ID patchset)
https://lore.kernel.org/linux-audit/21e6c4e1ac179c8dcf35803e603899ccfc69300a.1593198710.git.rgb@redhat.com

> diff --git a/net/netlabel/netlabel_user.c b/net/netlabel/netlabel_user.c
> index 951ba0639d20..4e9064754b5f 100644
> --- a/net/netlabel/netlabel_user.c
> +++ b/net/netlabel/netlabel_user.c
> @@ -84,12 +84,12 @@ struct audit_buffer *netlbl_audit_start_common(int type,
>                                                struct netlbl_audit *audit_info)
>  {
>         struct audit_buffer *audit_buf;
> -       struct lsmcontext context;
> -       struct lsmblob blob;
>
>         if (audit_enabled == AUDIT_OFF)
>                 return NULL;
>
> +       audit_stamp_context(audit_context());

Another one.

>         audit_buf = audit_log_start(audit_context(), GFP_ATOMIC, type);
>         if (audit_buf == NULL)
>                 return NULL;
diff mbox series

Patch

diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index 0bde1b96680e..93781dad0c28 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -3113,7 +3113,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/audit.h b/include/linux/audit.h
index ba1cd38d601b..fe027df0d9a8 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -186,7 +186,9 @@  extern void		    audit_log_path_denied(int type,
 						  const char *operation);
 extern void		    audit_log_lost(const char *message);
 
-extern int audit_log_task_context(struct audit_buffer *ab);
+extern void audit_log_lsm(struct lsmblob *blob, bool exiting);
+extern int audit_log_task_context(struct audit_buffer *ab,
+				  struct lsmblob *blob);
 extern void audit_log_task_info(struct audit_buffer *ab);
 
 extern int		    audit_update_lsm_rules(void);
@@ -246,7 +248,10 @@  static inline void audit_log_key(struct audit_buffer *ab, char *key)
 { }
 static inline void audit_log_path_denied(int type, const char *operation)
 { }
-static inline int audit_log_task_context(struct audit_buffer *ab)
+static inline void audit_log_lsm(struct lsmblob *blob, bool exiting)
+{ }
+static inline int audit_log_task_context(struct audit_buffer *ab,
+					 struct lsmblob *blob);
 {
 	return 0;
 }
@@ -305,6 +310,7 @@  extern void audit_seccomp(unsigned long syscall, long signr, int code);
 extern void audit_seccomp_actions_logged(const char *names,
 					 const char *old_names, int res);
 extern void __audit_ptrace(struct task_struct *t);
+extern void audit_stamp_context(struct audit_context *ctx);
 
 static inline void audit_set_context(struct task_struct *task, struct audit_context *ctx)
 {
@@ -682,6 +688,9 @@  static inline void audit_ntp_log(const struct audit_ntp_data *ad)
 static inline void audit_ptrace(struct task_struct *t)
 { }
 
+static inline void audit_stamp_context(struct audit_context *ctx)
+{ }
+
 static inline void audit_log_nfcfg(const char *name, u8 af,
 				   unsigned int nentries,
 				   enum audit_nfcfgop op, gfp_t gfp)
diff --git a/include/linux/security.h b/include/linux/security.h
index 40260bfc3a0d..3cbe24be1563 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -180,6 +180,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.
@@ -242,6 +244,17 @@  static inline u32 lsmblob_value(const struct lsmblob *blob)
 	return 0;
 }
 
+const char *security_lsm_slot_name(int slot);
+
+static inline bool lsm_multiple_contexts(void)
+{
+#ifdef CONFIG_SECURITY
+	return security_lsm_slot_name(1) != NULL;
+#else
+	return false;
+#endif
+}
+
 /* These functions are in security/commoncap.c */
 extern int cap_capable(const struct cred *cred, struct user_namespace *ns,
 		       int cap, unsigned int opts);
@@ -554,7 +567,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);
@@ -1372,7 +1386,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/netlabel.h b/include/net/netlabel.h
index 73fc25b4042b..216cb1ffc8f0 100644
--- a/include/net/netlabel.h
+++ b/include/net/netlabel.h
@@ -97,7 +97,7 @@  struct calipso_doi;
 
 /* NetLabel audit information */
 struct netlbl_audit {
-	u32 secid;
+	struct lsmblob lsmdata;
 	kuid_t loginuid;
 	unsigned int sessionid;
 };
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/net/xfrm.h b/include/net/xfrm.h
index 2737d24ec244..9e8cac6228b4 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -675,11 +675,13 @@  static inline struct audit_buffer *xfrm_audit_start(const char *op)
 
 	if (audit_enabled == AUDIT_OFF)
 		return NULL;
+	audit_stamp_context(audit_context());
 	audit_buf = audit_log_start(audit_context(), GFP_ATOMIC,
 				    AUDIT_MAC_IPSEC_EVENT);
 	if (audit_buf == NULL)
 		return NULL;
 	audit_log_format(audit_buf, "op=%s", op);
+	audit_log_lsm(NULL, false);
 	return audit_buf;
 }
 
@@ -693,7 +695,7 @@  static inline void xfrm_audit_helper_usrinfo(bool task_valid,
 		AUDIT_SID_UNSET;
 
 	audit_log_format(audit_buf, " auid=%u ses=%u", auid, ses);
-	audit_log_task_context(audit_buf);
+	audit_log_task_context(audit_buf, NULL);
 }
 
 void xfrm_audit_policy_add(struct xfrm_policy *xp, int result, bool task_valid);
diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h
index cd2d8279a5e4..2a63720e56f6 100644
--- a/include/uapi/linux/audit.h
+++ b/include/uapi/linux/audit.h
@@ -139,6 +139,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 594b42fc88ff..0e7831c9f321 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -394,10 +394,11 @@  static int audit_log_config_change(char *function_name, u32 new, u32 old,
 		return rc;
 	audit_log_format(ab, "op=set %s=%u old=%u ", function_name, new, old);
 	audit_log_session_info(ab);
-	rc = audit_log_task_context(ab);
+	rc = audit_log_task_context(ab, NULL);
 	if (rc)
 		allow_changes = 0; /* Something weird, deny request */
 	audit_log_format(ab, " res=%d", allow_changes);
+	audit_log_lsm(NULL, false);
 	audit_log_end(ab);
 	return rc;
 }
@@ -1070,13 +1071,31 @@  static void audit_log_common_recv_msg(struct audit_context *context,
 		return;
 	audit_log_format(*ab, "pid=%d uid=%u ", pid, uid);
 	audit_log_session_info(*ab);
-	audit_log_task_context(*ab);
+	audit_log_task_context(*ab, NULL);
 }
 
 static inline void audit_log_user_recv_msg(struct audit_buffer **ab,
 					   u16 msg_type)
 {
-	audit_log_common_recv_msg(NULL, ab, msg_type);
+	struct audit_context *context;
+
+	if (!lsm_multiple_contexts()) {
+		audit_log_common_recv_msg(NULL, ab, msg_type);
+		return;
+	}
+
+	context = audit_context();
+	if (context) {
+		if (!context->in_syscall)
+			audit_stamp_context(context);
+		audit_log_common_recv_msg(context, ab, msg_type);
+		return;
+	}
+
+	audit_alloc(current);
+	context = audit_context();
+
+	audit_log_common_recv_msg(context, ab, msg_type);
 }
 
 int is_audit_feature_set(int i)
@@ -1372,6 +1391,7 @@  static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 				audit_log_n_untrustedstring(ab, str, data_len);
 			}
 			audit_log_end(ab);
+			audit_log_lsm(NULL, false);
 		}
 		break;
 	case AUDIT_ADD_RULE:
@@ -1444,7 +1464,7 @@  static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 
 		if (lsmblob_is_set(&audit_sig_lsm)) {
 			err = security_secid_to_secctx(&audit_sig_lsm,
-						       &context);
+						       &context, LSMBLOB_FIRST);
 			if (err)
 				return err;
 		}
@@ -1572,7 +1592,7 @@  static void audit_log_multicast(int group, const char *op, int err)
 			 tty ? tty_name(tty) : "(none)",
 			 audit_get_sessionid(current));
 	audit_put_tty(tty);
-	audit_log_task_context(ab); /* subj= */
+	audit_log_task_context(ab, NULL); /* subj= */
 	audit_log_format(ab, " comm=");
 	audit_log_untrustedstring(ab, get_task_comm(comm, current));
 	audit_log_d_path_exe(ab, current->mm); /* exe= */
@@ -1869,6 +1889,10 @@  struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
 	}
 
 	audit_get_stamp(ab->ctx, &t, &serial);
+	if (type == AUDIT_MAC_TASK_CONTEXTS && ab->ctx->serial == 0) {
+		audit_stamp_context(ab->ctx);
+		audit_get_stamp(ab->ctx, &t, &serial);
+	}
 	audit_log_format(ab, "audit(%llu.%03lu:%u): ",
 			 (unsigned long long)t.tv_sec, t.tv_nsec/1000000, serial);
 
@@ -2126,30 +2150,47 @@  void audit_log_key(struct audit_buffer *ab, char *key)
 		audit_log_format(ab, "(null)");
 }
 
-int audit_log_task_context(struct audit_buffer *ab)
+int audit_log_task_context(struct audit_buffer *ab, struct lsmblob *blob)
 {
+	int i;
 	int error;
-	struct lsmblob blob;
-	struct lsmcontext context;
+	struct lsmblob localblob;
+	struct lsmcontext lsmdata;
 
-	security_task_getsecid(current, &blob);
-	if (!lsmblob_is_set(&blob))
+	/*
+	 * 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 (lsm_multiple_contexts()) {
+		audit_log_format(ab, " subj=?");
 		return 0;
+	}
 
-	error = security_secid_to_secctx(&blob, &context);
-	if (error) {
-		if (error != -EINVAL)
-			goto error_path;
-		return 0;
+	if (blob == NULL) {
+		security_task_getsecid(current, &localblob);
+		if (!lsmblob_is_set(&localblob)) {
+			audit_log_format(ab, " subj=?");
+			return 0;
+		}
+		blob = &localblob;
 	}
 
-	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;
+		}
 
-error_path:
-	audit_panic("error in audit_log_task_context");
-	return error;
+		audit_log_format(ab, " subj=%s", lsmdata.context);
+		security_release_secctx(&lsmdata);
+		break;
+	}
+
+	return 0;
 }
 EXPORT_SYMBOL(audit_log_task_context);
 
@@ -2221,7 +2262,7 @@  void audit_log_task_info(struct audit_buffer *ab)
 	audit_log_format(ab, " comm=");
 	audit_log_untrustedstring(ab, get_task_comm(comm, current));
 	audit_log_d_path_exe(ab, current->mm);
-	audit_log_task_context(ab);
+	audit_log_task_context(ab, NULL);
 }
 EXPORT_SYMBOL(audit_log_task_info);
 
@@ -2279,6 +2320,7 @@  static void audit_log_set_loginuid(kuid_t koldloginuid, kuid_t kloginuid,
 	if (!audit_enabled)
 		return;
 
+	audit_stamp_context(audit_context());
 	ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_LOGIN);
 	if (!ab)
 		return;
@@ -2289,11 +2331,12 @@  static void audit_log_set_loginuid(kuid_t koldloginuid, kuid_t kloginuid,
 	tty = audit_get_tty();
 
 	audit_log_format(ab, "pid=%d uid=%u", task_tgid_nr(current), uid);
-	audit_log_task_context(ab);
+	audit_log_task_context(ab, NULL);
 	audit_log_format(ab, " old-auid=%u auid=%u tty=%s old-ses=%u ses=%u res=%d",
 			 oldloginuid, loginuid, tty ? tty_name(tty) : "(none)",
 			 oldsessionid, sessionid, !rc);
 	audit_put_tty(tty);
+	audit_log_lsm(NULL, true);
 	audit_log_end(ab);
 }
 
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 31732023b689..6c03e463668e 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -1107,7 +1107,7 @@  static void audit_log_rule_change(char *action, struct audit_krule *rule, int re
 	if (!ab)
 		return;
 	audit_log_session_info(ab);
-	audit_log_task_context(ab);
+	audit_log_task_context(ab, NULL);
 	audit_log_format(ab, " op=%s", action);
 	audit_log_key(ab, rule->filterkey);
 	audit_log_format(ab, " list=%d res=%d", rule->listnr, res);
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 4af5861bcb9a..cf5dbd0e3a3d 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -473,7 +473,7 @@  static int audit_filter_rules(struct task_struct *tsk,
 {
 	const struct cred *cred;
 	int i, need_sid = 1;
-	struct lsmblob blob;
+	struct lsmblob blob = { };
 	unsigned int sessionid;
 
 	cred = rcu_dereference_check(tsk->cred, tsk == current || task_creation);
@@ -962,10 +962,12 @@  int audit_alloc(struct task_struct *tsk)
 		return 0; /* Return if not auditing. */
 
 	state = audit_filter_task(tsk, &key);
-	if (state == AUDIT_DISABLED) {
+	if (!lsm_multiple_contexts() && state == AUDIT_DISABLED) {
 		clear_tsk_thread_flag(tsk, TIF_SYSCALL_AUDIT);
 		return 0;
 	}
+	if (state == AUDIT_DISABLED)
+		clear_tsk_thread_flag(tsk, TIF_SYSCALL_AUDIT);
 
 	if (!(context = audit_alloc_context(state))) {
 		kfree(key);
@@ -1009,7 +1011,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 {
@@ -1254,7 +1256,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 {
@@ -1406,7 +1409,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;
@@ -1483,6 +1486,52 @@  static void audit_log_proctitle(void)
 	audit_log_end(ab);
 }
 
+void audit_log_lsm(struct lsmblob *blob, bool exiting)
+{
+	struct audit_context *context = audit_context();
+	struct lsmcontext lsmdata;
+	struct audit_buffer *ab;
+	struct lsmblob localblob;
+	bool sep = false;
+	int error;
+	int i;
+
+	if (!lsm_multiple_contexts())
+		return;
+
+	if (context && context->in_syscall && !exiting)
+		return;
+
+	ab = audit_log_start(context, GFP_ATOMIC, AUDIT_MAC_TASK_CONTEXTS);
+	if (!ab)
+		return;	/* audit_panic or being filtered */
+
+	if (blob == NULL) {
+		security_task_getsecid(current, &localblob);
+		if (!lsmblob_is_set(&localblob))
+			return;
+		blob = &localblob;
+	}
+
+	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_lsm");
+			return;
+		}
+
+		audit_log_format(ab, "%ssubj_%s=%s", sep ? " " : "",
+				 security_lsm_slot_name(i), lsmdata.context);
+		sep = true;
+
+		security_release_secctx(&lsmdata);
+	}
+
+	audit_log_end(ab);
+}
+
 static void audit_log_exit(void)
 {
 	int i, call_panic = 0;
@@ -1606,6 +1655,7 @@  static void audit_log_exit(void)
 	}
 
 	audit_log_proctitle();
+	audit_log_lsm(NULL, true);
 
 	/* Send end of event record to help user space know we are finished */
 	ab = audit_log_start(context, GFP_KERNEL, AUDIT_EOE);
@@ -2217,6 +2267,21 @@  void __audit_inode_child(struct inode *parent,
 }
 EXPORT_SYMBOL_GPL(__audit_inode_child);
 
+/**
+ * audit_stamp_context - set the timestamp+serial in an audit context
+ * @ctx: audit_context to set
+ */
+void audit_stamp_context(struct audit_context *ctx)
+{
+	/* ctx will be NULL unless lsm_multiple_contexts() is true */
+	if (!ctx)
+		return;
+
+	ktime_get_coarse_real_ts64(&ctx->ctime);
+	ctx->serial = audit_serial();
+	ctx->current_state = AUDIT_BUILD_CONTEXT;
+}
+ 
 /**
  * auditsc_get_stamp - get local copies of audit_context values
  * @ctx: audit_context for the task
@@ -2228,6 +2293,12 @@  EXPORT_SYMBOL_GPL(__audit_inode_child);
 int auditsc_get_stamp(struct audit_context *ctx,
 		       struct timespec64 *t, unsigned int *serial)
 {
+	if (ctx->serial && !ctx->in_syscall) {
+		t->tv_sec  = ctx->ctime.tv_sec;
+		t->tv_nsec = ctx->ctime.tv_nsec;
+		*serial    = ctx->serial;
+		return 1;
+	}
 	if (!ctx->in_syscall)
 		return 0;
 	if (!ctx->serial)
@@ -2622,7 +2693,7 @@  void __audit_log_nfcfg(const char *name, u8 af, unsigned int nentries,
 			 name, af, nentries, audit_nfcfgs[op].s);
 
 	audit_log_format(ab, " pid=%u", task_pid_nr(current));
-	audit_log_task_context(ab); /* subj= */
+	audit_log_task_context(ab, NULL); /* subj= */
 	audit_log_format(ab, " comm=");
 	audit_log_untrustedstring(ab, get_task_comm(comm, current));
 	audit_log_end(ab);
@@ -2645,7 +2716,7 @@  static void audit_log_task(struct audit_buffer *ab)
 			 from_kuid(&init_user_ns, uid),
 			 from_kgid(&init_user_ns, gid),
 			 sessionid);
-	audit_log_task_context(ab);
+	audit_log_task_context(ab, NULL);
 	audit_log_format(ab, " pid=%d comm=", task_tgid_nr(current));
 	audit_log_untrustedstring(ab, get_task_comm(comm, current));
 	audit_log_d_path_exe(ab, current->mm);
@@ -2668,11 +2739,13 @@  void audit_core_dumps(long signr)
 	if (signr == SIGQUIT)	/* don't care for those */
 		return;
 
+	audit_stamp_context(audit_context());
 	ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_ANOM_ABEND);
 	if (unlikely(!ab))
 		return;
 	audit_log_task(ab);
 	audit_log_format(ab, " sig=%ld res=1", signr);
+	audit_log_lsm(NULL, true);
 	audit_log_end(ab);
 }
 
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 58bf1f3532ae..16fa8f1fb4e0 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 e38b5182e301..3c90b9a488d5 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -339,7 +339,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;
 
@@ -655,7 +655,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 71bec249d23b..ca01bf2b73c2 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 c830401f7792..9c557f9091ab 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..99579fa49293 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,
@@ -1521,14 +1524,11 @@  int __init netlbl_unlabel_defconf(void)
 	int ret_val;
 	struct netlbl_dom_map *entry;
 	struct netlbl_audit audit_info;
-	struct lsmblob blob;
 
 	/* Only the kernel is allowed to call this function and the only time
 	 * it is called is at bootup before the audit subsystem is reporting
 	 * messages so don't worry to much about these values. */
-	security_task_getsecid(current, &blob);
-	/* scaffolding until audit_info.secid is converted */
-	audit_info.secid = blob.secid[0];
+	security_task_getsecid(current, &audit_info.lsmdata);
 	audit_info.loginuid = GLOBAL_ROOT_UID;
 	audit_info.sessionid = 0;
 
diff --git a/net/netlabel/netlabel_user.c b/net/netlabel/netlabel_user.c
index 951ba0639d20..4e9064754b5f 100644
--- a/net/netlabel/netlabel_user.c
+++ b/net/netlabel/netlabel_user.c
@@ -84,12 +84,12 @@  struct audit_buffer *netlbl_audit_start_common(int type,
 					       struct netlbl_audit *audit_info)
 {
 	struct audit_buffer *audit_buf;
-	struct lsmcontext context;
-	struct lsmblob blob;
 
 	if (audit_enabled == AUDIT_OFF)
 		return NULL;
 
+	audit_stamp_context(audit_context());
+
 	audit_buf = audit_log_start(audit_context(), GFP_ATOMIC, type);
 	if (audit_buf == NULL)
 		return NULL;
@@ -98,12 +98,8 @@  struct audit_buffer *netlbl_audit_start_common(int type,
 			 from_kuid(&init_user_ns, audit_info->loginuid),
 			 audit_info->sessionid);
 
-	lsmblob_init(&blob, audit_info->secid);
-	if (audit_info->secid != 0 &&
-	    security_secid_to_secctx(&blob, &context) == 0) {
-		audit_log_format(audit_buf, " subj=%s", context.context);
-		security_release_secctx(&context);
-	}
+	audit_log_task_context(audit_buf, &audit_info->lsmdata);
+	audit_log_lsm(&audit_info->lsmdata, false);
 
 	return audit_buf;
 }
diff --git a/net/netlabel/netlabel_user.h b/net/netlabel/netlabel_user.h
index 438b5db6c714..bd4335443b87 100644
--- a/net/netlabel/netlabel_user.h
+++ b/net/netlabel/netlabel_user.h
@@ -34,11 +34,7 @@ 
 static inline void netlbl_netlink_auditinfo(struct sk_buff *skb,
 					    struct netlbl_audit *audit_info)
 {
-	struct lsmblob blob;
-
-	security_task_getsecid(current, &blob);
-	/* scaffolding until secid is converted */
-	audit_info->secid = blob.secid[0];
+	security_task_getsecid(current, &audit_info->lsmdata);
 	audit_info->loginuid = audit_get_loginuid(current);
 	audit_info->sessionid = audit_get_sessionid(current);
 }
diff --git a/security/integrity/integrity_audit.c b/security/integrity/integrity_audit.c
index f25e7df099c8..418f7e45753d 100644
--- a/security/integrity/integrity_audit.c
+++ b/security/integrity/integrity_audit.c
@@ -50,7 +50,7 @@  void integrity_audit_message(int audit_msgno, struct inode *inode,
 			 from_kuid(&init_user_ns, current_cred()->uid),
 			 from_kuid(&init_user_ns, audit_get_loginuid(current)),
 			 audit_get_sessionid(current));
-	audit_log_task_context(ab);
+	audit_log_task_context(ab, NULL);
 	audit_log_format(ab, " op=%s cause=%s comm=", op, cause);
 	audit_log_untrustedstring(ab, get_task_comm(name, current));
 	if (fname) {
diff --git a/security/security.c b/security/security.c
index 95b48721fb17..4752291376bf 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.
@@ -2175,7 +2199,7 @@  int security_setprocattr(const char *lsm, const char *name, void *value,
 		hlist_for_each_entry(hp, &security_hook_heads.setprocattr,
 				     list) {
 			rc = hp->hook.setprocattr(name, value, size);
-			if (rc < 0)
+			if (rc < 0 && rc != -EINVAL)
 				return rc;
 		}
 
@@ -2220,13 +2244,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;
@@ -2256,7 +2299,7 @@  int security_secctx_to_secid(const char *secdata, u32 seclen,
 			return hp->hook.secctx_to_secid(secdata, seclen,
 						&blob->secid[hp->lsmid->slot]);
 	}
-	return 0;
+	return -EOPNOTSUPP;
 }
 EXPORT_SYMBOL(security_secctx_to_secid);
 
@@ -2757,23 +2800,17 @@  int security_key_getsecurity(struct key *key, char **_buffer)
 int security_audit_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule)
 {
 	struct security_hook_list *hp;
-	bool one_is_good = false;
-	int rc = 0;
-	int trc;
+	int display = lsm_task_display(current);
 
 	hlist_for_each_entry(hp, &security_hook_heads.audit_rule_init, list) {
 		if (WARN_ON(hp->lsmid->slot < 0 || hp->lsmid->slot >= lsm_slot))
 			continue;
-		trc = hp->hook.audit_rule_init(field, op, rulestr,
-					       &lsmrule[hp->lsmid->slot]);
-		if (trc == 0)
-			one_is_good = true;
-		else
-			rc = trc;
+		if (display != LSMBLOB_INVALID && display != hp->lsmid->slot)
+			continue;
+		return hp->hook.audit_rule_init(field, op, rulestr,
+						&lsmrule[hp->lsmid->slot]);
 	}
-	if (one_is_good)
-		return 0;
-	return rc;
+	return 0;
 }
 
 int security_audit_rule_known(struct audit_krule *krule)
@@ -2805,6 +2842,8 @@  int security_audit_rule_match(struct lsmblob *blob, u32 field, u32 op,
 			continue;
 		if (lsmrule[hp->lsmid->slot] == NULL)
 			continue;
+		if (lsmrule[hp->lsmid->slot] == NULL)
+			continue;
 		rc = hp->hook.audit_rule_match(blob->secid[hp->lsmid->slot],
 					       field, op,
 					       &lsmrule[hp->lsmid->slot]);
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index dcabf6bd8faa..15fa4b7eb2e6 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -185,7 +185,8 @@  static void smk_netlabel_audit_set(struct netlbl_audit *nap)
 
 	nap->loginuid = audit_get_loginuid(current);
 	nap->sessionid = audit_get_sessionid(current);
-	nap->secid = skp->smk_secid;
+	lsmblob_init(&nap->lsmdata, 0);
+	nap->lsmdata.secid[smack_lsmid.slot] = skp->smk_secid;
 }
 
 /*