linux-security-module.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH 00/15] LSM: No exclusive LSMs
       [not found] <20250621171851.5869-1-casey.ref@schaufler-ca.com>
@ 2025-06-21 17:18 ` Casey Schaufler
  2025-06-21 17:18   ` [RFC PATCH 01/15] Audit: Create audit_stamp structure Casey Schaufler
                     ` (14 more replies)
  0 siblings, 15 replies; 31+ messages in thread
From: Casey Schaufler @ 2025-06-21 17:18 UTC (permalink / raw)
  To: casey, paul, eparis, linux-security-module, audit
  Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
	stephen.smalley.work, linux-kernel, selinux

Remove all constraints that require Linux Security Modules to
be marked as "exclusive".

This RFC includes variants of two other patch sets:
https://github.com/cschaufler/lsm-stacking#audit-6.14-rc1-v4
https://github.com/cschaufler/lsm-stacking#mount-opts-6.16-rc1

Based on patches Paul Moore's LSM initialization patchset.
https://lore.kernel.org/all/20250409185019.238841-31-paul@paul-moore.com/v3

There are three components to this change. Patches 01-04
implement a mechanism to provide auxiliary audit records
and uses it to supply new records for multiple subject and
object security contexts. Patches 09-11 allow mount options
to be supported by multiple LSMs. The remaining patches
address mechanisms that cannot be used safely by more than
one LSM.

Testing has been done using SELinux, Smack and AppArmor on
Fedora and using AppArmor and Smack on Ubuntu. Using SELinux
and Smack on Fedora requires a systemd change.

Casey Schaufler (15):
  Audit: Create audit_stamp structure
  LSM: security_lsmblob_to_secctx module selection
  Audit: Add record for multiple task security contexts
  Audit: Add record for multiple object contexts
  LSM: Single calls in secid hooks
  LSM: Exclusive secmark usage
  Audit: Call only the first of the audit rule hooks
  AppArmor: Remove the exclusive flag
  LSM: Add mount opts blob size tracking
  LSM: allocate mnt_opts blobs instead of module specific data
  LSM: Infrastructure management of the mnt_opts security blob
  LSM: Allow reservation of netlabel
  LSM: restrict security_cred_getsecid() to a single LSM
  Smack: Remove LSM_FLAG_EXCLUSIVE
  LSM: Remove exclusive LSM flag

 include/linux/audit.h               |  23 +++
 include/linux/lsm_hooks.h           |   5 +-
 include/linux/security.h            |   6 +-
 include/uapi/linux/audit.h          |   2 +
 kernel/audit.c                      | 274 ++++++++++++++++++++++++----
 kernel/audit.h                      |  13 +-
 kernel/auditsc.c                    |  65 ++-----
 net/netlabel/netlabel_user.c        |   8 +-
 security/apparmor/include/net.h     |   5 +
 security/apparmor/lsm.c             |  12 +-
 security/lsm.h                      |   4 -
 security/lsm_init.c                 |  36 ++--
 security/security.c                 | 103 ++++++++---
 security/selinux/hooks.c            |  82 ++++++---
 security/selinux/include/netlabel.h |   5 +
 security/selinux/netlabel.c         |   4 +-
 security/smack/smack.h              |  10 +
 security/smack/smack_lsm.c          | 107 ++++++++---
 security/smack/smack_netfilter.c    |  10 +-
 security/smack/smackfs.c            |  20 +-
 20 files changed, 585 insertions(+), 209 deletions(-)

-- 
2.47.0


^ permalink raw reply	[flat|nested] 31+ messages in thread

* [RFC PATCH 01/15] Audit: Create audit_stamp structure
  2025-06-21 17:18 ` [RFC PATCH 00/15] LSM: No exclusive LSMs Casey Schaufler
@ 2025-06-21 17:18   ` Casey Schaufler
  2025-10-14 23:12     ` [PATCH RFC 1/15] " Paul Moore
  2025-06-21 17:18   ` [RFC PATCH 02/15] LSM: security_lsmblob_to_secctx module selection Casey Schaufler
                     ` (13 subsequent siblings)
  14 siblings, 1 reply; 31+ messages in thread
From: Casey Schaufler @ 2025-06-21 17:18 UTC (permalink / raw)
  To: casey, paul, eparis, linux-security-module, audit
  Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
	stephen.smalley.work, linux-kernel, selinux

Replace the timestamp and serial number pair used in audit records
with a structure containing the two elements.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
 kernel/audit.c   | 17 +++++++++--------
 kernel/audit.h   | 13 +++++++++----
 kernel/auditsc.c | 22 +++++++++-------------
 3 files changed, 27 insertions(+), 25 deletions(-)

diff --git a/kernel/audit.c b/kernel/audit.c
index 61b5744d0bb6..547967cb4266 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -1833,11 +1833,11 @@ unsigned int audit_serial(void)
 }
 
 static inline void audit_get_stamp(struct audit_context *ctx,
-				   struct timespec64 *t, unsigned int *serial)
+				   struct audit_stamp *stamp)
 {
-	if (!ctx || !auditsc_get_stamp(ctx, t, serial)) {
-		ktime_get_coarse_real_ts64(t);
-		*serial = audit_serial();
+	if (!ctx || !auditsc_get_stamp(ctx, stamp)) {
+		ktime_get_coarse_real_ts64(&stamp->ctime);
+		stamp->serial = audit_serial();
 	}
 }
 
@@ -1860,8 +1860,7 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
 				     int type)
 {
 	struct audit_buffer *ab;
-	struct timespec64 t;
-	unsigned int serial;
+	struct audit_stamp stamp;
 
 	if (audit_initialized != AUDIT_INITIALIZED)
 		return NULL;
@@ -1916,12 +1915,14 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
 		return NULL;
 	}
 
-	audit_get_stamp(ab->ctx, &t, &serial);
+	audit_get_stamp(ab->ctx, &stamp);
 	/* cancel dummy context to enable supporting records */
 	if (ctx)
 		ctx->dummy = 0;
 	audit_log_format(ab, "audit(%llu.%03lu:%u): ",
-			 (unsigned long long)t.tv_sec, t.tv_nsec/1000000, serial);
+			 (unsigned long long)stamp.ctime.tv_sec,
+			 stamp.ctime.tv_nsec/1000000,
+			 stamp.serial);
 
 	return ab;
 }
diff --git a/kernel/audit.h b/kernel/audit.h
index 0211cb307d30..4d6dd2588f9b 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -99,6 +99,12 @@ struct audit_proctitle {
 	char	*value;	/* the cmdline field */
 };
 
+/* A timestamp/serial pair to identify an event */
+struct audit_stamp {
+	struct timespec64	ctime;	/* time of syscall entry */
+	unsigned int		serial;	/* serial number for record */
+};
+
 /* The per-task audit context. */
 struct audit_context {
 	int		    dummy;	/* must be the first element */
@@ -108,10 +114,9 @@ struct audit_context {
 		AUDIT_CTX_URING,	/* in use by io_uring */
 	} context;
 	enum audit_state    state, current_state;
-	unsigned int	    serial;     /* serial number for record */
+	struct audit_stamp  stamp;	/* event identifier */
 	int		    major;      /* syscall number */
 	int		    uring_op;   /* uring operation */
-	struct timespec64   ctime;      /* time of syscall entry */
 	unsigned long	    argv[4];    /* syscall arguments */
 	long		    return_code;/* syscall return code */
 	u64		    prio;
@@ -263,7 +268,7 @@ extern void audit_put_tty(struct tty_struct *tty);
 extern unsigned int audit_serial(void);
 #ifdef CONFIG_AUDITSYSCALL
 extern int auditsc_get_stamp(struct audit_context *ctx,
-			      struct timespec64 *t, unsigned int *serial);
+			     struct audit_stamp *stamp);
 
 extern void audit_put_watch(struct audit_watch *watch);
 extern void audit_get_watch(struct audit_watch *watch);
@@ -304,7 +309,7 @@ extern void audit_filter_inodes(struct task_struct *tsk,
 				struct audit_context *ctx);
 extern struct list_head *audit_killed_trees(void);
 #else /* CONFIG_AUDITSYSCALL */
-#define auditsc_get_stamp(c, t, s) 0
+#define auditsc_get_stamp(c, s) 0
 #define audit_put_watch(w) do { } while (0)
 #define audit_get_watch(w) do { } while (0)
 #define audit_to_watch(k, p, l, o) (-EINVAL)
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 78fd876a5473..528b6d2f5cb0 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -994,10 +994,10 @@ static void audit_reset_context(struct audit_context *ctx)
 	 */
 
 	ctx->current_state = ctx->state;
-	ctx->serial = 0;
+	ctx->stamp.serial = 0;
+	ctx->stamp.ctime = (struct timespec64){ .tv_sec = 0, .tv_nsec = 0 };
 	ctx->major = 0;
 	ctx->uring_op = 0;
-	ctx->ctime = (struct timespec64){ .tv_sec = 0, .tv_nsec = 0 };
 	memset(ctx->argv, 0, sizeof(ctx->argv));
 	ctx->return_code = 0;
 	ctx->prio = (ctx->state == AUDIT_STATE_RECORD ? ~0ULL : 0);
@@ -1917,7 +1917,7 @@ void __audit_uring_entry(u8 op)
 
 	ctx->context = AUDIT_CTX_URING;
 	ctx->current_state = ctx->state;
-	ktime_get_coarse_real_ts64(&ctx->ctime);
+	ktime_get_coarse_real_ts64(&ctx->stamp.ctime);
 }
 
 /**
@@ -2039,7 +2039,7 @@ void __audit_syscall_entry(int major, unsigned long a1, unsigned long a2,
 	context->argv[3]    = a4;
 	context->context = AUDIT_CTX_SYSCALL;
 	context->current_state  = state;
-	ktime_get_coarse_real_ts64(&context->ctime);
+	ktime_get_coarse_real_ts64(&context->stamp.ctime);
 }
 
 /**
@@ -2508,21 +2508,17 @@ EXPORT_SYMBOL_GPL(__audit_inode_child);
 /**
  * auditsc_get_stamp - get local copies of audit_context values
  * @ctx: audit_context for the task
- * @t: timespec64 to store time recorded in the audit_context
- * @serial: serial value that is recorded in the audit_context
+ * @stamp: timestamp to record
  *
  * Also sets the context as auditable.
  */
-int auditsc_get_stamp(struct audit_context *ctx,
-		       struct timespec64 *t, unsigned int *serial)
+int auditsc_get_stamp(struct audit_context *ctx, struct audit_stamp *stamp)
 {
 	if (ctx->context == AUDIT_CTX_UNUSED)
 		return 0;
-	if (!ctx->serial)
-		ctx->serial = audit_serial();
-	t->tv_sec  = ctx->ctime.tv_sec;
-	t->tv_nsec = ctx->ctime.tv_nsec;
-	*serial    = ctx->serial;
+	if (!ctx->stamp.serial)
+		ctx->stamp.serial = audit_serial();
+	*stamp = ctx->stamp;
 	if (!ctx->prio) {
 		ctx->prio = 1;
 		ctx->current_state = AUDIT_STATE_RECORD;
-- 
2.47.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [RFC PATCH 02/15] LSM: security_lsmblob_to_secctx module selection
  2025-06-21 17:18 ` [RFC PATCH 00/15] LSM: No exclusive LSMs Casey Schaufler
  2025-06-21 17:18   ` [RFC PATCH 01/15] Audit: Create audit_stamp structure Casey Schaufler
@ 2025-06-21 17:18   ` Casey Schaufler
  2025-10-14 23:12     ` [PATCH RFC 2/15] " Paul Moore
  2025-06-21 17:18   ` [RFC PATCH 03/15] Audit: Add record for multiple task security contexts Casey Schaufler
                     ` (12 subsequent siblings)
  14 siblings, 1 reply; 31+ messages in thread
From: Casey Schaufler @ 2025-06-21 17:18 UTC (permalink / raw)
  To: casey, paul, eparis, linux-security-module, audit
  Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
	stephen.smalley.work, linux-kernel, selinux

Add a parameter lsmid to security_lsmblob_to_secctx() to identify which
of the security modules that may be active should provide the security
context. If the value of lsmid is LSM_ID_UNDEF the first LSM providing
a hook is used. security_secid_to_secctx() is unchanged, and will
always report the first LSM providing a hook.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
 include/linux/security.h     |  6 ++++--
 kernel/audit.c               |  4 ++--
 kernel/auditsc.c             |  8 +++++---
 net/netlabel/netlabel_user.c |  3 ++-
 security/security.c          | 13 +++++++++++--
 5 files changed, 24 insertions(+), 10 deletions(-)

diff --git a/include/linux/security.h b/include/linux/security.h
index c032ec4e95ff..5fbe38521938 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -564,7 +564,8 @@ int security_getprocattr(struct task_struct *p, int lsmid, const char *name,
 int security_setprocattr(int lsmid, const char *name, void *value, size_t size);
 int security_ismaclabel(const char *name);
 int security_secid_to_secctx(u32 secid, struct lsm_context *cp);
-int security_lsmprop_to_secctx(struct lsm_prop *prop, struct lsm_context *cp);
+int security_lsmprop_to_secctx(struct lsm_prop *prop, struct lsm_context *cp,
+			       int lsmid);
 int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
 void security_release_secctx(struct lsm_context *cp);
 void security_inode_invalidate_secctx(struct inode *inode);
@@ -1536,7 +1537,8 @@ static inline int security_secid_to_secctx(u32 secid, struct lsm_context *cp)
 }
 
 static inline int security_lsmprop_to_secctx(struct lsm_prop *prop,
-					     struct lsm_context *cp)
+					     struct lsm_context *cp,
+					     int lsmid)
 {
 	return -EOPNOTSUPP;
 }
diff --git a/kernel/audit.c b/kernel/audit.c
index 547967cb4266..226c8ae00d04 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -1473,7 +1473,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
 	case AUDIT_SIGNAL_INFO:
 		if (lsmprop_is_set(&audit_sig_lsm)) {
 			err = security_lsmprop_to_secctx(&audit_sig_lsm,
-							 &lsmctx);
+							 &lsmctx, LSM_ID_UNDEF);
 			if (err < 0)
 				return err;
 		}
@@ -2188,7 +2188,7 @@ int audit_log_task_context(struct audit_buffer *ab)
 	if (!lsmprop_is_set(&prop))
 		return 0;
 
-	error = security_lsmprop_to_secctx(&prop, &ctx);
+	error = security_lsmprop_to_secctx(&prop, &ctx, LSM_ID_UNDEF);
 	if (error < 0) {
 		if (error != -EINVAL)
 			goto error_path;
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 528b6d2f5cb0..322d4e27f28e 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -1109,7 +1109,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 (lsmprop_is_set(prop)) {
-		if (security_lsmprop_to_secctx(prop, &ctx) < 0) {
+		if (security_lsmprop_to_secctx(prop, &ctx, LSM_ID_UNDEF) < 0) {
 			audit_log_format(ab, " obj=(none)");
 			rc = 1;
 		} else {
@@ -1395,7 +1395,8 @@ static void show_special(struct audit_context *context, int *call_panic)
 			struct lsm_context lsmctx;
 
 			if (security_lsmprop_to_secctx(&context->ipc.oprop,
-						       &lsmctx) < 0) {
+						       &lsmctx,
+						       LSM_ID_UNDEF) < 0) {
 				*call_panic = 1;
 			} else {
 				audit_log_format(ab, " obj=%s", lsmctx.context);
@@ -1560,7 +1561,8 @@ static void audit_log_name(struct audit_context *context, struct audit_names *n,
 	if (lsmprop_is_set(&n->oprop)) {
 		struct lsm_context ctx;
 
-		if (security_lsmprop_to_secctx(&n->oprop, &ctx) < 0) {
+		if (security_lsmprop_to_secctx(&n->oprop, &ctx,
+					       LSM_ID_UNDEF) < 0) {
 			if (call_panic)
 				*call_panic = 2;
 		} else {
diff --git a/net/netlabel/netlabel_user.c b/net/netlabel/netlabel_user.c
index 0d04d23aafe7..6d6545297ee3 100644
--- a/net/netlabel/netlabel_user.c
+++ b/net/netlabel/netlabel_user.c
@@ -98,7 +98,8 @@ struct audit_buffer *netlbl_audit_start_common(int type,
 			 audit_info->sessionid);
 
 	if (lsmprop_is_set(&audit_info->prop) &&
-	    security_lsmprop_to_secctx(&audit_info->prop, &ctx) > 0) {
+	    security_lsmprop_to_secctx(&audit_info->prop, &ctx,
+				       LSM_ID_UNDEF) > 0) {
 		audit_log_format(audit_buf, " subj=%s", ctx.context);
 		security_release_secctx(&ctx);
 	}
diff --git a/security/security.c b/security/security.c
index 8a4e0f70e49d..e4b596bedb93 100644
--- a/security/security.c
+++ b/security/security.c
@@ -3756,6 +3756,7 @@ EXPORT_SYMBOL(security_ismaclabel);
  * security_secid_to_secctx() - Convert a secid to a secctx
  * @secid: secid
  * @cp: the LSM context
+ * @lsmid: which security module to report
  *
  * Convert secid to security context.  If @cp is NULL the length of the
  * result will be returned, but no data will be returned.  This
@@ -3782,9 +3783,17 @@ EXPORT_SYMBOL(security_secid_to_secctx);
  *
  * Return: Return length of data on success, error on failure.
  */
-int security_lsmprop_to_secctx(struct lsm_prop *prop, struct lsm_context *cp)
+int security_lsmprop_to_secctx(struct lsm_prop *prop, struct lsm_context *cp,
+			       int lsmid)
 {
-	return call_int_hook(lsmprop_to_secctx, prop, cp);
+	struct lsm_static_call *scall;
+
+	lsm_for_each_hook(scall, lsmprop_to_secctx) {
+		if (lsmid != LSM_ID_UNDEF && lsmid != scall->hl->lsmid->id)
+			continue;
+		return scall->hl->hook.lsmprop_to_secctx(prop, cp);
+	}
+	return LSM_RET_DEFAULT(lsmprop_to_secctx);
 }
 EXPORT_SYMBOL(security_lsmprop_to_secctx);
 
-- 
2.47.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [RFC PATCH 03/15] Audit: Add record for multiple task security contexts
  2025-06-21 17:18 ` [RFC PATCH 00/15] LSM: No exclusive LSMs Casey Schaufler
  2025-06-21 17:18   ` [RFC PATCH 01/15] Audit: Create audit_stamp structure Casey Schaufler
  2025-06-21 17:18   ` [RFC PATCH 02/15] LSM: security_lsmblob_to_secctx module selection Casey Schaufler
@ 2025-06-21 17:18   ` Casey Schaufler
  2025-10-14 23:12     ` [PATCH RFC 3/15] " Paul Moore
  2025-06-21 17:18   ` [RFC PATCH 04/15] Audit: Add record for multiple object contexts Casey Schaufler
                     ` (11 subsequent siblings)
  14 siblings, 1 reply; 31+ messages in thread
From: Casey Schaufler @ 2025-06-21 17:18 UTC (permalink / raw)
  To: casey, paul, eparis, linux-security-module, audit
  Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
	stephen.smalley.work, linux-kernel, selinux

Replace the single skb pointer in an audit_buffer with a list of
skb pointers. Add the audit_stamp information to the audit_buffer as
there's no guarantee that there will be an audit_context containing
the stamp associated with the event. At audit_log_end() time create
auxiliary records as have been added to the list. Functions are
created to manage the skb list in the audit_buffer.

Create a new audit record AUDIT_MAC_TASK_CONTEXTS.
An example of the MAC_TASK_CONTEXTS record is:

    type=MAC_TASK_CONTEXTS
    msg=audit(1600880931.832:113)
    subj_apparmor=unconfined
    subj_smack=_

When an audit event includes a AUDIT_MAC_TASK_CONTEXTS record the
"subj=" field in other records in the event will be "subj=?".
An AUDIT_MAC_TASK_CONTEXTS record is supplied when the system has
multiple security modules that may make access decisions based on a
subject security context.

Refactor audit_log_task_context(), creating a new audit_log_subj_ctx().
This is used in netlabel auditing to provide multiple subject security
contexts as necessary.

Suggested-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
 include/linux/audit.h        |  16 +++
 include/uapi/linux/audit.h   |   1 +
 kernel/audit.c               | 207 +++++++++++++++++++++++++++++------
 net/netlabel/netlabel_user.c |   9 +-
 security/apparmor/lsm.c      |   3 +
 security/lsm.h               |   4 -
 security/lsm_init.c          |   5 -
 security/security.c          |   3 -
 security/selinux/hooks.c     |   3 +
 security/smack/smack_lsm.c   |   3 +
 10 files changed, 202 insertions(+), 52 deletions(-)

diff --git a/include/linux/audit.h b/include/linux/audit.h
index 0050ef288ab3..5020939fb8bc 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -37,6 +37,8 @@ struct audit_watch;
 struct audit_tree;
 struct sk_buff;
 struct kern_ipc_perm;
+struct lsm_id;
+struct lsm_prop;
 
 struct audit_krule {
 	u32			pflags;
@@ -147,6 +149,9 @@ extern unsigned compat_signal_class[];
 #define AUDIT_TTY_ENABLE	BIT(0)
 #define AUDIT_TTY_LOG_PASSWD	BIT(1)
 
+/* bit values for audit_lsm_secctx */
+#define AUDIT_SECCTX_SUBJECT	BIT(0)
+
 struct filename;
 
 #define AUDIT_OFF	0
@@ -185,6 +190,7 @@ extern void		    audit_log_path_denied(int type,
 						  const char *operation);
 extern void		    audit_log_lost(const char *message);
 
+extern int audit_log_subj_ctx(struct audit_buffer *ab, struct lsm_prop *prop);
 extern int audit_log_task_context(struct audit_buffer *ab);
 extern void audit_log_task_info(struct audit_buffer *ab);
 
@@ -210,6 +216,8 @@ extern u32 audit_enabled;
 
 extern int audit_signal_info(int sig, struct task_struct *t);
 
+extern void audit_lsm_secctx(const struct lsm_id *lsmid, int flags);
+
 #else /* CONFIG_AUDIT */
 static inline __printf(4, 5)
 void audit_log(struct audit_context *ctx, gfp_t gfp_mask, int type,
@@ -245,6 +253,11 @@ 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_subj_ctx(struct audit_buffer *ab,
+				     struct lsm_prop *prop)
+{
+	return 0;
+}
 static inline int audit_log_task_context(struct audit_buffer *ab)
 {
 	return 0;
@@ -269,6 +282,9 @@ static inline int audit_signal_info(int sig, struct task_struct *t)
 	return 0;
 }
 
+static inline void audit_lsm_secctx(const struct lsm_id *lsmid, int flags)
+{ }
+
 #endif /* CONFIG_AUDIT */
 
 #ifdef CONFIG_AUDIT_COMPAT_GENERIC
diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h
index 9a4ecc9f6dc5..8cad2f307719 100644
--- a/include/uapi/linux/audit.h
+++ b/include/uapi/linux/audit.h
@@ -148,6 +148,7 @@
 #define AUDIT_IPE_POLICY_LOAD	1422	/* IPE policy load */
 #define AUDIT_LANDLOCK_ACCESS	1423	/* Landlock denial */
 #define AUDIT_LANDLOCK_DOMAIN	1424	/* Landlock domain status */
+#define AUDIT_MAC_TASK_CONTEXTS	1425	/* Multiple LSM task 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 226c8ae00d04..2ddb5d7696da 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -54,6 +54,7 @@
 #include <net/netlink.h>
 #include <linux/skbuff.h>
 #include <linux/security.h>
+#include <linux/lsm_hooks.h>
 #include <linux/freezer.h>
 #include <linux/pid_namespace.h>
 #include <net/netns/generic.h>
@@ -81,6 +82,11 @@ static u32	audit_failure = AUDIT_FAIL_PRINTK;
 /* private audit network namespace index */
 static unsigned int audit_net_id;
 
+/* Number of modules that provide a security context.
+   List of lsms that provide a security context */
+static u32 audit_subj_secctx_cnt;
+static const struct lsm_id *audit_subj_lsms[MAX_LSM_COUNT];
+
 /**
  * struct audit_net - audit private network namespace data
  * @sk: communication socket
@@ -195,8 +201,10 @@ static struct audit_ctl_mutex {
  * to place it on a transmit queue.  Multiple audit_buffers can be in
  * use simultaneously. */
 struct audit_buffer {
-	struct sk_buff       *skb;	/* formatted skb ready to send */
+	struct sk_buff       *skb;	/* the skb for audit_log functions */
+	struct sk_buff_head  skb_list;	/* formatted skbs, ready to send */
 	struct audit_context *ctx;	/* NULL or associated context */
+	struct audit_stamp   stamp;	/* audit stamp for these records */
 	gfp_t		     gfp_mask;
 };
 
@@ -278,6 +286,27 @@ static pid_t auditd_pid_vnr(void)
 	return pid;
 }
 
+/**
+ * audit_lsm_secctx - Identify a security module as providing a secctx.
+ * @lsmid: LSM identity
+ * @flags: which contexts are provided
+ *
+ * Description:
+ * Increments the count of the security modules providing a secctx.
+ * If the LSM id is already in the list leave it alone.
+ */
+void audit_lsm_secctx(const struct lsm_id *lsmid, int flags)
+{
+	int i;
+
+	if (flags & AUDIT_SECCTX_SUBJECT) {
+		for (i = 0 ; i < audit_subj_secctx_cnt; i++)
+			if (audit_subj_lsms[i] == lsmid)
+				return;
+		audit_subj_lsms[audit_subj_secctx_cnt++] = lsmid;
+	}
+}
+
 /**
  * audit_get_sk - Return the audit socket for the given network namespace
  * @net: the destination network namespace
@@ -1776,10 +1805,13 @@ __setup("audit_backlog_limit=", audit_backlog_limit_set);
 
 static void audit_buffer_free(struct audit_buffer *ab)
 {
+	struct sk_buff *skb;
+
 	if (!ab)
 		return;
 
-	kfree_skb(ab->skb);
+	while ((skb = skb_dequeue(&ab->skb_list)))
+		kfree_skb(skb);
 	kmem_cache_free(audit_buffer_cache, ab);
 }
 
@@ -1795,6 +1827,10 @@ static struct audit_buffer *audit_buffer_alloc(struct audit_context *ctx,
 	ab->skb = nlmsg_new(AUDIT_BUFSIZ, gfp_mask);
 	if (!ab->skb)
 		goto err;
+
+	skb_queue_head_init(&ab->skb_list);
+	skb_queue_tail(&ab->skb_list, ab->skb);
+
 	if (!nlmsg_put(ab->skb, 0, 0, type, 0, 0))
 		goto err;
 
@@ -1860,7 +1896,6 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
 				     int type)
 {
 	struct audit_buffer *ab;
-	struct audit_stamp stamp;
 
 	if (audit_initialized != AUDIT_INITIALIZED)
 		return NULL;
@@ -1915,14 +1950,14 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
 		return NULL;
 	}
 
-	audit_get_stamp(ab->ctx, &stamp);
+	audit_get_stamp(ab->ctx, &ab->stamp);
 	/* cancel dummy context to enable supporting records */
 	if (ctx)
 		ctx->dummy = 0;
 	audit_log_format(ab, "audit(%llu.%03lu:%u): ",
-			 (unsigned long long)stamp.ctime.tv_sec,
-			 stamp.ctime.tv_nsec/1000000,
-			 stamp.serial);
+			 (unsigned long long)ab->stamp.ctime.tv_sec,
+			 ab->stamp.ctime.tv_nsec/1000000,
+			 ab->stamp.serial);
 
 	return ab;
 }
@@ -2178,31 +2213,128 @@ void audit_log_key(struct audit_buffer *ab, char *key)
 		audit_log_format(ab, "(null)");
 }
 
-int audit_log_task_context(struct audit_buffer *ab)
+/**
+ * audit_buffer_aux_new - Add an aux record buffer to the skb list
+ * @ab: audit_buffer
+ * @type: message type
+ *
+ * Aux records are allocated and added to the skb list of
+ * the "main" record. The ab->skb is reset to point to the
+ * aux record on its creation. When the aux record in complete
+ * ab->skb has to be reset to point to the "main" record.
+ * This allows the audit_log_ functions to be ignorant of
+ * which kind of record it is logging to. It also avoids adding
+ * special data for aux records.
+ *
+ * On success ab->skb will point to the new aux record.
+ * Returns 0 on success, -ENOMEM should allocation fail.
+ */
+static int audit_buffer_aux_new(struct audit_buffer *ab, int type)
+{
+	WARN_ON(ab->skb != skb_peek(&ab->skb_list));
+
+	ab->skb = nlmsg_new(AUDIT_BUFSIZ, ab->gfp_mask);
+	if (!ab->skb)
+		goto err;
+	if (!nlmsg_put(ab->skb, 0, 0, type, 0, 0))
+		goto err;
+	skb_queue_tail(&ab->skb_list, ab->skb);
+
+	audit_log_format(ab, "audit(%llu.%03lu:%u): ",
+			 (unsigned long long)ab->stamp.ctime.tv_sec,
+			 ab->stamp.ctime.tv_nsec/1000000,
+			 ab->stamp.serial);
+
+	return 0;
+
+err:
+	kfree_skb(ab->skb);
+	ab->skb = skb_peek(&ab->skb_list);
+	return -ENOMEM;
+}
+
+/**
+ * audit_buffer_aux_end - Switch back to the "main" record from an aux record
+ * @ab: audit_buffer
+ *
+ * Restores the "main" audit record to ab->skb.
+ */
+static void audit_buffer_aux_end(struct audit_buffer *ab)
+{
+	ab->skb = skb_peek(&ab->skb_list);
+}
+
+/**
+ * audit_log_subj_ctx - Add LSM subject information
+ * @ab: audit_buffer
+ * @prop: LSM subject properties.
+ *
+ * Add a subj= field and, if necessary, a AUDIT_MAC_TASK_CONTEXTS record.
+ */
+int audit_log_subj_ctx(struct audit_buffer *ab, struct lsm_prop *prop)
 {
-	struct lsm_prop prop;
 	struct lsm_context ctx;
+	char *space = "";
 	int error;
+	int i;
 
-	security_current_getlsmprop_subj(&prop);
-	if (!lsmprop_is_set(&prop))
+	security_current_getlsmprop_subj(prop);
+	if (!lsmprop_is_set(prop))
 		return 0;
 
-	error = security_lsmprop_to_secctx(&prop, &ctx, LSM_ID_UNDEF);
-	if (error < 0) {
-		if (error != -EINVAL)
-			goto error_path;
+	if (audit_subj_secctx_cnt < 2) {
+		error = security_lsmprop_to_secctx(prop, &ctx, LSM_ID_UNDEF);
+		if (error < 0) {
+			if (error != -EINVAL)
+				goto error_path;
+			return 0;
+		}
+		audit_log_format(ab, " subj=%s", ctx.context);
+		security_release_secctx(&ctx);
 		return 0;
 	}
-
-	audit_log_format(ab, " subj=%s", ctx.context);
-	security_release_secctx(&ctx);
+	/* Multiple LSMs provide contexts. Include an aux record. */
+	audit_log_format(ab, " subj=?");
+	error = audit_buffer_aux_new(ab, AUDIT_MAC_TASK_CONTEXTS);
+	if (error)
+		goto error_path;
+
+	for (i = 0; i < audit_subj_secctx_cnt; i++) {
+		error = security_lsmprop_to_secctx(prop, &ctx,
+						   audit_subj_lsms[i]->id);
+		if (error < 0) {
+			/*
+			 * Don't print anything. An LSM like BPF could
+			 * claim to support contexts, but only do so under
+			 * certain conditions.
+			 */
+			if (error == -EOPNOTSUPP)
+				continue;
+			if (error != -EINVAL)
+				audit_panic("error in audit_log_task_context");
+		} else {
+			audit_log_format(ab, "%ssubj_%s=%s", space,
+					 audit_subj_lsms[i]->name, ctx.context);
+			space = " ";
+			security_release_secctx(&ctx);
+		}
+	}
+	audit_buffer_aux_end(ab);
 	return 0;
 
 error_path:
-	audit_panic("error in audit_log_task_context");
+	audit_panic("error in audit_log_subj_ctx");
 	return error;
 }
+EXPORT_SYMBOL(audit_log_subj_ctx);
+
+int audit_log_task_context(struct audit_buffer *ab)
+{
+	struct lsm_prop prop;
+
+	security_current_getlsmprop_subj(&prop);
+	return audit_log_subj_ctx(ab, &prop);
+}
 EXPORT_SYMBOL(audit_log_task_context);
 
 void audit_log_d_path_exe(struct audit_buffer *ab,
@@ -2411,6 +2543,26 @@ int audit_signal_info(int sig, struct task_struct *t)
 	return audit_signal_info_syscall(t);
 }
 
+/**
+ * __audit_log_end - enqueue one audit record
+ * @skb: the buffer to send
+ */
+static void __audit_log_end(struct sk_buff *skb)
+{
+	struct nlmsghdr *nlh;
+
+	if (audit_rate_check()) {
+		/* setup the netlink header, see the comments in
+		 * kauditd_send_multicast_skb() for length quirks */
+		nlh = nlmsg_hdr(skb);
+		nlh->nlmsg_len = skb->len - NLMSG_HDRLEN;
+
+		/* queue the netlink packet */
+		skb_queue_tail(&audit_queue, skb);
+	} else
+		audit_log_lost("rate limit exceeded");
+}
+
 /**
  * audit_log_end - end one audit record
  * @ab: the audit_buffer
@@ -2423,25 +2575,16 @@ int audit_signal_info(int sig, struct task_struct *t)
 void audit_log_end(struct audit_buffer *ab)
 {
 	struct sk_buff *skb;
-	struct nlmsghdr *nlh;
 
 	if (!ab)
 		return;
 
-	if (audit_rate_check()) {
-		skb = ab->skb;
-		ab->skb = NULL;
+	while ((skb = skb_dequeue(&ab->skb_list)))
+		__audit_log_end(skb);
 
-		/* setup the netlink header, see the comments in
-		 * kauditd_send_multicast_skb() for length quirks */
-		nlh = nlmsg_hdr(skb);
-		nlh->nlmsg_len = skb->len - NLMSG_HDRLEN;
-
-		/* queue the netlink packet and poke the kauditd thread */
-		skb_queue_tail(&audit_queue, skb);
+	/* poke the kauditd thread */
+	if (audit_rate_check())
 		wake_up_interruptible(&kauditd_wait);
-	} else
-		audit_log_lost("rate limit exceeded");
 
 	audit_buffer_free(ab);
 }
diff --git a/net/netlabel/netlabel_user.c b/net/netlabel/netlabel_user.c
index 6d6545297ee3..0da652844dd6 100644
--- a/net/netlabel/netlabel_user.c
+++ b/net/netlabel/netlabel_user.c
@@ -84,7 +84,6 @@ struct audit_buffer *netlbl_audit_start_common(int type,
 					       struct netlbl_audit *audit_info)
 {
 	struct audit_buffer *audit_buf;
-	struct lsm_context ctx;
 
 	if (audit_enabled == AUDIT_OFF)
 		return NULL;
@@ -96,13 +95,7 @@ struct audit_buffer *netlbl_audit_start_common(int type,
 	audit_log_format(audit_buf, "netlabel: auid=%u ses=%u",
 			 from_kuid(&init_user_ns, audit_info->loginuid),
 			 audit_info->sessionid);
-
-	if (lsmprop_is_set(&audit_info->prop) &&
-	    security_lsmprop_to_secctx(&audit_info->prop, &ctx,
-				       LSM_ID_UNDEF) > 0) {
-		audit_log_format(audit_buf, " subj=%s", ctx.context);
-		security_release_secctx(&ctx);
-	}
+	audit_log_subj_ctx(audit_buf, &audit_info->prop);
 
 	return audit_buf;
 }
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index db8592bed189..4ba6db93e5b0 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -2251,6 +2251,9 @@ static int __init apparmor_init(void)
 	security_add_hooks(apparmor_hooks, ARRAY_SIZE(apparmor_hooks),
 				&apparmor_lsmid);
 
+	/* Inform the audit system that secctx is used */
+	audit_lsm_secctx(&apparmor_lsmid, AUDIT_SECCTX_SUBJECT);
+
 	/* Report that AppArmor successfully initialized */
 	apparmor_initialized = 1;
 	if (aa_g_profile_mode == APPARMOR_COMPLAIN)
diff --git a/security/lsm.h b/security/lsm.h
index d1d54540da98..c432dc0c5e30 100644
--- a/security/lsm.h
+++ b/security/lsm.h
@@ -24,10 +24,6 @@ extern bool lsm_debug;
 extern unsigned int lsm_count;
 extern const struct lsm_id *lsm_idlist[];
 
-/* LSM property configuration */
-extern unsigned int lsm_count_prop_subj;
-extern unsigned int lsm_count_prop_obj;
-
 /* LSM blob configuration */
 extern struct lsm_blob_sizes blob_sizes;
 
diff --git a/security/lsm_init.c b/security/lsm_init.c
index c2ef4db055db..54166688efff 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -190,11 +190,6 @@ static void __init lsm_order_append(struct lsm_info *lsm, const char *src)
 	lsm_order[lsm_count] = lsm;
 	lsm_idlist[lsm_count++] = lsm->id;
 
-	if (lsm->id->flags & LSM_ID_FLG_PROP_SUBJ)
-		lsm_count_prop_subj++;
-	if (lsm->id->flags & LSM_ID_FLG_PROP_OBJ)
-		lsm_count_prop_obj++;
-
 	lsm_pr_dbg("enabling LSM %s:%s\n", src, lsm->id->name);
 }
 
diff --git a/security/security.c b/security/security.c
index e4b596bedb93..db85006d2fd5 100644
--- a/security/security.c
+++ b/security/security.c
@@ -78,9 +78,6 @@ bool lsm_debug __ro_after_init;
 unsigned int lsm_count __ro_after_init;
 const struct lsm_id *lsm_idlist[MAX_LSM_COUNT];
 
-unsigned int lsm_count_prop_subj __ro_after_init;
-unsigned int lsm_count_prop_obj __ro_after_init;
-
 struct lsm_blob_sizes blob_sizes;
 
 struct kmem_cache *lsm_file_cache;
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index b00c2627286a..9a64c76839da 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -7594,6 +7594,9 @@ static __init int selinux_init(void)
 	/* Set the security state for the initial task. */
 	cred_init_security();
 
+	/* Inform the audit system that secctx is used */
+	audit_lsm_secctx(&selinux_lsmid, AUDIT_SECCTX_SUBJECT);
+
 	default_noexec = !(VM_DATA_DEFAULT_FLAGS & VM_EXEC);
 	if (!default_noexec)
 		pr_notice("SELinux:  virtual memory is executable by default\n");
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 46ef5ece991c..3a8d9324d040 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -5268,6 +5268,9 @@ static __init int smack_init(void)
 	/* initialize the smack_known_list */
 	init_smack_known_list();
 
+	/* Inform the audit system that secctx is used */
+	audit_lsm_secctx(&smack_lsmid, AUDIT_SECCTX_SUBJECT);
+
 	return 0;
 }
 
-- 
2.47.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [RFC PATCH 04/15] Audit: Add record for multiple object contexts
  2025-06-21 17:18 ` [RFC PATCH 00/15] LSM: No exclusive LSMs Casey Schaufler
                     ` (2 preceding siblings ...)
  2025-06-21 17:18   ` [RFC PATCH 03/15] Audit: Add record for multiple task security contexts Casey Schaufler
@ 2025-06-21 17:18   ` Casey Schaufler
  2025-10-14 23:12     ` [PATCH RFC 4/15] " Paul Moore
  2025-06-21 17:18   ` [RFC PATCH 05/15] LSM: Single calls in secid hooks Casey Schaufler
                     ` (10 subsequent siblings)
  14 siblings, 1 reply; 31+ messages in thread
From: Casey Schaufler @ 2025-06-21 17:18 UTC (permalink / raw)
  To: casey, paul, eparis, linux-security-module, audit
  Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
	stephen.smalley.work, linux-kernel, selinux

Create a new audit record AUDIT_MAC_OBJ_CONTEXTS.
An example of the MAC_OBJ_CONTEXTS record is:

    type=MAC_OBJ_CONTEXTS
    msg=audit(1601152467.009:1050):
    obj_selinux=unconfined_u:object_r:user_home_t:s0

When an audit event includes a AUDIT_MAC_OBJ_CONTEXTS record
the "obj=" field in other records in the event will be "obj=?".
An AUDIT_MAC_OBJ_CONTEXTS record is supplied when the system has
multiple security modules that may make access decisions based
on an object security context.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
 include/linux/audit.h      |  7 +++++
 include/uapi/linux/audit.h |  1 +
 kernel/audit.c             | 58 +++++++++++++++++++++++++++++++++++++-
 kernel/auditsc.c           | 45 ++++++++---------------------
 security/selinux/hooks.c   |  3 +-
 security/smack/smack_lsm.c |  3 +-
 6 files changed, 80 insertions(+), 37 deletions(-)

diff --git a/include/linux/audit.h b/include/linux/audit.h
index 5020939fb8bc..c507fdfcf534 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -151,6 +151,7 @@ extern unsigned compat_signal_class[];
 
 /* bit values for audit_lsm_secctx */
 #define AUDIT_SECCTX_SUBJECT	BIT(0)
+#define AUDIT_SECCTX_OBJECT	BIT(1)
 
 struct filename;
 
@@ -191,6 +192,7 @@ extern void		    audit_log_path_denied(int type,
 extern void		    audit_log_lost(const char *message);
 
 extern int audit_log_subj_ctx(struct audit_buffer *ab, struct lsm_prop *prop);
+extern int audit_log_obj_ctx(struct audit_buffer *ab, struct lsm_prop *prop);
 extern int audit_log_task_context(struct audit_buffer *ab);
 extern void audit_log_task_info(struct audit_buffer *ab);
 
@@ -258,6 +260,11 @@ static inline int audit_log_subj_ctx(struct audit_buffer *ab,
 {
 	return 0;
 }
+static inline int audit_log_obj_ctx(struct audit_buffer *ab,
+				    struct lsm_prop *prop)
+{
+	return 0;
+}
 static inline int audit_log_task_context(struct audit_buffer *ab)
 {
 	return 0;
diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h
index 8cad2f307719..14a1c1fe013a 100644
--- a/include/uapi/linux/audit.h
+++ b/include/uapi/linux/audit.h
@@ -149,6 +149,7 @@
 #define AUDIT_LANDLOCK_ACCESS	1423	/* Landlock denial */
 #define AUDIT_LANDLOCK_DOMAIN	1424	/* Landlock domain status */
 #define AUDIT_MAC_TASK_CONTEXTS	1425	/* Multiple LSM task contexts */
+#define AUDIT_MAC_OBJ_CONTEXTS	1426	/* Multiple LSM objext 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 2ddb5d7696da..fbb991dec717 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -85,7 +85,9 @@ static unsigned int audit_net_id;
 /* Number of modules that provide a security context.
    List of lsms that provide a security context */
 static u32 audit_subj_secctx_cnt;
+static u32 audit_obj_secctx_cnt;
 static const struct lsm_id *audit_subj_lsms[MAX_LSM_COUNT];
+static const struct lsm_id *audit_obj_lsms[MAX_LSM_COUNT];
 
 /**
  * struct audit_net - audit private network namespace data
@@ -305,6 +307,12 @@ void audit_lsm_secctx(const struct lsm_id *lsmid, int flags)
 				return;
 		audit_subj_lsms[audit_subj_secctx_cnt++] = lsmid;
 	}
+	if (flags & AUDIT_SECCTX_OBJECT) {
+		for (i = 0 ; i < audit_obj_secctx_cnt; i++)
+			if (audit_obj_lsms[i] == lsmid)
+				return;
+		audit_obj_lsms[audit_obj_secctx_cnt++] = lsmid;
+	}
 }
 
 /**
@@ -1142,7 +1150,6 @@ static int is_audit_feature_set(int i)
 	return af.features & AUDIT_FEATURE_TO_MASK(i);
 }
 
-
 static int audit_get_feature(struct sk_buff *skb)
 {
 	u32 seq;
@@ -2337,6 +2344,55 @@ int audit_log_task_context(struct audit_buffer *ab)
 }
 EXPORT_SYMBOL(audit_log_task_context);
 
+int audit_log_obj_ctx(struct audit_buffer *ab, struct lsm_prop *prop)
+{
+	int i;
+	int rc;
+	int error = 0;
+	char *space = "";
+	struct lsm_context ctx;
+
+	if (audit_obj_secctx_cnt < 2) {
+		error = security_lsmprop_to_secctx(prop, &ctx, LSM_ID_UNDEF);
+		if (error < 0) {
+			if (error != -EINVAL)
+				goto error_path;
+			return error;
+		}
+		audit_log_format(ab, " obj=%s", ctx.context);
+		security_release_secctx(&ctx);
+		return 0;
+	}
+	audit_log_format(ab, " obj=?");
+	error = audit_buffer_aux_new(ab, AUDIT_MAC_OBJ_CONTEXTS);
+	if (error)
+		goto error_path;
+
+	for (i = 0; i < audit_obj_secctx_cnt; i++) {
+		rc = security_lsmprop_to_secctx(prop, &ctx,
+						audit_obj_lsms[i]->id);
+		if (rc < 0) {
+			audit_log_format(ab, "%sobj_%s=?", space,
+					 audit_obj_lsms[i]->name);
+			if (rc != -EINVAL)
+				audit_panic("error in audit_log_obj_ctx");
+			error = rc;
+		} else {
+			audit_log_format(ab, "%sobj_%s=%s", space,
+					 audit_obj_lsms[i]->name, ctx.context);
+			security_release_secctx(&ctx);
+		}
+		space = " ";
+	}
+
+	audit_buffer_aux_end(ab);
+	return error;
+
+error_path:
+	audit_panic("error in audit_log_obj_ctx");
+	return error;
+}
+
 void audit_log_d_path_exe(struct audit_buffer *ab,
 			  struct mm_struct *mm)
 {
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 322d4e27f28e..0c28fa33d099 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -1098,7 +1098,6 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
 				 char *comm)
 {
 	struct audit_buffer *ab;
-	struct lsm_context ctx;
 	int rc = 0;
 
 	ab = audit_log_start(context, GFP_KERNEL, AUDIT_OBJ_PID);
@@ -1108,15 +1107,9 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
 	audit_log_format(ab, "opid=%d oauid=%d ouid=%d oses=%d", pid,
 			 from_kuid(&init_user_ns, auid),
 			 from_kuid(&init_user_ns, uid), sessionid);
-	if (lsmprop_is_set(prop)) {
-		if (security_lsmprop_to_secctx(prop, &ctx, LSM_ID_UNDEF) < 0) {
-			audit_log_format(ab, " obj=(none)");
-			rc = 1;
-		} else {
-			audit_log_format(ab, " obj=%s", ctx.context);
-			security_release_secctx(&ctx);
-		}
-	}
+	if (lsmprop_is_set(prop) && audit_log_obj_ctx(ab, prop))
+		rc = 1;
+
 	audit_log_format(ab, " ocomm=");
 	audit_log_untrustedstring(ab, comm);
 	audit_log_end(ab);
@@ -1392,16 +1385,8 @@ static void show_special(struct audit_context *context, int *call_panic)
 				 from_kgid(&init_user_ns, context->ipc.gid),
 				 context->ipc.mode);
 		if (lsmprop_is_set(&context->ipc.oprop)) {
-			struct lsm_context lsmctx;
-
-			if (security_lsmprop_to_secctx(&context->ipc.oprop,
-						       &lsmctx,
-						       LSM_ID_UNDEF) < 0) {
+			if (audit_log_obj_ctx(ab, &context->ipc.oprop))
 				*call_panic = 1;
-			} else {
-				audit_log_format(ab, " obj=%s", lsmctx.context);
-				security_release_secctx(&lsmctx);
-			}
 		}
 		if (context->ipc.has_perm) {
 			audit_log_end(ab);
@@ -1558,18 +1543,9 @@ static void audit_log_name(struct audit_context *context, struct audit_names *n,
 				 from_kgid(&init_user_ns, n->gid),
 				 MAJOR(n->rdev),
 				 MINOR(n->rdev));
-	if (lsmprop_is_set(&n->oprop)) {
-		struct lsm_context ctx;
-
-		if (security_lsmprop_to_secctx(&n->oprop, &ctx,
-					       LSM_ID_UNDEF) < 0) {
-			if (call_panic)
-				*call_panic = 2;
-		} else {
-			audit_log_format(ab, " obj=%s", ctx.context);
-			security_release_secctx(&ctx);
-		}
-	}
+	if (lsmprop_is_set(&n->oprop) &&
+	    audit_log_obj_ctx(ab, &n->oprop))
+		*call_panic = 2;
 
 	/* log the audit_names record type */
 	switch (n->type) {
@@ -1780,15 +1756,16 @@ static void audit_log_exit(void)
 						  axs->target_sessionid[i],
 						  &axs->target_ref[i],
 						  axs->target_comm[i]))
-				call_panic = 1;
+			call_panic = 1;
 	}
 
 	if (context->target_pid &&
 	    audit_log_pid_context(context, context->target_pid,
 				  context->target_auid, context->target_uid,
 				  context->target_sessionid,
-				  &context->target_ref, context->target_comm))
-			call_panic = 1;
+				  &context->target_ref,
+				  context->target_comm))
+		call_panic = 1;
 
 	if (context->pwd.dentry && context->pwd.mnt) {
 		ab = audit_log_start(context, GFP_KERNEL, AUDIT_CWD);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 9a64c76839da..9f816e25198a 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -7595,7 +7595,8 @@ static __init int selinux_init(void)
 	cred_init_security();
 
 	/* Inform the audit system that secctx is used */
-	audit_lsm_secctx(&selinux_lsmid, AUDIT_SECCTX_SUBJECT);
+	audit_lsm_secctx(&selinux_lsmid,
+			 AUDIT_SECCTX_SUBJECT | AUDIT_SECCTX_OBJECT);
 
 	default_noexec = !(VM_DATA_DEFAULT_FLAGS & VM_EXEC);
 	if (!default_noexec)
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 3a8d9324d040..d363adead435 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -5269,7 +5269,8 @@ static __init int smack_init(void)
 	init_smack_known_list();
 
 	/* Inform the audit system that secctx is used */
-	audit_lsm_secctx(&smack_lsmid, AUDIT_SECCTX_SUBJECT);
+	audit_lsm_secctx(&smack_lsmid,
+			 AUDIT_SECCTX_SUBJECT | AUDIT_SECCTX_OBJECT);
 
 	return 0;
 }
-- 
2.47.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [RFC PATCH 05/15] LSM: Single calls in secid hooks
  2025-06-21 17:18 ` [RFC PATCH 00/15] LSM: No exclusive LSMs Casey Schaufler
                     ` (3 preceding siblings ...)
  2025-06-21 17:18   ` [RFC PATCH 04/15] Audit: Add record for multiple object contexts Casey Schaufler
@ 2025-06-21 17:18   ` Casey Schaufler
  2025-10-14 23:12     ` [PATCH RFC 5/15] " Paul Moore
  2025-06-21 17:18   ` [RFC PATCH 06/15] LSM: Exclusive secmark usage Casey Schaufler
                     ` (9 subsequent siblings)
  14 siblings, 1 reply; 31+ messages in thread
From: Casey Schaufler @ 2025-06-21 17:18 UTC (permalink / raw)
  To: casey, paul, eparis, linux-security-module, audit
  Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
	stephen.smalley.work, linux-kernel, selinux

security_socket_getpeersec_stream(), security_socket_getpeersec_dgram()
and security_secctx_to_secid() can only provide a single security context
or secid to their callers.  Open code these hooks to return the first
hook provided. Because only one "major" LSM is allowed there will only
be one hook in the list, with the excepton being BPF. BPF is not expected
to be using these interfaces.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
 security/security.c | 24 ++++++++++++++++++++----
 1 file changed, 20 insertions(+), 4 deletions(-)

diff --git a/security/security.c b/security/security.c
index db85006d2fd5..2286285f8aea 100644
--- a/security/security.c
+++ b/security/security.c
@@ -3806,8 +3806,13 @@ EXPORT_SYMBOL(security_lsmprop_to_secctx);
  */
 int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
 {
+	struct lsm_static_call *scall;
+
 	*secid = 0;
-	return call_int_hook(secctx_to_secid, secdata, seclen, secid);
+	lsm_for_each_hook(scall, secctx_to_secid) {
+		return scall->hl->hook.secctx_to_secid(secdata, seclen, secid);
+	}
+	return LSM_RET_DEFAULT(secctx_to_secid);
 }
 EXPORT_SYMBOL(security_secctx_to_secid);
 
@@ -4268,8 +4273,13 @@ EXPORT_SYMBOL(security_sock_rcv_skb);
 int security_socket_getpeersec_stream(struct socket *sock, sockptr_t optval,
 				      sockptr_t optlen, unsigned int len)
 {
-	return call_int_hook(socket_getpeersec_stream, sock, optval, optlen,
-			     len);
+	struct lsm_static_call *scall;
+
+	lsm_for_each_hook(scall, socket_getpeersec_stream) {
+		return scall->hl->hook.socket_getpeersec_stream(sock, optval,
+								optlen, len);
+	}
+	return LSM_RET_DEFAULT(socket_getpeersec_stream);
 }
 
 /**
@@ -4289,7 +4299,13 @@ int security_socket_getpeersec_stream(struct socket *sock, sockptr_t optval,
 int security_socket_getpeersec_dgram(struct socket *sock,
 				     struct sk_buff *skb, u32 *secid)
 {
-	return call_int_hook(socket_getpeersec_dgram, sock, skb, secid);
+	struct lsm_static_call *scall;
+
+	lsm_for_each_hook(scall, socket_getpeersec_dgram) {
+		return scall->hl->hook.socket_getpeersec_dgram(sock, skb,
+							       secid);
+	}
+	return LSM_RET_DEFAULT(socket_getpeersec_dgram);
 }
 EXPORT_SYMBOL(security_socket_getpeersec_dgram);
 
-- 
2.47.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [RFC PATCH 06/15] LSM: Exclusive secmark usage
  2025-06-21 17:18 ` [RFC PATCH 00/15] LSM: No exclusive LSMs Casey Schaufler
                     ` (4 preceding siblings ...)
  2025-06-21 17:18   ` [RFC PATCH 05/15] LSM: Single calls in secid hooks Casey Schaufler
@ 2025-06-21 17:18   ` Casey Schaufler
  2025-10-14 23:12     ` [PATCH RFC 6/15] " Paul Moore
  2025-06-21 17:18   ` [RFC PATCH 07/15] Audit: Call only the first of the audit rule hooks Casey Schaufler
                     ` (8 subsequent siblings)
  14 siblings, 1 reply; 31+ messages in thread
From: Casey Schaufler @ 2025-06-21 17:18 UTC (permalink / raw)
  To: casey, paul, eparis, linux-security-module, audit
  Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
	stephen.smalley.work, linux-kernel, selinux

The network secmark can only be used by one security module
at a time. Establish mechanism to identify to security modules
whether they have access to the secmark. SELinux already
incorparates mechanism, but it has to be added to Smack and
AppArmor.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
 include/linux/lsm_hooks.h        |  1 +
 security/apparmor/include/net.h  |  5 +++++
 security/apparmor/lsm.c          |  7 ++++---
 security/lsm_init.c              |  6 ++++++
 security/selinux/hooks.c         |  4 +++-
 security/smack/smack.h           |  5 +++++
 security/smack/smack_lsm.c       |  3 ++-
 security/smack/smack_netfilter.c | 10 ++++++++--
 8 files changed, 34 insertions(+), 7 deletions(-)

diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 5bc144c5f685..1ad9f8a86b10 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -122,6 +122,7 @@ struct lsm_blob_sizes {
 	unsigned int lbs_xattr_count; /* num xattr slots in new_xattrs array */
 	unsigned int lbs_tun_dev;
 	unsigned int lbs_bdev;
+	bool lbs_secmark; /* expressed desire for secmark use */
 };
 
 /*
diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h
index c42ed8a73f1c..2e43e1e8303c 100644
--- a/security/apparmor/include/net.h
+++ b/security/apparmor/include/net.h
@@ -51,6 +51,11 @@ struct aa_sk_ctx {
 	struct aa_label *peer;
 };
 
+static inline bool aa_secmark(void)
+{
+	return apparmor_blob_sizes.lbs_secmark;
+}
+
 static inline struct aa_sk_ctx *aa_sock(const struct sock *sk)
 {
 	return sk->sk_security + apparmor_blob_sizes.lbs_sock;
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 4ba6db93e5b0..255d2e40386f 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -1291,7 +1291,7 @@ static int apparmor_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
 {
 	struct aa_sk_ctx *ctx = aa_sock(sk);
 
-	if (!skb->secmark)
+	if (!aa_secmark() || !skb->secmark)
 		return 0;
 
 	/*
@@ -1407,7 +1407,7 @@ static int apparmor_inet_conn_request(const struct sock *sk, struct sk_buff *skb
 {
 	struct aa_sk_ctx *ctx = aa_sock(sk);
 
-	if (!skb->secmark)
+	if (!aa_secmark() || !skb->secmark)
 		return 0;
 
 	return apparmor_secmark_check(ctx->label, OP_CONNECT, AA_MAY_CONNECT,
@@ -1423,6 +1423,7 @@ struct lsm_blob_sizes apparmor_blob_sizes __ro_after_init = {
 	.lbs_file = sizeof(struct aa_file_ctx),
 	.lbs_task = sizeof(struct aa_task_ctx),
 	.lbs_sock = sizeof(struct aa_sk_ctx),
+	.lbs_secmark = true,
 };
 
 static const struct lsm_id apparmor_lsmid = {
@@ -2085,7 +2086,7 @@ static unsigned int apparmor_ip_postroute(void *priv,
 	struct aa_sk_ctx *ctx;
 	struct sock *sk;
 
-	if (!skb->secmark)
+	if (!aa_secmark() || !skb->secmark)
 		return NF_ACCEPT;
 
 	sk = skb_to_full_sk(skb);
diff --git a/security/lsm_init.c b/security/lsm_init.c
index 54166688efff..4e3944c68bc8 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -313,6 +313,12 @@ static void __init lsm_prep_single(struct lsm_info *lsm)
 	lsm_blob_size_update(&blobs->lbs_xattr_count,
 			     &blob_sizes.lbs_xattr_count);
 	lsm_blob_size_update(&blobs->lbs_bdev, &blob_sizes.lbs_bdev);
+	if (blobs->lbs_secmark) {
+		if (blob_sizes.lbs_secmark)
+			blobs->lbs_secmark = false;
+		else
+			blob_sizes.lbs_secmark = true;
+	}
 }
 
 /**
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 9f816e25198a..18ab1f13f3f9 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -165,7 +165,8 @@ __setup("checkreqprot=", checkreqprot_setup);
  */
 static int selinux_secmark_enabled(void)
 {
-	return (selinux_policycap_alwaysnetwork() ||
+	return selinux_blob_sizes.lbs_secmark &&
+	       (selinux_policycap_alwaysnetwork() ||
 		atomic_read(&selinux_secmark_refcount));
 }
 
@@ -7160,6 +7161,7 @@ struct lsm_blob_sizes selinux_blob_sizes __ro_after_init = {
 	.lbs_xattr_count = SELINUX_INODE_INIT_XATTRS,
 	.lbs_tun_dev = sizeof(struct tun_security_struct),
 	.lbs_ib = sizeof(struct ib_security_struct),
+	.lbs_secmark = true,
 };
 
 #ifdef CONFIG_PERF_EVENTS
diff --git a/security/smack/smack.h b/security/smack/smack.h
index 709e0d6cd5e1..2f7b8d79b69f 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -389,6 +389,11 @@ static inline int smk_inode_transmutable(const struct inode *isp)
 	return (sip->smk_flags & SMK_INODE_TRANSMUTE) != 0;
 }
 
+static inline bool smack_secmark(void)
+{
+	return smack_blob_sizes.lbs_secmark;
+}
+
 /*
  * Present a pointer to the smack label entry in an inode blob.
  */
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index d363adead435..c8c173bb9cc3 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -4102,7 +4102,7 @@ static int smk_skb_to_addr_ipv6(struct sk_buff *skb, struct sockaddr_in6 *sip)
 #ifdef CONFIG_NETWORK_SECMARK
 static struct smack_known *smack_from_skb(struct sk_buff *skb)
 {
-	if (skb == NULL || skb->secmark == 0)
+	if (!smack_secmark() || skb == NULL || skb->secmark == 0)
 		return NULL;
 
 	return smack_from_secid(skb->secmark);
@@ -5030,6 +5030,7 @@ struct lsm_blob_sizes smack_blob_sizes __ro_after_init = {
 	.lbs_sock = sizeof(struct socket_smack),
 	.lbs_superblock = sizeof(struct superblock_smack),
 	.lbs_xattr_count = SMACK_INODE_INIT_XATTRS,
+	.lbs_secmark = true,
 };
 
 static const struct lsm_id smack_lsmid = {
diff --git a/security/smack/smack_netfilter.c b/security/smack/smack_netfilter.c
index 17ba578b1308..1dcaba0d224a 100644
--- a/security/smack/smack_netfilter.c
+++ b/security/smack/smack_netfilter.c
@@ -26,7 +26,7 @@ static unsigned int smack_ip_output(void *priv,
 	struct socket_smack *ssp;
 	struct smack_known *skp;
 
-	if (sk) {
+	if (smack_secmark() && sk) {
 		ssp = smack_sock(sk);
 		skp = ssp->smk_out;
 		skb->secmark = skp->smk_secid;
@@ -54,12 +54,18 @@ static const struct nf_hook_ops smack_nf_ops[] = {
 
 static int __net_init smack_nf_register(struct net *net)
 {
+	if (!smack_secmark())
+		return 0;
+
 	return nf_register_net_hooks(net, smack_nf_ops,
 				     ARRAY_SIZE(smack_nf_ops));
 }
 
 static void __net_exit smack_nf_unregister(struct net *net)
 {
+	if (!smack_secmark())
+		return;
+
 	nf_unregister_net_hooks(net, smack_nf_ops, ARRAY_SIZE(smack_nf_ops));
 }
 
@@ -70,7 +76,7 @@ static struct pernet_operations smack_net_ops = {
 
 int __init smack_nf_ip_init(void)
 {
-	if (smack_enabled == 0)
+	if (smack_enabled == 0 || !smack_secmark())
 		return 0;
 
 	printk(KERN_DEBUG "Smack: Registering netfilter hooks\n");
-- 
2.47.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [RFC PATCH 07/15] Audit: Call only the first of the audit rule hooks
  2025-06-21 17:18 ` [RFC PATCH 00/15] LSM: No exclusive LSMs Casey Schaufler
                     ` (5 preceding siblings ...)
  2025-06-21 17:18   ` [RFC PATCH 06/15] LSM: Exclusive secmark usage Casey Schaufler
@ 2025-06-21 17:18   ` Casey Schaufler
  2025-10-14 23:12     ` [PATCH RFC 7/15] " Paul Moore
  2025-06-21 17:18   ` [RFC PATCH 08/15] AppArmor: Remove the exclusive flag Casey Schaufler
                     ` (7 subsequent siblings)
  14 siblings, 1 reply; 31+ messages in thread
From: Casey Schaufler @ 2025-06-21 17:18 UTC (permalink / raw)
  To: casey, paul, eparis, linux-security-module, audit
  Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
	stephen.smalley.work, linux-kernel, selinux

The audit system is not (yet) capable for distinguishing
between audit rules specified for multiple security modules.
Call only the first registered of the audit rule hooks.
The order of registration, which can be specified with the
lsm= boot parameter, is hence an important consideration.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
 security/security.c | 30 ++++++++++++++++++++++++++----
 1 file changed, 26 insertions(+), 4 deletions(-)

diff --git a/security/security.c b/security/security.c
index 2286285f8aea..93d4ac39fe9f 100644
--- a/security/security.c
+++ b/security/security.c
@@ -5056,7 +5056,13 @@ void security_key_post_create_or_update(struct key *keyring, struct key *key,
 int security_audit_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule,
 			     gfp_t gfp)
 {
-	return call_int_hook(audit_rule_init, field, op, rulestr, lsmrule, gfp);
+	struct lsm_static_call *scall;
+
+	lsm_for_each_hook(scall, audit_rule_init) {
+		return scall->hl->hook.audit_rule_init(field, op, rulestr,
+						       lsmrule, gfp);
+	}
+	return LSM_RET_DEFAULT(audit_rule_init);
 }
 
 /**
@@ -5070,7 +5076,12 @@ int security_audit_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule,
  */
 int security_audit_rule_known(struct audit_krule *krule)
 {
-	return call_int_hook(audit_rule_known, krule);
+	struct lsm_static_call *scall;
+
+	lsm_for_each_hook(scall, audit_rule_known) {
+		return scall->hl->hook.audit_rule_known(krule);
+	}
+	return LSM_RET_DEFAULT(audit_rule_known);
 }
 
 /**
@@ -5082,7 +5093,12 @@ int security_audit_rule_known(struct audit_krule *krule)
  */
 void security_audit_rule_free(void *lsmrule)
 {
-	call_void_hook(audit_rule_free, lsmrule);
+	struct lsm_static_call *scall;
+
+	lsm_for_each_hook(scall, audit_rule_free) {
+		scall->hl->hook.audit_rule_free(lsmrule);
+		return;
+	}
 }
 
 /**
@@ -5101,7 +5117,13 @@ void security_audit_rule_free(void *lsmrule)
 int security_audit_rule_match(struct lsm_prop *prop, u32 field, u32 op,
 			      void *lsmrule)
 {
-	return call_int_hook(audit_rule_match, prop, field, op, lsmrule);
+	struct lsm_static_call *scall;
+
+	lsm_for_each_hook(scall, audit_rule_match) {
+		return scall->hl->hook.audit_rule_match(prop, field, op,
+							lsmrule);
+	}
+	return LSM_RET_DEFAULT(audit_rule_match);
 }
 #endif /* CONFIG_AUDIT */
 
-- 
2.47.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [RFC PATCH 08/15] AppArmor: Remove the exclusive flag
  2025-06-21 17:18 ` [RFC PATCH 00/15] LSM: No exclusive LSMs Casey Schaufler
                     ` (6 preceding siblings ...)
  2025-06-21 17:18   ` [RFC PATCH 07/15] Audit: Call only the first of the audit rule hooks Casey Schaufler
@ 2025-06-21 17:18   ` Casey Schaufler
  2025-06-21 17:18   ` [RFC PATCH 09/15] LSM: Add mount opts blob size tracking Casey Schaufler
                     ` (6 subsequent siblings)
  14 siblings, 0 replies; 31+ messages in thread
From: Casey Schaufler @ 2025-06-21 17:18 UTC (permalink / raw)
  To: casey, paul, eparis, linux-security-module, audit
  Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
	stephen.smalley.work, linux-kernel, selinux

With the preceeding audit changes AppArmor no longer needs
to be treated as an "exclusive" security module. Remove the
flag that indicates it is exclusive.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
 security/apparmor/lsm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 255d2e40386f..ac38864d9bce 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -2278,7 +2278,7 @@ static int __init apparmor_init(void)
 
 DEFINE_LSM(apparmor) = {
 	.id = &apparmor_lsmid,
-	.flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
+	.flags = LSM_FLAG_LEGACY_MAJOR,
 	.enabled = &apparmor_enabled,
 	.blobs = &apparmor_blob_sizes,
 	.init = apparmor_init,
-- 
2.47.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [RFC PATCH 09/15] LSM: Add mount opts blob size tracking
  2025-06-21 17:18 ` [RFC PATCH 00/15] LSM: No exclusive LSMs Casey Schaufler
                     ` (7 preceding siblings ...)
  2025-06-21 17:18   ` [RFC PATCH 08/15] AppArmor: Remove the exclusive flag Casey Schaufler
@ 2025-06-21 17:18   ` Casey Schaufler
  2025-10-14 23:12     ` [PATCH RFC 9/15] " Paul Moore
  2025-06-21 17:18   ` [RFC PATCH 10/15] LSM: allocate mnt_opts blobs instead of module specific data Casey Schaufler
                     ` (5 subsequent siblings)
  14 siblings, 1 reply; 31+ messages in thread
From: Casey Schaufler @ 2025-06-21 17:18 UTC (permalink / raw)
  To: casey, paul, eparis, linux-security-module, audit
  Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
	stephen.smalley.work, linux-kernel, selinux

Add mount option data to the blob size accounting in anticipation
of using a shared mnt_opts blob.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
 include/linux/lsm_hooks.h  | 1 +
 security/lsm_init.c        | 2 ++
 security/selinux/hooks.c   | 1 +
 security/smack/smack_lsm.c | 1 +
 4 files changed, 5 insertions(+)

diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 1ad9f8a86b10..2e3b1559714c 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -122,6 +122,7 @@ struct lsm_blob_sizes {
 	unsigned int lbs_xattr_count; /* num xattr slots in new_xattrs array */
 	unsigned int lbs_tun_dev;
 	unsigned int lbs_bdev;
+	unsigned int lbs_mnt_opts;
 	bool lbs_secmark; /* expressed desire for secmark use */
 };
 
diff --git a/security/lsm_init.c b/security/lsm_init.c
index 4e3944c68bc8..d27a457627ed 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -313,6 +313,7 @@ static void __init lsm_prep_single(struct lsm_info *lsm)
 	lsm_blob_size_update(&blobs->lbs_xattr_count,
 			     &blob_sizes.lbs_xattr_count);
 	lsm_blob_size_update(&blobs->lbs_bdev, &blob_sizes.lbs_bdev);
+	lsm_blob_size_update(&blobs->lbs_mnt_opts, &blob_sizes.lbs_mnt_opts);
 	if (blobs->lbs_secmark) {
 		if (blob_sizes.lbs_secmark)
 			blobs->lbs_secmark = false;
@@ -460,6 +461,7 @@ int __init security_init(void)
 		lsm_pr("blob(tun_dev) size %d\n", blob_sizes.lbs_tun_dev);
 		lsm_pr("blob(xattr) count %d\n", blob_sizes.lbs_xattr_count);
 		lsm_pr("blob(bdev) size %d\n", blob_sizes.lbs_bdev);
+		lsm_pr("blob(mnt_opts) size %d\n", blob_sizes.lbs_mnt_opts);
 	}
 
 	if (blob_sizes.lbs_file)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 18ab1f13f3f9..c86b430f34c3 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -7161,6 +7161,7 @@ struct lsm_blob_sizes selinux_blob_sizes __ro_after_init = {
 	.lbs_xattr_count = SELINUX_INODE_INIT_XATTRS,
 	.lbs_tun_dev = sizeof(struct tun_security_struct),
 	.lbs_ib = sizeof(struct ib_security_struct),
+	.lbs_mnt_opts = sizeof(struct selinux_mnt_opts),
 	.lbs_secmark = true,
 };
 
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index c8c173bb9cc3..956dce6b1e97 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -5030,6 +5030,7 @@ struct lsm_blob_sizes smack_blob_sizes __ro_after_init = {
 	.lbs_sock = sizeof(struct socket_smack),
 	.lbs_superblock = sizeof(struct superblock_smack),
 	.lbs_xattr_count = SMACK_INODE_INIT_XATTRS,
+	.lbs_mnt_opts = sizeof(struct smack_mnt_opts),
 	.lbs_secmark = true,
 };
 
-- 
2.47.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [RFC PATCH 10/15] LSM: allocate mnt_opts blobs instead of module specific data
  2025-06-21 17:18 ` [RFC PATCH 00/15] LSM: No exclusive LSMs Casey Schaufler
                     ` (8 preceding siblings ...)
  2025-06-21 17:18   ` [RFC PATCH 09/15] LSM: Add mount opts blob size tracking Casey Schaufler
@ 2025-06-21 17:18   ` Casey Schaufler
  2025-10-14 23:12     ` [PATCH RFC " Paul Moore
  2025-06-21 17:18   ` [RFC PATCH 11/15] LSM: Infrastructure management of the mnt_opts security blob Casey Schaufler
                     ` (4 subsequent siblings)
  14 siblings, 1 reply; 31+ messages in thread
From: Casey Schaufler @ 2025-06-21 17:18 UTC (permalink / raw)
  To: casey, paul, eparis, linux-security-module, audit
  Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
	stephen.smalley.work, linux-kernel, selinux

Replace allocations of LSM specific mount data with the
shared mnt_opts blob.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
 include/linux/lsm_hooks.h  |  1 +
 security/security.c        | 12 ++++++++++++
 security/selinux/hooks.c   | 10 +++++++---
 security/smack/smack_lsm.c |  4 ++--
 4 files changed, 22 insertions(+), 5 deletions(-)

diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 2e3b1559714c..38f89762c0df 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -220,4 +220,5 @@ static inline struct xattr *lsm_get_xattr_slot(struct xattr *xattrs,
 	return &xattrs[(*xattr_count)++];
 }
 
+extern void *lsm_mnt_opts_alloc(gfp_t priority);
 #endif /* ! __LINUX_LSM_HOOKS_H */
diff --git a/security/security.c b/security/security.c
index 93d4ac39fe9f..98a80078b2df 100644
--- a/security/security.c
+++ b/security/security.c
@@ -901,6 +901,18 @@ void security_sb_free(struct super_block *sb)
 	sb->s_security = NULL;
 }
 
+/**
+ * lsm_mnt_opts_alloc - allocate a mnt_opts blob
+ * @priority: memory allocation priority
+ *
+ * Returns a newly allocated mnt_opts blob or NULL if
+ * memory isn't available.
+ */
+void *lsm_mnt_opts_alloc(gfp_t priority)
+{
+	return kzalloc(blob_sizes.lbs_mnt_opts, priority);
+}
+
 /**
  * security_free_mnt_opts() - Free memory associated with mount options
  * @mnt_opts: LSM processed mount options
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index c86b430f34c3..8e0671920e3a 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2809,7 +2809,7 @@ static int selinux_fs_context_submount(struct fs_context *fc,
 	if (!(sbsec->flags & (FSCONTEXT_MNT|CONTEXT_MNT|DEFCONTEXT_MNT)))
 		return 0;
 
-	opts = kzalloc(sizeof(*opts), GFP_KERNEL);
+	opts = lsm_mnt_opts_alloc(GFP_KERNEL);
 	if (!opts)
 		return -ENOMEM;
 
@@ -2831,8 +2831,12 @@ static int selinux_fs_context_dup(struct fs_context *fc,
 	if (!src)
 		return 0;
 
-	fc->security = kmemdup(src, sizeof(*src), GFP_KERNEL);
-	return fc->security ? 0 : -ENOMEM;
+	fc->security = lsm_mnt_opts_alloc(GFP_KERNEL);
+	if (!fc->security)
+		return -ENOMEM;
+
+	memcpy(fc->security, src, sizeof(*src));
+	return 0;
 }
 
 static const struct fs_parameter_spec selinux_fs_parameters[] = {
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 956dce6b1e97..0cc24b57bb52 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -622,7 +622,7 @@ static int smack_fs_context_submount(struct fs_context *fc,
 	struct smack_mnt_opts *ctx;
 	struct inode_smack *isp;
 
-	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	ctx = lsm_mnt_opts_alloc(GFP_KERNEL);
 	if (!ctx)
 		return -ENOMEM;
 	fc->security = ctx;
@@ -673,7 +673,7 @@ static int smack_fs_context_dup(struct fs_context *fc,
 	if (!src)
 		return 0;
 
-	fc->security = kzalloc(sizeof(struct smack_mnt_opts), GFP_KERNEL);
+	fc->security = lsm_mnt_opts_alloc(GFP_KERNEL);
 	if (!fc->security)
 		return -ENOMEM;
 
-- 
2.47.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [RFC PATCH 11/15] LSM: Infrastructure management of the mnt_opts security blob
  2025-06-21 17:18 ` [RFC PATCH 00/15] LSM: No exclusive LSMs Casey Schaufler
                     ` (9 preceding siblings ...)
  2025-06-21 17:18   ` [RFC PATCH 10/15] LSM: allocate mnt_opts blobs instead of module specific data Casey Schaufler
@ 2025-06-21 17:18   ` Casey Schaufler
  2025-10-14 23:12     ` [PATCH RFC " Paul Moore
  2025-06-21 17:18   ` [RFC PATCH 12/15] LSM: Allow reservation of netlabel Casey Schaufler
                     ` (3 subsequent siblings)
  14 siblings, 1 reply; 31+ messages in thread
From: Casey Schaufler @ 2025-06-21 17:18 UTC (permalink / raw)
  To: casey, paul, eparis, linux-security-module, audit
  Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
	stephen.smalley.work, linux-kernel, selinux

Move management of the mnt_opts->security blob out of the
individual security modules and into the security
infrastructure. Blobs are still allocated within the modules
as they are only required when mount options are present.
The modules tell the infrastructure how much space is required,
and the space is allocated if needed. Modules can no longer
count on the presence of a blob implying that mount options
specific to that module are present, so flags are added
to the module specific blobs to indicate that this module
has options.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
 security/security.c        | 14 ++++-----
 security/selinux/hooks.c   | 58 +++++++++++++++++++++++-------------
 security/smack/smack_lsm.c | 61 ++++++++++++++++++++++++++------------
 3 files changed, 85 insertions(+), 48 deletions(-)

diff --git a/security/security.c b/security/security.c
index 98a80078b2df..dd167a872248 100644
--- a/security/security.c
+++ b/security/security.c
@@ -840,17 +840,14 @@ int security_fs_context_parse_param(struct fs_context *fc,
 				    struct fs_parameter *param)
 {
 	struct lsm_static_call *scall;
-	int trc;
-	int rc = -ENOPARAM;
+	int rc;
 
 	lsm_for_each_hook(scall, fs_context_parse_param) {
-		trc = scall->hl->hook.fs_context_parse_param(fc, param);
-		if (trc == 0)
-			rc = 0;
-		else if (trc != -ENOPARAM)
-			return trc;
+		rc = scall->hl->hook.fs_context_parse_param(fc, param);
+		if (rc != -ENOPARAM)
+			return rc;
 	}
-	return rc;
+	return -ENOPARAM;
 }
 
 /**
@@ -924,6 +921,7 @@ void security_free_mnt_opts(void **mnt_opts)
 	if (!*mnt_opts)
 		return;
 	call_void_hook(sb_free_mnt_opts, *mnt_opts);
+	kfree(*mnt_opts);
 	*mnt_opts = NULL;
 }
 EXPORT_SYMBOL(security_free_mnt_opts);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 8e0671920e3a..636a38449253 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -379,15 +379,28 @@ static void inode_free_security(struct inode *inode)
 }
 
 struct selinux_mnt_opts {
+	bool initialized;
 	u32 fscontext_sid;
 	u32 context_sid;
 	u32 rootcontext_sid;
 	u32 defcontext_sid;
 };
 
+static inline struct selinux_mnt_opts *selinux_mnt_opts(void *mnt_opts)
+{
+	if (mnt_opts)
+		return mnt_opts + selinux_blob_sizes.lbs_mnt_opts;
+	return NULL;
+}
+
 static void selinux_free_mnt_opts(void *mnt_opts)
 {
-	kfree(mnt_opts);
+	struct selinux_mnt_opts *opts;
+
+	if (mnt_opts) {
+		opts = selinux_mnt_opts(mnt_opts);
+		opts->initialized = false;
+	}
 }
 
 enum {
@@ -642,7 +655,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
 	const struct cred *cred = current_cred();
 	struct superblock_security_struct *sbsec = selinux_superblock(sb);
 	struct dentry *root = sb->s_root;
-	struct selinux_mnt_opts *opts = mnt_opts;
+	struct selinux_mnt_opts *opts = selinux_mnt_opts(mnt_opts);
 	struct inode_security_struct *root_isec;
 	u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
 	u32 defcontext_sid = 0;
@@ -658,7 +671,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
 	mutex_lock(&sbsec->lock);
 
 	if (!selinux_initialized()) {
-		if (!opts) {
+		if (!opts || !opts->initialized) {
 			/* Defer initialization until selinux_complete_init,
 			   after the initial policy is loaded and the security
 			   server is ready to handle calls. */
@@ -696,7 +709,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
 	 * also check if someone is trying to mount the same sb more
 	 * than once with different security options.
 	 */
-	if (opts) {
+	if (opts && opts->initialized) {
 		if (opts->fscontext_sid) {
 			fscontext_sid = opts->fscontext_sid;
 			if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
@@ -1005,7 +1018,7 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
  */
 static int selinux_add_opt(int token, const char *s, void **mnt_opts)
 {
-	struct selinux_mnt_opts *opts = *mnt_opts;
+	struct selinux_mnt_opts *opts;
 	u32 *dst_sid;
 	int rc;
 
@@ -1020,12 +1033,12 @@ static int selinux_add_opt(int token, const char *s, void **mnt_opts)
 		return -EINVAL;
 	}
 
-	if (!opts) {
-		opts = kzalloc(sizeof(*opts), GFP_KERNEL);
-		if (!opts)
+	if (!*mnt_opts) {
+		*mnt_opts = lsm_mnt_opts_alloc(GFP_KERNEL);
+		if (!*mnt_opts)
 			return -ENOMEM;
-		*mnt_opts = opts;
 	}
+	opts = selinux_mnt_opts(*mnt_opts);
 
 	switch (token) {
 	case Opt_context:
@@ -1052,6 +1065,7 @@ static int selinux_add_opt(int token, const char *s, void **mnt_opts)
 		WARN_ON(1);
 		return -EINVAL;
 	}
+	opts->initialized = true;
 	rc = security_context_str_to_sid(s, dst_sid, GFP_KERNEL);
 	if (rc)
 		pr_warn("SELinux: security_context_str_to_sid (%s) failed with errno=%d\n",
@@ -2651,10 +2665,7 @@ static int selinux_sb_eat_lsm_opts(char *options, void **mnt_opts)
 	return 0;
 
 free_opt:
-	if (*mnt_opts) {
-		selinux_free_mnt_opts(*mnt_opts);
-		*mnt_opts = NULL;
-	}
+	selinux_free_mnt_opts(*mnt_opts);
 	return rc;
 }
 
@@ -2705,13 +2716,13 @@ static int selinux_sb_mnt_opts_compat(struct super_block *sb, void *mnt_opts)
 
 static int selinux_sb_remount(struct super_block *sb, void *mnt_opts)
 {
-	struct selinux_mnt_opts *opts = mnt_opts;
+	struct selinux_mnt_opts *opts = selinux_mnt_opts(mnt_opts);
 	struct superblock_security_struct *sbsec = selinux_superblock(sb);
 
 	if (!(sbsec->flags & SE_SBINITIALIZED))
 		return 0;
 
-	if (!opts)
+	if (!opts || !opts->initialized)
 		return 0;
 
 	if (opts->fscontext_sid) {
@@ -2809,9 +2820,13 @@ static int selinux_fs_context_submount(struct fs_context *fc,
 	if (!(sbsec->flags & (FSCONTEXT_MNT|CONTEXT_MNT|DEFCONTEXT_MNT)))
 		return 0;
 
-	opts = lsm_mnt_opts_alloc(GFP_KERNEL);
-	if (!opts)
-		return -ENOMEM;
+	if (!fc->security) {
+		fc->security = lsm_mnt_opts_alloc(GFP_KERNEL);
+		if (!fc->security)
+			return -ENOMEM;
+	}
+	opts = selinux_mnt_opts(fc->security);
+	opts->initialized = true;
 
 	if (sbsec->flags & FSCONTEXT_MNT)
 		opts->fscontext_sid = sbsec->sid;
@@ -2819,14 +2834,14 @@ static int selinux_fs_context_submount(struct fs_context *fc,
 		opts->context_sid = sbsec->mntpoint_sid;
 	if (sbsec->flags & DEFCONTEXT_MNT)
 		opts->defcontext_sid = sbsec->def_sid;
-	fc->security = opts;
 	return 0;
 }
 
 static int selinux_fs_context_dup(struct fs_context *fc,
 				  struct fs_context *src_fc)
 {
-	const struct selinux_mnt_opts *src = src_fc->security;
+	const struct selinux_mnt_opts *src = selinux_mnt_opts(src_fc->security);
+	struct selinux_mnt_opts *dst;
 
 	if (!src)
 		return 0;
@@ -2835,7 +2850,8 @@ static int selinux_fs_context_dup(struct fs_context *fc,
 	if (!fc->security)
 		return -ENOMEM;
 
-	memcpy(fc->security, src, sizeof(*src));
+	dst = selinux_mnt_opts(fc->security);
+	memcpy(dst, src, sizeof(*src));
 	return 0;
 }
 
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 0cc24b57bb52..ced66130fb7d 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -544,6 +544,7 @@ static int smack_sb_alloc_security(struct super_block *sb)
 }
 
 struct smack_mnt_opts {
+	bool initialized;
 	const char *fsdefault;
 	const char *fsfloor;
 	const char *fshat;
@@ -551,24 +552,37 @@ struct smack_mnt_opts {
 	const char *fstransmute;
 };
 
+static inline struct smack_mnt_opts *smack_mnt_opts(void *mnt_opts)
+{
+	if (mnt_opts)
+		return mnt_opts + smack_blob_sizes.lbs_mnt_opts;
+	return NULL;
+}
+
 static void smack_free_mnt_opts(void *mnt_opts)
 {
-	kfree(mnt_opts);
+	struct smack_mnt_opts *opts;
+
+	if (mnt_opts) {
+		opts = smack_mnt_opts(mnt_opts);
+		opts->initialized = false;
+	}
 }
 
 static int smack_add_opt(int token, const char *s, void **mnt_opts)
 {
-	struct smack_mnt_opts *opts = *mnt_opts;
+	struct smack_mnt_opts *opts;
 	struct smack_known *skp;
 
-	if (!opts) {
-		opts = kzalloc(sizeof(struct smack_mnt_opts), GFP_KERNEL);
-		if (!opts)
+	if (!s)
+		return -EINVAL;
+
+	if (!*mnt_opts) {
+		*mnt_opts = lsm_mnt_opts_alloc(GFP_KERNEL);
+		if (!*mnt_opts)
 			return -ENOMEM;
-		*mnt_opts = opts;
 	}
-	if (!s)
-		return -ENOMEM;
+	opts = smack_mnt_opts(*mnt_opts);
 
 	skp = smk_import_entry(s, 0);
 	if (IS_ERR(skp))
@@ -601,6 +615,7 @@ static int smack_add_opt(int token, const char *s, void **mnt_opts)
 		opts->fstransmute = skp->smk_known;
 		break;
 	}
+	opts->initialized = true;
 	return 0;
 
 out_opt_err:
@@ -622,10 +637,12 @@ static int smack_fs_context_submount(struct fs_context *fc,
 	struct smack_mnt_opts *ctx;
 	struct inode_smack *isp;
 
-	ctx = lsm_mnt_opts_alloc(GFP_KERNEL);
-	if (!ctx)
-		return -ENOMEM;
-	fc->security = ctx;
+	if (!fc->security) {
+		fc->security = lsm_mnt_opts_alloc(GFP_KERNEL);
+		if (!fc->security)
+			return -ENOMEM;
+	}
+	ctx = smack_mnt_opts(fc->security);
 
 	sbsp = smack_superblock(reference);
 	isp = smack_inode(reference->s_root->d_inode);
@@ -655,6 +672,7 @@ static int smack_fs_context_submount(struct fs_context *fc,
 				return -ENOMEM;
 		}
 	}
+	ctx->initialized = true;
 	return 0;
 }
 
@@ -668,16 +686,21 @@ static int smack_fs_context_submount(struct fs_context *fc,
 static int smack_fs_context_dup(struct fs_context *fc,
 				struct fs_context *src_fc)
 {
-	struct smack_mnt_opts *dst, *src = src_fc->security;
+	struct smack_mnt_opts *src;
+	struct smack_mnt_opts *dst;
 
+	src = smack_mnt_opts(src_fc->security);
 	if (!src)
 		return 0;
 
-	fc->security = lsm_mnt_opts_alloc(GFP_KERNEL);
-	if (!fc->security)
-		return -ENOMEM;
+	if (!fc->security) {
+		fc->security = lsm_mnt_opts_alloc(GFP_KERNEL);
+		if (!fc->security)
+			return -ENOMEM;
+	}
 
-	dst = fc->security;
+	dst = smack_mnt_opts(fc->security);
+	dst->initialized = src->initialized;
 	dst->fsdefault = src->fsdefault;
 	dst->fsfloor = src->fsfloor;
 	dst->fshat = src->fshat;
@@ -787,7 +810,7 @@ static int smack_set_mnt_opts(struct super_block *sb,
 	struct superblock_smack *sp = smack_superblock(sb);
 	struct inode_smack *isp;
 	struct smack_known *skp;
-	struct smack_mnt_opts *opts = mnt_opts;
+	struct smack_mnt_opts *opts = smack_mnt_opts(mnt_opts);
 	bool transmute = false;
 
 	if (sp->smk_flags & SMK_SB_INITIALIZED)
@@ -820,7 +843,7 @@ static int smack_set_mnt_opts(struct super_block *sb,
 
 	sp->smk_flags |= SMK_SB_INITIALIZED;
 
-	if (opts) {
+	if (opts && opts->initialized) {
 		if (opts->fsdefault) {
 			skp = smk_import_entry(opts->fsdefault, 0);
 			if (IS_ERR(skp))
-- 
2.47.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [RFC PATCH 12/15] LSM: Allow reservation of netlabel
  2025-06-21 17:18 ` [RFC PATCH 00/15] LSM: No exclusive LSMs Casey Schaufler
                     ` (10 preceding siblings ...)
  2025-06-21 17:18   ` [RFC PATCH 11/15] LSM: Infrastructure management of the mnt_opts security blob Casey Schaufler
@ 2025-06-21 17:18   ` Casey Schaufler
  2025-10-14 23:12     ` [PATCH RFC " Paul Moore
  2025-06-21 17:18   ` [RFC PATCH 13/15] LSM: restrict security_cred_getsecid() to a single LSM Casey Schaufler
                     ` (2 subsequent siblings)
  14 siblings, 1 reply; 31+ messages in thread
From: Casey Schaufler @ 2025-06-21 17:18 UTC (permalink / raw)
  To: casey, paul, eparis, linux-security-module, audit
  Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
	stephen.smalley.work, linux-kernel, selinux

Allow LSMs to request exclusive access to the netlabel facility.
Provide mechanism for LSMs to determine if they have access to
netlabel. Update the current users of netlabel, SELinux and Smack,
to use and respect the exclusive use of netlabel.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
 include/linux/lsm_hooks.h           |  1 +
 security/lsm_init.c                 |  6 +++++
 security/selinux/hooks.c            |  7 +++---
 security/selinux/include/netlabel.h |  5 ++++
 security/selinux/netlabel.c         |  4 ++--
 security/smack/smack.h              |  5 ++++
 security/smack/smack_lsm.c          | 36 +++++++++++++++++++++--------
 security/smack/smackfs.c            | 20 +++++++++++++++-
 8 files changed, 69 insertions(+), 15 deletions(-)

diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 38f89762c0df..06e840fd4b63 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -124,6 +124,7 @@ struct lsm_blob_sizes {
 	unsigned int lbs_bdev;
 	unsigned int lbs_mnt_opts;
 	bool lbs_secmark; /* expressed desire for secmark use */
+	bool lbs_netlabel; /* expressed desire for netlabel use */
 };
 
 /*
diff --git a/security/lsm_init.c b/security/lsm_init.c
index d27a457627ed..784f8296966f 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -320,6 +320,12 @@ static void __init lsm_prep_single(struct lsm_info *lsm)
 		else
 			blob_sizes.lbs_secmark = true;
 	}
+	if (blobs->lbs_netlabel) {
+		if (blob_sizes.lbs_netlabel)
+			blobs->lbs_netlabel = false;
+		else
+			blob_sizes.lbs_netlabel = true;
+	}
 }
 
 /**
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 636a38449253..9578b63bbd2a 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -183,7 +183,7 @@ static int selinux_secmark_enabled(void)
 static int selinux_peerlbl_enabled(void)
 {
 	return (selinux_policycap_alwaysnetwork() ||
-		netlbl_enabled() || selinux_xfrm_enabled());
+		selinux_netlbl_enabled() || selinux_xfrm_enabled());
 }
 
 static int selinux_netcache_avc_callback(u32 event)
@@ -5860,7 +5860,7 @@ static unsigned int selinux_ip_forward(void *priv, struct sk_buff *skb,
 				 SECCLASS_PACKET, PACKET__FORWARD_IN, &ad))
 			return NF_DROP;
 
-	if (netlbl_enabled())
+	if (selinux_netlbl_enabled())
 		/* we do this in the FORWARD path and not the POST_ROUTING
 		 * path because we want to make sure we apply the necessary
 		 * labeling before IPsec is applied so we can leverage AH
@@ -5877,7 +5877,7 @@ static unsigned int selinux_ip_output(void *priv, struct sk_buff *skb,
 	struct sock *sk;
 	u32 sid;
 
-	if (!netlbl_enabled())
+	if (!selinux_netlbl_enabled())
 		return NF_ACCEPT;
 
 	/* we do this in the LOCAL_OUT path and not the POST_ROUTING path
@@ -7183,6 +7183,7 @@ struct lsm_blob_sizes selinux_blob_sizes __ro_after_init = {
 	.lbs_ib = sizeof(struct ib_security_struct),
 	.lbs_mnt_opts = sizeof(struct selinux_mnt_opts),
 	.lbs_secmark = true,
+	.lbs_netlabel = true,
 };
 
 #ifdef CONFIG_PERF_EVENTS
diff --git a/security/selinux/include/netlabel.h b/security/selinux/include/netlabel.h
index 5731c0dcd3e8..5be82aa8e7ca 100644
--- a/security/selinux/include/netlabel.h
+++ b/security/selinux/include/netlabel.h
@@ -134,4 +134,9 @@ static inline int selinux_netlbl_socket_connect_locked(struct sock *sk,
 }
 #endif /* CONFIG_NETLABEL */
 
+static inline bool selinux_netlbl_enabled(void)
+{
+	return selinux_blob_sizes.lbs_netlabel && netlbl_enabled();
+}
+
 #endif
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c
index d51dfe892312..a6c58b8e7bfd 100644
--- a/security/selinux/netlabel.c
+++ b/security/selinux/netlabel.c
@@ -199,7 +199,7 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
 	int rc;
 	struct netlbl_lsm_secattr secattr;
 
-	if (!netlbl_enabled()) {
+	if (!selinux_netlbl_enabled()) {
 		*type = NETLBL_NLTYPE_NONE;
 		*sid = SECSID_NULL;
 		return 0;
@@ -444,7 +444,7 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
 	u32 perm;
 	struct netlbl_lsm_secattr secattr;
 
-	if (!netlbl_enabled())
+	if (!selinux_netlbl_enabled())
 		return 0;
 
 	netlbl_secattr_init(&secattr);
diff --git a/security/smack/smack.h b/security/smack/smack.h
index 2f7b8d79b69f..de707d481e39 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -380,6 +380,11 @@ static inline struct smack_known **smack_key(const struct key *key)
 }
 #endif /* CONFIG_KEYS */
 
+static inline bool smack_netlabel(void)
+{
+	return smack_blob_sizes.lbs_netlabel;
+}
+
 /*
  * Is the directory transmuting?
  */
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index ced66130fb7d..650f2700160f 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -2598,6 +2598,9 @@ static int smack_netlbl_add(struct sock *sk)
 	struct smack_known *skp = ssp->smk_out;
 	int rc;
 
+	if (!smack_netlabel())
+		return 0;
+
 	local_bh_disable();
 	bh_lock_sock_nested(sk);
 
@@ -2629,6 +2632,9 @@ static void smack_netlbl_delete(struct sock *sk)
 {
 	struct socket_smack *ssp = smack_sock(sk);
 
+	if (!smack_netlabel())
+		return;
+
 	/*
 	 * Take the label off the socket if one is set.
 	 */
@@ -2679,7 +2685,7 @@ static int smk_ipv4_check(struct sock *sk, struct sockaddr_in *sap)
 		/*
 		 * Clear the socket netlabel if it's set.
 		 */
-		if (!rc)
+		if (!rc && smack_netlabel())
 			smack_netlbl_delete(sk);
 	}
 	rcu_read_unlock();
@@ -4005,6 +4011,8 @@ static struct smack_known *smack_from_secattr(struct netlbl_lsm_secattr *sap,
 	int acat;
 	int kcat;
 
+	if (!smack_netlabel())
+		return smack_net_ambient;
 	/*
 	 * Netlabel found it in the cache.
 	 */
@@ -4155,6 +4163,9 @@ static struct smack_known *smack_from_netlbl(const struct sock *sk, u16 family,
 	struct socket_smack *ssp = NULL;
 	struct smack_known *skp = NULL;
 
+	if (!smack_netlabel())
+		return NULL;
+
 	netlbl_secattr_init(&secattr);
 
 	if (sk)
@@ -4225,7 +4236,7 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
 		rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad);
 		rc = smk_bu_note("IPv4 delivery", skp, ssp->smk_in,
 					MAY_WRITE, rc);
-		if (rc != 0)
+		if (rc != 0 && smack_netlabel())
 			netlbl_skbuff_err(skb, family, rc, 0);
 		break;
 #if IS_ENABLED(CONFIG_IPV6)
@@ -4413,7 +4424,7 @@ static int smack_inet_conn_request(const struct sock *sk, struct sk_buff *skb,
 	if (skp == NULL) {
 		skp = smack_from_netlbl(sk, family, skb);
 		if (skp == NULL)
-			skp = &smack_known_huh;
+			skp = smack_net_ambient;
 	}
 
 #ifdef CONFIG_AUDIT
@@ -4434,8 +4445,11 @@ static int smack_inet_conn_request(const struct sock *sk, struct sk_buff *skb,
 	/*
 	 * Save the peer's label in the request_sock so we can later setup
 	 * smk_packet in the child socket so that SO_PEERCRED can report it.
+	 *
+	 * Only do this if Smack is using netlabel.
 	 */
-	req->peer_secid = skp->smk_secid;
+	if (smack_netlabel())
+		req->peer_secid = skp->smk_secid;
 
 	/*
 	 * We need to decide if we want to label the incoming connection here
@@ -4448,10 +4462,13 @@ static int smack_inet_conn_request(const struct sock *sk, struct sk_buff *skb,
 	hskp = smack_ipv4host_label(&addr);
 	rcu_read_unlock();
 
-	if (hskp == NULL)
-		rc = netlbl_req_setattr(req, &ssp->smk_out->smk_netlabel);
-	else
-		netlbl_req_delattr(req);
+	if (smack_netlabel()) {
+		if (hskp == NULL)
+			rc = netlbl_req_setattr(req,
+						&ssp->smk_out->smk_netlabel);
+		else
+			netlbl_req_delattr(req);
+	}
 
 	return rc;
 }
@@ -4469,7 +4486,7 @@ static void smack_inet_csk_clone(struct sock *sk,
 	struct socket_smack *ssp = smack_sock(sk);
 	struct smack_known *skp;
 
-	if (req->peer_secid != 0) {
+	if (smack_netlabel() && req->peer_secid != 0) {
 		skp = smack_from_secid(req->peer_secid);
 		ssp->smk_packet = skp;
 	} else
@@ -5055,6 +5072,7 @@ struct lsm_blob_sizes smack_blob_sizes __ro_after_init = {
 	.lbs_xattr_count = SMACK_INODE_INIT_XATTRS,
 	.lbs_mnt_opts = sizeof(struct smack_mnt_opts),
 	.lbs_secmark = true,
+	.lbs_netlabel = true,
 };
 
 static const struct lsm_id smack_lsmid = {
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index 405ace6db109..2e43e9670265 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -79,7 +79,7 @@ static DEFINE_MUTEX(smk_net6addr_lock);
  * If it isn't somehow marked, use this.
  * It can be reset via smackfs/ambient
  */
-struct smack_known *smack_net_ambient;
+struct smack_known *smack_net_ambient = &smack_known_floor;
 
 /*
  * This is the level in a CIPSO header that indicates a
@@ -671,6 +671,9 @@ static void smk_cipso_doi(void)
 	struct cipso_v4_doi *doip;
 	struct netlbl_audit nai;
 
+	if (!smack_netlabel())
+		return;
+
 	smk_netlabel_audit_set(&nai);
 
 	rc = netlbl_cfg_map_del(NULL, PF_INET, NULL, NULL, &nai);
@@ -711,6 +714,9 @@ static void smk_unlbl_ambient(char *oldambient)
 	int rc;
 	struct netlbl_audit nai;
 
+	if (!smack_netlabel())
+		return;
+
 	smk_netlabel_audit_set(&nai);
 
 	if (oldambient != NULL) {
@@ -834,6 +840,8 @@ static ssize_t smk_set_cipso(struct file *file, const char __user *buf,
 	 */
 	if (!smack_privileged(CAP_MAC_ADMIN))
 		return -EPERM;
+	if (!smack_netlabel())
+		return -EINVAL;
 	if (*ppos != 0)
 		return -EINVAL;
 	if (format == SMK_FIXED24_FMT &&
@@ -1156,6 +1164,8 @@ static ssize_t smk_write_net4addr(struct file *file, const char __user *buf,
 	 */
 	if (!smack_privileged(CAP_MAC_ADMIN))
 		return -EPERM;
+	if (!smack_netlabel())
+		return -EINVAL;
 	if (*ppos != 0)
 		return -EINVAL;
 	if (count < SMK_NETLBLADDRMIN || count > PAGE_SIZE - 1)
@@ -1414,6 +1424,8 @@ static ssize_t smk_write_net6addr(struct file *file, const char __user *buf,
 	 */
 	if (!smack_privileged(CAP_MAC_ADMIN))
 		return -EPERM;
+	if (!smack_netlabel())
+		return -EINVAL;
 	if (*ppos != 0)
 		return -EINVAL;
 	if (count < SMK_NETLBLADDRMIN || count > PAGE_SIZE - 1)
@@ -1585,6 +1597,8 @@ static ssize_t smk_write_doi(struct file *file, const char __user *buf,
 
 	if (!smack_privileged(CAP_MAC_ADMIN))
 		return -EPERM;
+	if (!smack_netlabel())
+		return -EINVAL;
 
 	if (count >= sizeof(temp) || count == 0)
 		return -EINVAL;
@@ -1652,6 +1666,8 @@ static ssize_t smk_write_direct(struct file *file, const char __user *buf,
 
 	if (!smack_privileged(CAP_MAC_ADMIN))
 		return -EPERM;
+	if (!smack_netlabel())
+		return -EINVAL;
 
 	if (count >= sizeof(temp) || count == 0)
 		return -EINVAL;
@@ -1730,6 +1746,8 @@ static ssize_t smk_write_mapped(struct file *file, const char __user *buf,
 
 	if (!smack_privileged(CAP_MAC_ADMIN))
 		return -EPERM;
+	if (!smack_netlabel())
+		return -EINVAL;
 
 	if (count >= sizeof(temp) || count == 0)
 		return -EINVAL;
-- 
2.47.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [RFC PATCH 13/15] LSM: restrict security_cred_getsecid() to a single LSM
  2025-06-21 17:18 ` [RFC PATCH 00/15] LSM: No exclusive LSMs Casey Schaufler
                     ` (11 preceding siblings ...)
  2025-06-21 17:18   ` [RFC PATCH 12/15] LSM: Allow reservation of netlabel Casey Schaufler
@ 2025-06-21 17:18   ` Casey Schaufler
  2025-10-14 23:13     ` [PATCH RFC " Paul Moore
  2025-06-21 17:18   ` [RFC PATCH 14/15] Smack: Remove LSM_FLAG_EXCLUSIVE Casey Schaufler
  2025-06-21 17:18   ` [RFC PATCH 15/15] LSM: Remove exclusive LSM flag Casey Schaufler
  14 siblings, 1 reply; 31+ messages in thread
From: Casey Schaufler @ 2025-06-21 17:18 UTC (permalink / raw)
  To: casey, paul, eparis, linux-security-module, audit
  Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
	stephen.smalley.work, linux-kernel, selinux

The LSM hook security_cred_getsecid() provides a single secid
that is only used by the binder driver. Provide the first value
available, and abandon any other hooks.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
 security/security.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/security/security.c b/security/security.c
index dd167a872248..409b1cb10d35 100644
--- a/security/security.c
+++ b/security/security.c
@@ -2740,8 +2740,13 @@ void security_transfer_creds(struct cred *new, const struct cred *old)
  */
 void security_cred_getsecid(const struct cred *c, u32 *secid)
 {
+	struct lsm_static_call *scall;
+
 	*secid = 0;
-	call_void_hook(cred_getsecid, c, secid);
+	lsm_for_each_hook(scall, cred_getsecid) {
+		scall->hl->hook.cred_getsecid(c, secid);
+		break;
+	}
 }
 EXPORT_SYMBOL(security_cred_getsecid);
 
-- 
2.47.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [RFC PATCH 14/15] Smack: Remove LSM_FLAG_EXCLUSIVE
  2025-06-21 17:18 ` [RFC PATCH 00/15] LSM: No exclusive LSMs Casey Schaufler
                     ` (12 preceding siblings ...)
  2025-06-21 17:18   ` [RFC PATCH 13/15] LSM: restrict security_cred_getsecid() to a single LSM Casey Schaufler
@ 2025-06-21 17:18   ` Casey Schaufler
  2025-06-21 17:18   ` [RFC PATCH 15/15] LSM: Remove exclusive LSM flag Casey Schaufler
  14 siblings, 0 replies; 31+ messages in thread
From: Casey Schaufler @ 2025-06-21 17:18 UTC (permalink / raw)
  To: casey, paul, eparis, linux-security-module, audit
  Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
	stephen.smalley.work, linux-kernel, selinux

Smack no longer has any behaviors that require LSM_FLAG_EXCLUSIVE.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
 security/smack/smack_lsm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 650f2700160f..fa7a9b76f0a4 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -5339,7 +5339,7 @@ static int __init smack_initcall(void)
  */
 DEFINE_LSM(smack) = {
 	.id = &smack_lsmid,
-	.flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
+	.flags = LSM_FLAG_LEGACY_MAJOR,
 	.blobs = &smack_blob_sizes,
 	.init = smack_init,
 	.initcall_device = smack_initcall,
-- 
2.47.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [RFC PATCH 15/15] LSM: Remove exclusive LSM flag
  2025-06-21 17:18 ` [RFC PATCH 00/15] LSM: No exclusive LSMs Casey Schaufler
                     ` (13 preceding siblings ...)
  2025-06-21 17:18   ` [RFC PATCH 14/15] Smack: Remove LSM_FLAG_EXCLUSIVE Casey Schaufler
@ 2025-06-21 17:18   ` Casey Schaufler
  14 siblings, 0 replies; 31+ messages in thread
From: Casey Schaufler @ 2025-06-21 17:18 UTC (permalink / raw)
  To: casey, paul, eparis, linux-security-module, audit
  Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
	stephen.smalley.work, linux-kernel, selinux

Only SELinux specifies LSM_FLAG_EXCLUSIVE, so there is no point in
enforcing it. There is no expectation that new exclusive security
modules will be accepted, as the reasons for exclusivity have been
addressed. The LSM_FLAG_EXCLUSIVE flag and its enforcement can be
removed.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
 include/linux/lsm_hooks.h |  1 -
 security/lsm_init.c       | 17 +----------------
 security/selinux/hooks.c  |  2 +-
 3 files changed, 2 insertions(+), 18 deletions(-)

diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 06e840fd4b63..717541fcd653 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -149,7 +149,6 @@ extern void security_add_hooks(struct security_hook_list *hooks, int count,
 			       const struct lsm_id *lsmid);
 
 #define LSM_FLAG_LEGACY_MAJOR	BIT(0)
-#define LSM_FLAG_EXCLUSIVE	BIT(1)
 
 enum lsm_order {
 	LSM_ORDER_FIRST = -1,	/* This is only for capabilities. */
diff --git a/security/lsm_init.c b/security/lsm_init.c
index 784f8296966f..3d8f59104d8f 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -28,7 +28,6 @@ static __initdata const char *lsm_order_cmdline;
 static __initdata const char *lsm_order_legacy;
 
 /* Ordered list of LSMs to initialize. */
-static __initdata struct lsm_info *lsm_exclusive;
 static __initdata struct lsm_info *lsm_order[MAX_LSM_COUNT + 1];
 
 #define lsm_order_for_each(iter)					\
@@ -150,8 +149,7 @@ static bool __init lsm_order_exists(struct lsm_info *lsm)
  * @src: source of the addition
  *
  * Append @lsm to the enabled LSM array after ensuring that it hasn't been
- * explicitly disabled, is a duplicate entry, or would run afoul of the
- * LSM_FLAG_EXCLUSIVE logic.
+ * explicitly disabled or is a duplicate entry.
  */
 static void __init lsm_order_append(struct lsm_info *lsm, const char *src)
 {
@@ -173,19 +171,6 @@ static void __init lsm_order_append(struct lsm_info *lsm, const char *src)
 		return;
 	}
 
-	if (lsm->flags & LSM_FLAG_EXCLUSIVE) {
-		if (lsm_exclusive) {
-			lsm_pr_dbg("skip exclusive LSM conflict %s:%s\n",
-				   src, lsm->id->name);
-			lsm_enabled_set(lsm, false);
-			return;
-		} else {
-			lsm_pr_dbg("select exclusive LSM %s:%s\n",
-				   src, lsm->id->name);
-			lsm_exclusive = lsm;
-		}
-	}
-
 	lsm_enabled_set(lsm, true);
 	lsm_order[lsm_count] = lsm;
 	lsm_idlist[lsm_count++] = lsm->id;
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 9578b63bbd2a..039d03be91f0 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -7675,7 +7675,7 @@ void selinux_complete_init(void)
    all processes and objects when they are created. */
 DEFINE_LSM(selinux) = {
 	.id = &selinux_lsmid,
-	.flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
+	.flags = LSM_FLAG_LEGACY_MAJOR,
 	.enabled = &selinux_enabled_boot,
 	.blobs = &selinux_blob_sizes,
 	.init = selinux_init,
-- 
2.47.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* Re: [PATCH RFC 1/15] Audit: Create audit_stamp structure
  2025-06-21 17:18   ` [RFC PATCH 01/15] Audit: Create audit_stamp structure Casey Schaufler
@ 2025-10-14 23:12     ` Paul Moore
  2025-10-15  5:18       ` Casey Schaufler
  0 siblings, 1 reply; 31+ messages in thread
From: Paul Moore @ 2025-10-14 23:12 UTC (permalink / raw)
  To: Casey Schaufler, casey, eparis, linux-security-module, audit
  Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
	stephen.smalley.work, linux-kernel, selinux

On Jun 21, 2025 Casey Schaufler <casey@schaufler-ca.com> wrote:
> 
> Replace the timestamp and serial number pair used in audit records
> with a structure containing the two elements.
> 
> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> ---
>  kernel/audit.c   | 17 +++++++++--------
>  kernel/audit.h   | 13 +++++++++----
>  kernel/auditsc.c | 22 +++++++++-------------
>  3 files changed, 27 insertions(+), 25 deletions(-)

Dropped as this patch was merged into Linus' tree during the v6.18
merge window via another patchset.  To be clear, I generally don't have
a problem with multiple patchsets including a few common patches, it
helps prevent cross-dependencies between patchsets which is a good
thing.

--
paul-moore.com

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH RFC 2/15] LSM: security_lsmblob_to_secctx module selection
  2025-06-21 17:18   ` [RFC PATCH 02/15] LSM: security_lsmblob_to_secctx module selection Casey Schaufler
@ 2025-10-14 23:12     ` Paul Moore
  0 siblings, 0 replies; 31+ messages in thread
From: Paul Moore @ 2025-10-14 23:12 UTC (permalink / raw)
  To: Casey Schaufler, casey, eparis, linux-security-module, audit
  Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
	stephen.smalley.work, linux-kernel, selinux

On Jun 21, 2025 Casey Schaufler <casey@schaufler-ca.com> wrote:
> 
> Add a parameter lsmid to security_lsmblob_to_secctx() to identify which
> of the security modules that may be active should provide the security
> context. If the value of lsmid is LSM_ID_UNDEF the first LSM providing
> a hook is used. security_secid_to_secctx() is unchanged, and will
> always report the first LSM providing a hook.
> 
> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> ---
>  include/linux/security.h     |  6 ++++--
>  kernel/audit.c               |  4 ++--
>  kernel/auditsc.c             |  8 +++++---
>  net/netlabel/netlabel_user.c |  3 ++-
>  security/security.c          | 13 +++++++++++--
>  5 files changed, 24 insertions(+), 10 deletions(-)

Similar to patch 1/15, dropped due to this already being in Linus'
tree.

--
paul-moore.com

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH RFC 3/15] Audit: Add record for multiple task security  contexts
  2025-06-21 17:18   ` [RFC PATCH 03/15] Audit: Add record for multiple task security contexts Casey Schaufler
@ 2025-10-14 23:12     ` Paul Moore
  0 siblings, 0 replies; 31+ messages in thread
From: Paul Moore @ 2025-10-14 23:12 UTC (permalink / raw)
  To: Casey Schaufler, casey, eparis, linux-security-module, audit
  Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
	stephen.smalley.work, linux-kernel, selinux

On Jun 21, 2025 Casey Schaufler <casey@schaufler-ca.com> wrote:
> 
> Replace the single skb pointer in an audit_buffer with a list of
> skb pointers. Add the audit_stamp information to the audit_buffer as
> there's no guarantee that there will be an audit_context containing
> the stamp associated with the event. At audit_log_end() time create
> auxiliary records as have been added to the list. Functions are
> created to manage the skb list in the audit_buffer.
> 
> Create a new audit record AUDIT_MAC_TASK_CONTEXTS.
> An example of the MAC_TASK_CONTEXTS record is:
> 
>     type=MAC_TASK_CONTEXTS
>     msg=audit(1600880931.832:113)
>     subj_apparmor=unconfined
>     subj_smack=_
> 
> When an audit event includes a AUDIT_MAC_TASK_CONTEXTS record the
> "subj=" field in other records in the event will be "subj=?".
> An AUDIT_MAC_TASK_CONTEXTS record is supplied when the system has
> multiple security modules that may make access decisions based on a
> subject security context.
> 
> Refactor audit_log_task_context(), creating a new audit_log_subj_ctx().
> This is used in netlabel auditing to provide multiple subject security
> contexts as necessary.
> 
> Suggested-by: Paul Moore <paul@paul-moore.com>
> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> ---
>  include/linux/audit.h        |  16 +++
>  include/uapi/linux/audit.h   |   1 +
>  kernel/audit.c               | 207 +++++++++++++++++++++++++++++------
>  net/netlabel/netlabel_user.c |   9 +-
>  security/apparmor/lsm.c      |   3 +
>  security/lsm.h               |   4 -
>  security/lsm_init.c          |   5 -
>  security/security.c          |   3 -
>  security/selinux/hooks.c     |   3 +
>  security/smack/smack_lsm.c   |   3 +
>  10 files changed, 202 insertions(+), 52 deletions(-)

Similar to patch 1/15, dropped due to this already being in Linus'
tree.

--
paul-moore.com

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH RFC 4/15] Audit: Add record for multiple object contexts
  2025-06-21 17:18   ` [RFC PATCH 04/15] Audit: Add record for multiple object contexts Casey Schaufler
@ 2025-10-14 23:12     ` Paul Moore
  0 siblings, 0 replies; 31+ messages in thread
From: Paul Moore @ 2025-10-14 23:12 UTC (permalink / raw)
  To: Casey Schaufler, casey, eparis, linux-security-module, audit
  Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
	stephen.smalley.work, linux-kernel, selinux

On Jun 21, 2025 Casey Schaufler <casey@schaufler-ca.com> wrote:
> 
> Create a new audit record AUDIT_MAC_OBJ_CONTEXTS.
> An example of the MAC_OBJ_CONTEXTS record is:
> 
>     type=MAC_OBJ_CONTEXTS
>     msg=audit(1601152467.009:1050):
>     obj_selinux=unconfined_u:object_r:user_home_t:s0
> 
> When an audit event includes a AUDIT_MAC_OBJ_CONTEXTS record
> the "obj=" field in other records in the event will be "obj=?".
> An AUDIT_MAC_OBJ_CONTEXTS record is supplied when the system has
> multiple security modules that may make access decisions based
> on an object security context.
> 
> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> ---
>  include/linux/audit.h      |  7 +++++
>  include/uapi/linux/audit.h |  1 +
>  kernel/audit.c             | 58 +++++++++++++++++++++++++++++++++++++-
>  kernel/auditsc.c           | 45 ++++++++---------------------
>  security/selinux/hooks.c   |  3 +-
>  security/smack/smack_lsm.c |  3 +-
>  6 files changed, 80 insertions(+), 37 deletions(-)

Similar to patch 1/15, dropped due to this already being in Linus'
tree.

--
paul-moore.com

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH RFC 5/15] LSM: Single calls in secid hooks
  2025-06-21 17:18   ` [RFC PATCH 05/15] LSM: Single calls in secid hooks Casey Schaufler
@ 2025-10-14 23:12     ` Paul Moore
  2025-11-04 16:00       ` Casey Schaufler
  0 siblings, 1 reply; 31+ messages in thread
From: Paul Moore @ 2025-10-14 23:12 UTC (permalink / raw)
  To: Casey Schaufler, casey, eparis, linux-security-module, audit
  Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
	stephen.smalley.work, linux-kernel, selinux

On Jun 21, 2025 Casey Schaufler <casey@schaufler-ca.com> wrote:
> 
> security_socket_getpeersec_stream(), security_socket_getpeersec_dgram()
> and security_secctx_to_secid() can only provide a single security context
> or secid to their callers.  Open code these hooks to return the first
> hook provided. Because only one "major" LSM is allowed there will only
> be one hook in the list, with the excepton being BPF. BPF is not expected
> to be using these interfaces.
> 
> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> ---
>  security/security.c | 24 ++++++++++++++++++++----
>  1 file changed, 20 insertions(+), 4 deletions(-)
> 
> diff --git a/security/security.c b/security/security.c
> index db85006d2fd5..2286285f8aea 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -3806,8 +3806,13 @@ EXPORT_SYMBOL(security_lsmprop_to_secctx);
>   */
>  int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
>  {
> +	struct lsm_static_call *scall;
> +
>  	*secid = 0;
> -	return call_int_hook(secctx_to_secid, secdata, seclen, secid);
> +	lsm_for_each_hook(scall, secctx_to_secid) {
> +		return scall->hl->hook.secctx_to_secid(secdata, seclen, secid);
> +	}
> +	return LSM_RET_DEFAULT(secctx_to_secid);
>  }
>  EXPORT_SYMBOL(security_secctx_to_secid);

Two thoughts come to mind:

If we are relying on BPF not using these hooks we should remove the BPF
callback.  It looks like the secctx_to_secid and socket_getpeersec_stream
callbacks are already absent from the BPF LSM, so it's just a matter of
working with the BPF folks to see if socket_getpeersec_dgram can be
removed.  If it can't be removed, you'll need to find another solution.

Instead of opening up the call_int_hook() wrapper here, what would it
look like if we enforced the single callback rule at LSM registration
time?

> @@ -4268,8 +4273,13 @@ EXPORT_SYMBOL(security_sock_rcv_skb);
>  int security_socket_getpeersec_stream(struct socket *sock, sockptr_t optval,
>  				      sockptr_t optlen, unsigned int len)
>  {
> -	return call_int_hook(socket_getpeersec_stream, sock, optval, optlen,
> -			     len);
> +	struct lsm_static_call *scall;
> +
> +	lsm_for_each_hook(scall, socket_getpeersec_stream) {
> +		return scall->hl->hook.socket_getpeersec_stream(sock, optval,
> +								optlen, len);
> +	}
> +	return LSM_RET_DEFAULT(socket_getpeersec_stream);
>  }
>  
>  /**
> @@ -4289,7 +4299,13 @@ int security_socket_getpeersec_stream(struct socket *sock, sockptr_t optval,
>  int security_socket_getpeersec_dgram(struct socket *sock,
>  				     struct sk_buff *skb, u32 *secid)
>  {
> -	return call_int_hook(socket_getpeersec_dgram, sock, skb, secid);
> +	struct lsm_static_call *scall;
> +
> +	lsm_for_each_hook(scall, socket_getpeersec_dgram) {
> +		return scall->hl->hook.socket_getpeersec_dgram(sock, skb,
> +							       secid);
> +	}
> +	return LSM_RET_DEFAULT(socket_getpeersec_dgram);
>  }
>  EXPORT_SYMBOL(security_socket_getpeersec_dgram);
>  
> -- 
> 2.47.0

--
paul-moore.com

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH RFC 6/15] LSM: Exclusive secmark usage
  2025-06-21 17:18   ` [RFC PATCH 06/15] LSM: Exclusive secmark usage Casey Schaufler
@ 2025-10-14 23:12     ` Paul Moore
  0 siblings, 0 replies; 31+ messages in thread
From: Paul Moore @ 2025-10-14 23:12 UTC (permalink / raw)
  To: Casey Schaufler, casey, eparis, linux-security-module, audit
  Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
	stephen.smalley.work, linux-kernel, selinux

On Jun 21, 2025 Casey Schaufler <casey@schaufler-ca.com> wrote:
> 
> The network secmark can only be used by one security module
> at a time. Establish mechanism to identify to security modules
> whether they have access to the secmark. SELinux already
> incorparates mechanism, but it has to be added to Smack and
> AppArmor.
> 
> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> ---
>  include/linux/lsm_hooks.h        |  1 +
>  security/apparmor/include/net.h  |  5 +++++
>  security/apparmor/lsm.c          |  7 ++++---
>  security/lsm_init.c              |  6 ++++++
>  security/selinux/hooks.c         |  4 +++-
>  security/smack/smack.h           |  5 +++++
>  security/smack/smack_lsm.c       |  3 ++-
>  security/smack/smack_netfilter.c | 10 ++++++++--
>  8 files changed, 34 insertions(+), 7 deletions(-)

We discussed this patch in a separate patchset, lore link below.

https://lore.kernel.org/linux-security-module/20251001215643.31465-1-casey@schaufler-ca.com/

--
paul-moore.com

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH RFC 7/15] Audit: Call only the first of the audit rule  hooks
  2025-06-21 17:18   ` [RFC PATCH 07/15] Audit: Call only the first of the audit rule hooks Casey Schaufler
@ 2025-10-14 23:12     ` Paul Moore
  0 siblings, 0 replies; 31+ messages in thread
From: Paul Moore @ 2025-10-14 23:12 UTC (permalink / raw)
  To: Casey Schaufler, casey, eparis, linux-security-module, audit
  Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
	stephen.smalley.work, linux-kernel, selinux

On Jun 21, 2025 Casey Schaufler <casey@schaufler-ca.com> wrote:
> 
> The audit system is not (yet) capable for distinguishing
> between audit rules specified for multiple security modules.
> Call only the first registered of the audit rule hooks.
> The order of registration, which can be specified with the
> lsm= boot parameter, is hence an important consideration.
> 
> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> ---
>  security/security.c | 30 ++++++++++++++++++++++++++----
>  1 file changed, 26 insertions(+), 4 deletions(-)
> 
> diff --git a/security/security.c b/security/security.c
> index 2286285f8aea..93d4ac39fe9f 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -5056,7 +5056,13 @@ void security_key_post_create_or_update(struct key *keyring, struct key *key,
>  int security_audit_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule,
>  			     gfp_t gfp)
>  {
> -	return call_int_hook(audit_rule_init, field, op, rulestr, lsmrule, gfp);
> +	struct lsm_static_call *scall;
> +
> +	lsm_for_each_hook(scall, audit_rule_init) {
> +		return scall->hl->hook.audit_rule_init(field, op, rulestr,
> +						       lsmrule, gfp);
> +	}
> +	return LSM_RET_DEFAULT(audit_rule_init);
>  }

Similar to the comments in patch 5/15, what would it look like to do the
enforcement of this callback restriction at LSM registration time?

>  /**
> @@ -5070,7 +5076,12 @@ int security_audit_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule,
>   */
>  int security_audit_rule_known(struct audit_krule *krule)
>  {
> -	return call_int_hook(audit_rule_known, krule);
> +	struct lsm_static_call *scall;
> +
> +	lsm_for_each_hook(scall, audit_rule_known) {
> +		return scall->hl->hook.audit_rule_known(krule);
> +	}
> +	return LSM_RET_DEFAULT(audit_rule_known);
>  }
>  
>  /**
> @@ -5082,7 +5093,12 @@ int security_audit_rule_known(struct audit_krule *krule)
>   */
>  void security_audit_rule_free(void *lsmrule)
>  {
> -	call_void_hook(audit_rule_free, lsmrule);
> +	struct lsm_static_call *scall;
> +
> +	lsm_for_each_hook(scall, audit_rule_free) {
> +		scall->hl->hook.audit_rule_free(lsmrule);
> +		return;
> +	}
>  }
>  
>  /**
> @@ -5101,7 +5117,13 @@ void security_audit_rule_free(void *lsmrule)
>  int security_audit_rule_match(struct lsm_prop *prop, u32 field, u32 op,
>  			      void *lsmrule)
>  {
> -	return call_int_hook(audit_rule_match, prop, field, op, lsmrule);
> +	struct lsm_static_call *scall;
> +
> +	lsm_for_each_hook(scall, audit_rule_match) {
> +		return scall->hl->hook.audit_rule_match(prop, field, op,
> +							lsmrule);
> +	}
> +	return LSM_RET_DEFAULT(audit_rule_match);
>  }
>  #endif /* CONFIG_AUDIT */
>  
> -- 
> 2.47.0

--
paul-moore.com

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH RFC 9/15] LSM: Add mount opts blob size tracking
  2025-06-21 17:18   ` [RFC PATCH 09/15] LSM: Add mount opts blob size tracking Casey Schaufler
@ 2025-10-14 23:12     ` Paul Moore
  0 siblings, 0 replies; 31+ messages in thread
From: Paul Moore @ 2025-10-14 23:12 UTC (permalink / raw)
  To: Casey Schaufler, casey, eparis, linux-security-module, audit
  Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
	stephen.smalley.work, linux-kernel, selinux

On Jun 21, 2025 Casey Schaufler <casey@schaufler-ca.com> wrote:
> 
> Add mount option data to the blob size accounting in anticipation
> of using a shared mnt_opts blob.
> 
> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> ---
>  include/linux/lsm_hooks.h  | 1 +
>  security/lsm_init.c        | 2 ++
>  security/selinux/hooks.c   | 1 +
>  security/smack/smack_lsm.c | 1 +
>  4 files changed, 5 insertions(+)

We discussed this patch in a separate patchset, lore link below.

https://lore.kernel.org/linux-security-module/20250925171208.5997-1-casey@schaufler-ca.com/

--
paul-moore.com

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH RFC 10/15] LSM: allocate mnt_opts blobs instead of module  specific data
  2025-06-21 17:18   ` [RFC PATCH 10/15] LSM: allocate mnt_opts blobs instead of module specific data Casey Schaufler
@ 2025-10-14 23:12     ` Paul Moore
  0 siblings, 0 replies; 31+ messages in thread
From: Paul Moore @ 2025-10-14 23:12 UTC (permalink / raw)
  To: Casey Schaufler, casey, eparis, linux-security-module, audit
  Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
	stephen.smalley.work, linux-kernel, selinux

On Jun 21, 2025 Casey Schaufler <casey@schaufler-ca.com> wrote:
> 
> Replace allocations of LSM specific mount data with the
> shared mnt_opts blob.
> 
> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> ---
>  include/linux/lsm_hooks.h  |  1 +
>  security/security.c        | 12 ++++++++++++
>  security/selinux/hooks.c   | 10 +++++++---
>  security/smack/smack_lsm.c |  4 ++--
>  4 files changed, 22 insertions(+), 5 deletions(-)

We discussed the concepts in this patch in a separate patchset, lore link below.

https://lore.kernel.org/linux-security-module/20250925171208.5997-1-casey@schaufler-ca.com/

--
paul-moore.com

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH RFC 11/15] LSM: Infrastructure management of the mnt_opts  security blob
  2025-06-21 17:18   ` [RFC PATCH 11/15] LSM: Infrastructure management of the mnt_opts security blob Casey Schaufler
@ 2025-10-14 23:12     ` Paul Moore
  0 siblings, 0 replies; 31+ messages in thread
From: Paul Moore @ 2025-10-14 23:12 UTC (permalink / raw)
  To: Casey Schaufler, casey, eparis, linux-security-module, audit
  Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
	stephen.smalley.work, linux-kernel, selinux

On Jun 21, 2025 Casey Schaufler <casey@schaufler-ca.com> wrote:
> 
> Move management of the mnt_opts->security blob out of the
> individual security modules and into the security
> infrastructure. Blobs are still allocated within the modules
> as they are only required when mount options are present.
> The modules tell the infrastructure how much space is required,
> and the space is allocated if needed. Modules can no longer
> count on the presence of a blob implying that mount options
> specific to that module are present, so flags are added
> to the module specific blobs to indicate that this module
> has options.
> 
> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> ---
>  security/security.c        | 14 ++++-----
>  security/selinux/hooks.c   | 58 +++++++++++++++++++++++-------------
>  security/smack/smack_lsm.c | 61 ++++++++++++++++++++++++++------------
>  3 files changed, 85 insertions(+), 48 deletions(-)

We discussed this patch in a separate patchset, lore link below.

https://lore.kernel.org/linux-security-module/20250925171208.5997-1-casey@schaufler-ca.com/

--
paul-moore.com

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH RFC 12/15] LSM: Allow reservation of netlabel
  2025-06-21 17:18   ` [RFC PATCH 12/15] LSM: Allow reservation of netlabel Casey Schaufler
@ 2025-10-14 23:12     ` Paul Moore
  0 siblings, 0 replies; 31+ messages in thread
From: Paul Moore @ 2025-10-14 23:12 UTC (permalink / raw)
  To: Casey Schaufler, casey, eparis, linux-security-module, audit
  Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
	stephen.smalley.work, linux-kernel, selinux

On Jun 21, 2025 Casey Schaufler <casey@schaufler-ca.com> wrote:
> 
> Allow LSMs to request exclusive access to the netlabel facility.
> Provide mechanism for LSMs to determine if they have access to
> netlabel. Update the current users of netlabel, SELinux and Smack,
> to use and respect the exclusive use of netlabel.
> 
> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> ---
>  include/linux/lsm_hooks.h           |  1 +
>  security/lsm_init.c                 |  6 +++++
>  security/selinux/hooks.c            |  7 +++---
>  security/selinux/include/netlabel.h |  5 ++++
>  security/selinux/netlabel.c         |  4 ++--
>  security/smack/smack.h              |  5 ++++
>  security/smack/smack_lsm.c          | 36 +++++++++++++++++++++--------
>  security/smack/smackfs.c            | 20 +++++++++++++++-
>  8 files changed, 69 insertions(+), 15 deletions(-)

We discussed this patch in a separate patchset, lore link below.

https://lore.kernel.org/linux-security-module/20251001215643.31465-1-casey@schaufler-ca.com/

--
paul-moore.com

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH RFC 13/15] LSM: restrict security_cred_getsecid() to a  single LSM
  2025-06-21 17:18   ` [RFC PATCH 13/15] LSM: restrict security_cred_getsecid() to a single LSM Casey Schaufler
@ 2025-10-14 23:13     ` Paul Moore
  0 siblings, 0 replies; 31+ messages in thread
From: Paul Moore @ 2025-10-14 23:13 UTC (permalink / raw)
  To: Casey Schaufler, casey, eparis, linux-security-module, audit
  Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
	stephen.smalley.work, linux-kernel, selinux

On Jun 21, 2025 Casey Schaufler <casey@schaufler-ca.com> wrote:
> 
> The LSM hook security_cred_getsecid() provides a single secid
> that is only used by the binder driver. Provide the first value
> available, and abandon any other hooks.
> 
> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> ---
>  security/security.c | 7 ++++++-
>  1 file changed, 6 insertions(+), 1 deletion(-)
> 
> diff --git a/security/security.c b/security/security.c
> index dd167a872248..409b1cb10d35 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -2740,8 +2740,13 @@ void security_transfer_creds(struct cred *new, const struct cred *old)
>   */
>  void security_cred_getsecid(const struct cred *c, u32 *secid)
>  {
> +	struct lsm_static_call *scall;
> +
>  	*secid = 0;
> -	call_void_hook(cred_getsecid, c, secid);
> +	lsm_for_each_hook(scall, cred_getsecid) {
> +		scall->hl->hook.cred_getsecid(c, secid);
> +		break;
> +	}
>  }
>  EXPORT_SYMBOL(security_cred_getsecid);

Another case of "would this be painful to do at registration time?"

--
paul-moore.com

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH RFC 1/15] Audit: Create audit_stamp structure
  2025-10-14 23:12     ` [PATCH RFC 1/15] " Paul Moore
@ 2025-10-15  5:18       ` Casey Schaufler
  2025-10-15 15:01         ` Paul Moore
  0 siblings, 1 reply; 31+ messages in thread
From: Casey Schaufler @ 2025-10-15  5:18 UTC (permalink / raw)
  To: Paul Moore; +Cc: LSM List


On 10/14/2025 4:12 PM, Paul Moore wrote:
> On Jun 21, 2025 Casey Schaufler <casey@schaufler-ca.com> wrote:
>> Replace the timestamp and serial number pair used in audit records
>> with a structure containing the two elements.
>>
>> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
>> ---
>>  kernel/audit.c   | 17 +++++++++--------
>>  kernel/audit.h   | 13 +++++++++----
>>  kernel/auditsc.c | 22 +++++++++-------------
>>  3 files changed, 27 insertions(+), 25 deletions(-)
> Dropped as this patch was merged into Linus' tree during the v6.18
> merge window via another patchset.  To be clear, I generally don't have
> a problem with multiple patchsets including a few common patches, it
> helps prevent cross-dependencies between patchsets which is a good
> thing.
>
> --
> paul-moore.com

I'm off-grid for the rest of the month. Will respond to these many things
upon my return.


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH RFC 1/15] Audit: Create audit_stamp structure
  2025-10-15  5:18       ` Casey Schaufler
@ 2025-10-15 15:01         ` Paul Moore
  0 siblings, 0 replies; 31+ messages in thread
From: Paul Moore @ 2025-10-15 15:01 UTC (permalink / raw)
  To: Casey Schaufler; +Cc: LSM List

On Wed, Oct 15, 2025 at 1:20 AM Casey Schaufler <casey@schaufler-ca.com> wrote:
> On 10/14/2025 4:12 PM, Paul Moore wrote:
> > On Jun 21, 2025 Casey Schaufler <casey@schaufler-ca.com> wrote:
> >> Replace the timestamp and serial number pair used in audit records
> >> with a structure containing the two elements.
> >>
> >> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> >> ---
> >>  kernel/audit.c   | 17 +++++++++--------
> >>  kernel/audit.h   | 13 +++++++++----
> >>  kernel/auditsc.c | 22 +++++++++-------------
> >>  3 files changed, 27 insertions(+), 25 deletions(-)
> >
> > Dropped as this patch was merged into Linus' tree during the v6.18
> > merge window via another patchset.  To be clear, I generally don't have
> > a problem with multiple patchsets including a few common patches, it
> > helps prevent cross-dependencies between patchsets which is a good
> > thing.
>
> I'm off-grid for the rest of the month. Will respond to these many things
> upon my return.

No worries, enjoy your time away and thanks for letting us know.

-- 
paul-moore.com

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH RFC 5/15] LSM: Single calls in secid hooks
  2025-10-14 23:12     ` [PATCH RFC 5/15] " Paul Moore
@ 2025-11-04 16:00       ` Casey Schaufler
  0 siblings, 0 replies; 31+ messages in thread
From: Casey Schaufler @ 2025-11-04 16:00 UTC (permalink / raw)
  To: Paul Moore, eparis, linux-security-module, audit
  Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
	stephen.smalley.work, linux-kernel, selinux, Casey Schaufler

On 10/14/2025 4:12 PM, Paul Moore wrote:
> On Jun 21, 2025 Casey Schaufler <casey@schaufler-ca.com> wrote:
>> security_socket_getpeersec_stream(), security_socket_getpeersec_dgram()
>> and security_secctx_to_secid() can only provide a single security context
>> or secid to their callers.  Open code these hooks to return the first
>> hook provided. Because only one "major" LSM is allowed there will only
>> be one hook in the list, with the excepton being BPF. BPF is not expected
>> to be using these interfaces.
>>
>> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
>> ---
>>  security/security.c | 24 ++++++++++++++++++++----
>>  1 file changed, 20 insertions(+), 4 deletions(-)
>>
>> diff --git a/security/security.c b/security/security.c
>> index db85006d2fd5..2286285f8aea 100644
>> --- a/security/security.c
>> +++ b/security/security.c
>> @@ -3806,8 +3806,13 @@ EXPORT_SYMBOL(security_lsmprop_to_secctx);
>>   */
>>  int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
>>  {
>> +	struct lsm_static_call *scall;
>> +
>>  	*secid = 0;
>> -	return call_int_hook(secctx_to_secid, secdata, seclen, secid);
>> +	lsm_for_each_hook(scall, secctx_to_secid) {
>> +		return scall->hl->hook.secctx_to_secid(secdata, seclen, secid);
>> +	}
>> +	return LSM_RET_DEFAULT(secctx_to_secid);
>>  }
>>  EXPORT_SYMBOL(security_secctx_to_secid);
> Two thoughts come to mind:
>
> If we are relying on BPF not using these hooks we should remove the BPF
> callback.  It looks like the secctx_to_secid and socket_getpeersec_stream
> callbacks are already absent from the BPF LSM, so it's just a matter of
> working with the BPF folks to see if socket_getpeersec_dgram can be
> removed.  If it can't be removed, you'll need to find another solution.

That should be doable. If BPF decides they want to use lsm_prop data
they already have a passel of work to do, and I see that they have
already suggested removing the BPF data from lsm_prop.
The socket_getpeersec_dgram interface uses secids, not lsm_prop, but
that's an artifact of networking attitude, not what's "right" for it.

> Instead of opening up the call_int_hook() wrapper here, what would it
> look like if we enforced the single callback rule at LSM registration
> time?

I have considered that approach in the past. It would require that
security_add_hooks() know which hooks are single callback and only
call lsm_static_call_init() if no LSM had requested the hook before.
This would be fairly straight forward and have the advantage of allowing
the infrastructure to report which single callback hooks have been
chosen and which disallowed. It does raise the question of whether the
LSM that requested the hook should be notified in the case it was
discarded. That's messy, as there are multiple single callback hooks,
and you could have a case where some are chosen and others disallowed.
I would go without notification, as it's hard to say what an LSM would
do with that information.

I'll give it a go in the next version.

>> @@ -4268,8 +4273,13 @@ EXPORT_SYMBOL(security_sock_rcv_skb);
>>  int security_socket_getpeersec_stream(struct socket *sock, sockptr_t optval,
>>  				      sockptr_t optlen, unsigned int len)
>>  {
>> -	return call_int_hook(socket_getpeersec_stream, sock, optval, optlen,
>> -			     len);
>> +	struct lsm_static_call *scall;
>> +
>> +	lsm_for_each_hook(scall, socket_getpeersec_stream) {
>> +		return scall->hl->hook.socket_getpeersec_stream(sock, optval,
>> +								optlen, len);
>> +	}
>> +	return LSM_RET_DEFAULT(socket_getpeersec_stream);
>>  }
>>  
>>  /**
>> @@ -4289,7 +4299,13 @@ int security_socket_getpeersec_stream(struct socket *sock, sockptr_t optval,
>>  int security_socket_getpeersec_dgram(struct socket *sock,
>>  				     struct sk_buff *skb, u32 *secid)
>>  {
>> -	return call_int_hook(socket_getpeersec_dgram, sock, skb, secid);
>> +	struct lsm_static_call *scall;
>> +
>> +	lsm_for_each_hook(scall, socket_getpeersec_dgram) {
>> +		return scall->hl->hook.socket_getpeersec_dgram(sock, skb,
>> +							       secid);
>> +	}
>> +	return LSM_RET_DEFAULT(socket_getpeersec_dgram);
>>  }
>>  EXPORT_SYMBOL(security_socket_getpeersec_dgram);
>>  
>> -- 
>> 2.47.0
> --
> paul-moore.com

^ permalink raw reply	[flat|nested] 31+ messages in thread

end of thread, other threads:[~2025-11-04 16:10 UTC | newest]

Thread overview: 31+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <20250621171851.5869-1-casey.ref@schaufler-ca.com>
2025-06-21 17:18 ` [RFC PATCH 00/15] LSM: No exclusive LSMs Casey Schaufler
2025-06-21 17:18   ` [RFC PATCH 01/15] Audit: Create audit_stamp structure Casey Schaufler
2025-10-14 23:12     ` [PATCH RFC 1/15] " Paul Moore
2025-10-15  5:18       ` Casey Schaufler
2025-10-15 15:01         ` Paul Moore
2025-06-21 17:18   ` [RFC PATCH 02/15] LSM: security_lsmblob_to_secctx module selection Casey Schaufler
2025-10-14 23:12     ` [PATCH RFC 2/15] " Paul Moore
2025-06-21 17:18   ` [RFC PATCH 03/15] Audit: Add record for multiple task security contexts Casey Schaufler
2025-10-14 23:12     ` [PATCH RFC 3/15] " Paul Moore
2025-06-21 17:18   ` [RFC PATCH 04/15] Audit: Add record for multiple object contexts Casey Schaufler
2025-10-14 23:12     ` [PATCH RFC 4/15] " Paul Moore
2025-06-21 17:18   ` [RFC PATCH 05/15] LSM: Single calls in secid hooks Casey Schaufler
2025-10-14 23:12     ` [PATCH RFC 5/15] " Paul Moore
2025-11-04 16:00       ` Casey Schaufler
2025-06-21 17:18   ` [RFC PATCH 06/15] LSM: Exclusive secmark usage Casey Schaufler
2025-10-14 23:12     ` [PATCH RFC 6/15] " Paul Moore
2025-06-21 17:18   ` [RFC PATCH 07/15] Audit: Call only the first of the audit rule hooks Casey Schaufler
2025-10-14 23:12     ` [PATCH RFC 7/15] " Paul Moore
2025-06-21 17:18   ` [RFC PATCH 08/15] AppArmor: Remove the exclusive flag Casey Schaufler
2025-06-21 17:18   ` [RFC PATCH 09/15] LSM: Add mount opts blob size tracking Casey Schaufler
2025-10-14 23:12     ` [PATCH RFC 9/15] " Paul Moore
2025-06-21 17:18   ` [RFC PATCH 10/15] LSM: allocate mnt_opts blobs instead of module specific data Casey Schaufler
2025-10-14 23:12     ` [PATCH RFC " Paul Moore
2025-06-21 17:18   ` [RFC PATCH 11/15] LSM: Infrastructure management of the mnt_opts security blob Casey Schaufler
2025-10-14 23:12     ` [PATCH RFC " Paul Moore
2025-06-21 17:18   ` [RFC PATCH 12/15] LSM: Allow reservation of netlabel Casey Schaufler
2025-10-14 23:12     ` [PATCH RFC " Paul Moore
2025-06-21 17:18   ` [RFC PATCH 13/15] LSM: restrict security_cred_getsecid() to a single LSM Casey Schaufler
2025-10-14 23:13     ` [PATCH RFC " Paul Moore
2025-06-21 17:18   ` [RFC PATCH 14/15] Smack: Remove LSM_FLAG_EXCLUSIVE Casey Schaufler
2025-06-21 17:18   ` [RFC PATCH 15/15] LSM: Remove exclusive LSM flag Casey Schaufler

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).