All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/7] Change skb secmarks to x-array indexes
       [not found] <20260902220150.18586-1-casey.ref@schaufler-ca.com>
@ 2026-09-02 22:01 ` Casey Schaufler
  2026-09-02 22:01   ` [PATCH v2 1/7] net, smack: Create a function to set secmarks Casey Schaufler
                     ` (6 more replies)
  0 siblings, 7 replies; 22+ messages in thread
From: Casey Schaufler @ 2026-09-02 22:01 UTC (permalink / raw)
  To: casey, paul, linux-security-module, pablo, fw, phil
  Cc: linux-kernel, netfilter-devel, coreteam, jmorris, serge, keescook,
	john.johansen, penguin-kernel, stephen.smalley.work, selinux

When security secmarks were added to the Linux network stack there was
only one Linux Security Module (LSM), SELinux.  SELinux already used the
concept of a security ID (secid) as the representation of the security
information about a system subject (active entity) or object (passive
entity). Adding a container for a secid, the secmark, to the sk_buff
structure allowed for efficient transmission of the SELinux secid for
socket based access controls.

Subsequent LSMs have chosen to represent security information more
directly. Smack and AppArmor use pointers to structures containing
relevant information. Alas, these pointers do not fit in the u32 secmark
on most modern architectures. These LSMs are required to provide a secid
mapping to use secmarks.

Even with all LSMs that use secmarks having a secid to reference the
security information the mechanism is imperfect. A system that wants
to use multiple LSMs that use secmarks is constrained by the size
of the secmark. There is no rational way to fit multiple secids in a
secmark. While it would be possible to allow one LSM to use the secmark
and any others to be told it is unavailable, this has been deemed an
unacceptable limitation.

There is a lsm_prop structure available that contains security information
for any LSM that maintains it. The secmark cannot, unfortunately,
contain one. Instead, an x-array of lsm_prop structures is maintained,
and the index (secxa) is used in the secmark instead of the single LSM
restricted secid.

Uses of security_secctx_to_secid() have been changed to
security_secctx_to_lsmprop() in the netfilter and iptables code.
The security_secmark_relabel_packet() function has been updated to accept
an lsm_prop pointer rather than a secid.
To support multiple LSMs using a secmark it is necessary to re-evaluate
which lsm_prop structure represents the current security information
at each step where the secmark can be set. Smack sets the secmark for
every packet.  Netfilter, used by SELinux, Smack and AppArmor, will set
the secmark on selected packets at a later time. If Smack and AppArmor
are active on a system Smack will set the secmark initially, and AppArmor
may reset it by netfilter rule.

v2: Address issues raised by Sashiko
 - Configuration option insufficiencies
 - Locking issues

https://github.com/cschaufler/lsm-stacking#secmark-xa-7.2-rc7-v2

Casey Schaufler (7):
  net, smack: Create a function to set secmarks
  LSM: Implement x array functions for secmarks
  LSM: Two hooks for manipulating struct lsm_prop
  SELinux: hooks for secctx_to_lsmprop and update_lsmprop
  Smack: hooks for secctx_to_lsmprop and update_lsmprop
  Apparmor: hooks for secctx_to_lsmprop and update_lsmprop
  net, lsm: Change skb secmarks to x-array indexes

 include/linux/lsm_hook_defs.h     |   6 +-
 include/linux/lsm_secxa.h         |  33 ++++++++
 include/linux/security.h          |  20 ++++-
 net/netfilter/nfnetlink_queue.c   |  12 ++-
 net/netfilter/nft_meta.c          |  20 +++--
 net/netfilter/xt_CONNSECMARK.c    |   3 +-
 net/netfilter/xt_SECMARK.c        |  19 +++--
 security/Makefile                 |   1 +
 security/apparmor/include/secid.h |   4 +
 security/apparmor/lsm.c           |   2 +
 security/apparmor/net.c           |   8 +-
 security/apparmor/secid.c         |  21 +++++
 security/lsm_secxa.c              | 127 ++++++++++++++++++++++++++++++
 security/security.c               |  38 ++++++++-
 security/selinux/hooks.c          |  87 +++++++++++++++++---
 security/smack/smack_lsm.c        |  43 +++++++++-
 security/smack/smack_netfilter.c  |  11 ++-
 17 files changed, 417 insertions(+), 38 deletions(-)
 create mode 100644 include/linux/lsm_secxa.h
 create mode 100644 security/lsm_secxa.c

-- 
2.54.0


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

* [PATCH v2 1/7] net, smack: Create a function to set secmarks
  2026-09-02 22:01 ` [PATCH v2 0/7] Change skb secmarks to x-array indexes Casey Schaufler
@ 2026-09-02 22:01   ` Casey Schaufler
  2026-09-02 22:13     ` sashiko-bot
  2026-09-03  5:35     ` John Johansen
  2026-09-02 22:01   ` [PATCH v2 2/7] LSM: Implement x array functions for secmarks Casey Schaufler
                     ` (5 subsequent siblings)
  6 siblings, 2 replies; 22+ messages in thread
From: Casey Schaufler @ 2026-09-02 22:01 UTC (permalink / raw)
  To: casey, paul, linux-security-module, pablo, fw, phil
  Cc: linux-kernel, netfilter-devel, coreteam, jmorris, serge, keescook,
	john.johansen, penguin-kernel, stephen.smalley.work, selinux

Rather than open coding assignments to skb->secmark, use a helper function
secxa_set_secmark(). This allows for a case where assigning a secmark
is more complex than a simple assignment. The version of the function
here does the legacy simple assignment.

Change the functions that currently assign values to skb->secmark to
use this function.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
 include/linux/lsm_secxa.h        | 28 ++++++++++++++++++++++++++++
 net/netfilter/nft_meta.c         |  5 +++--
 net/netfilter/xt_CONNSECMARK.c   |  3 ++-
 net/netfilter/xt_SECMARK.c       |  3 ++-
 security/smack/smack_netfilter.c |  3 ++-
 5 files changed, 37 insertions(+), 5 deletions(-)
 create mode 100644 include/linux/lsm_secxa.h

diff --git a/include/linux/lsm_secxa.h b/include/linux/lsm_secxa.h
new file mode 100644
index 000000000000..926257d4730c
--- /dev/null
+++ b/include/linux/lsm_secxa.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * Copyright (C) 2026 Casey Schaufler <casey@schaufler-ca.com>
+ */
+
+#ifndef __LINUX_LSM_SECXA_H
+#define __LINUX_LSM_SECXA_H
+
+#ifdef CONFIG_NETWORK_SECMARK
+
+#include <linux/security.h>
+#include <linux/skbuff.h>
+
+static inline void secxa_set_secmark(struct sk_buff *skb, u32 secxa)
+{
+	skb->secmark = secxa;
+}
+#else /* CONFIG_NETWORK_SECMARK */
+
+struct sk_buff;
+
+static inline void secxa_set_secmark(struct sk_buff *skb, u32 secxa)
+{
+}
+#endif /* CONFIG_NETWORK_SECMARK */
+
+#endif  /* __LINUX_LSM_SECXA_H */
diff --git a/net/netfilter/nft_meta.c b/net/netfilter/nft_meta.c
index 0a43e0787a68..bd0f7a0931f4 100644
--- a/net/netfilter/nft_meta.c
+++ b/net/netfilter/nft_meta.c
@@ -17,6 +17,7 @@
 #include <linux/random.h>
 #include <linux/smp.h>
 #include <linux/static_key.h>
+#include <linux/lsm_secxa.h>
 #include <net/dst.h>
 #include <net/ip.h>
 #include <net/sock.h>
@@ -502,7 +503,7 @@ void nft_meta_set_eval(const struct nft_expr *expr,
 		break;
 #ifdef CONFIG_NETWORK_SECMARK
 	case NFT_META_SECMARK:
-		skb->secmark = value;
+		secxa_set_secmark(skb, value);
 		break;
 #endif
 	default:
@@ -950,7 +951,7 @@ static void nft_secmark_obj_eval(struct nft_object *obj, struct nft_regs *regs,
 	const struct nft_secmark *priv = nft_obj_data(obj);
 	struct sk_buff *skb = pkt->skb;
 
-	skb->secmark = priv->secid;
+	secxa_set_secmark(skb, priv->secid);
 }
 
 static int nft_secmark_obj_init(const struct nft_ctx *ctx,
diff --git a/net/netfilter/xt_CONNSECMARK.c b/net/netfilter/xt_CONNSECMARK.c
index 1494b3ee30e1..9d799d2459dc 100644
--- a/net/netfilter/xt_CONNSECMARK.c
+++ b/net/netfilter/xt_CONNSECMARK.c
@@ -14,6 +14,7 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/module.h>
 #include <linux/skbuff.h>
+#include <linux/lsm_secxa.h>
 #include <linux/netfilter/x_tables.h>
 #include <linux/netfilter/xt_CONNSECMARK.h>
 #include <net/netfilter/nf_conntrack.h>
@@ -55,7 +56,7 @@ static void secmark_restore(struct sk_buff *skb)
 
 		ct = nf_ct_get(skb, &ctinfo);
 		if (ct && ct->secmark)
-			skb->secmark = ct->secmark;
+			secxa_set_secmark(skb, ct->secmark);
 	}
 }
 
diff --git a/net/netfilter/xt_SECMARK.c b/net/netfilter/xt_SECMARK.c
index 5bc5ea505eb9..ea67aa92ddc2 100644
--- a/net/netfilter/xt_SECMARK.c
+++ b/net/netfilter/xt_SECMARK.c
@@ -11,6 +11,7 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/module.h>
 #include <linux/security.h>
+#include <linux/lsm_secxa.h>
 #include <linux/skbuff.h>
 #include <linux/netfilter/x_tables.h>
 #include <linux/netfilter/xt_SECMARK.h>
@@ -36,7 +37,7 @@ secmark_tg(struct sk_buff *skb, const struct xt_secmark_target_info_v1 *info)
 		BUG();
 	}
 
-	skb->secmark = secmark;
+	secxa_set_secmark(skb, secmark);
 	return XT_CONTINUE;
 }
 
diff --git a/security/smack/smack_netfilter.c b/security/smack/smack_netfilter.c
index 17ba578b1308..b363c42f252e 100644
--- a/security/smack/smack_netfilter.c
+++ b/security/smack/smack_netfilter.c
@@ -14,6 +14,7 @@
 #include <linux/netfilter_ipv4.h>
 #include <linux/netfilter_ipv6.h>
 #include <linux/netdevice.h>
+#include <linux/lsm_secxa.h>
 #include <net/inet_sock.h>
 #include <net/net_namespace.h>
 #include "smack.h"
@@ -29,7 +30,7 @@ static unsigned int smack_ip_output(void *priv,
 	if (sk) {
 		ssp = smack_sock(sk);
 		skp = ssp->smk_out;
-		skb->secmark = skp->smk_secid;
+		secxa_set_secmark(skb, skp->smk_secid);
 	}
 
 	return NF_ACCEPT;
-- 
2.54.0


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

* [PATCH v2 2/7] LSM: Implement x array functions for secmarks
  2026-09-02 22:01 ` [PATCH v2 0/7] Change skb secmarks to x-array indexes Casey Schaufler
  2026-09-02 22:01   ` [PATCH v2 1/7] net, smack: Create a function to set secmarks Casey Schaufler
@ 2026-09-02 22:01   ` Casey Schaufler
  2026-09-02 22:21     ` sashiko-bot
  2026-09-03  5:36     ` John Johansen
  2026-09-02 22:01   ` [PATCH v2 3/7] LSM: Two hooks for manipulating struct lsm_prop Casey Schaufler
                     ` (4 subsequent siblings)
  6 siblings, 2 replies; 22+ messages in thread
From: Casey Schaufler @ 2026-09-02 22:01 UTC (permalink / raw)
  To: casey, paul, linux-security-module, pablo, fw, phil
  Cc: linux-kernel, netfilter-devel, coreteam, jmorris, serge, keescook,
	john.johansen, penguin-kernel, stephen.smalley.work, selinux

Implement, but don't use (yet) the functions required to use
xarray indexes in secmarks.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
 include/linux/lsm_secxa.h |  19 ++++---
 security/Makefile         |   1 +
 security/lsm_secxa.c      | 109 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 121 insertions(+), 8 deletions(-)
 create mode 100644 security/lsm_secxa.c

diff --git a/include/linux/lsm_secxa.h b/include/linux/lsm_secxa.h
index 926257d4730c..84b06c093460 100644
--- a/include/linux/lsm_secxa.h
+++ b/include/linux/lsm_secxa.h
@@ -7,19 +7,22 @@
 #ifndef __LINUX_LSM_SECXA_H
 #define __LINUX_LSM_SECXA_H
 
-#ifdef CONFIG_NETWORK_SECMARK
+#ifdef CONFIG_SECURITY
 
-#include <linux/security.h>
-#include <linux/skbuff.h>
+struct lsm_prop;
 
-static inline void secxa_set_secmark(struct sk_buff *skb, u32 secxa)
-{
-	skb->secmark = secxa;
-}
-#else /* CONFIG_NETWORK_SECMARK */
+int secxa_from_lsmprop(struct lsm_prop *prop, u32 *secxa);
+int secxa_get_lsmprop(struct lsm_prop **pro, u32 secxa);
+
+#endif /* CONFIG_SECURITY */
+
+#ifdef CONFIG_NETWORK_SECMARK
 
 struct sk_buff;
 
+void secxa_set_secmark(struct sk_buff *skb, u32 secxa);
+#else /* CONFIG_NETWORK_SECMARK */
+
 static inline void secxa_set_secmark(struct sk_buff *skb, u32 secxa)
 {
 }
diff --git a/security/Makefile b/security/Makefile
index 4601230ba442..e93be00bb6ae 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_KEYS)			+= keys/
 # always enable default capabilities
 obj-y					+= commoncap.o
 obj-$(CONFIG_SECURITY) 			+= lsm_syscalls.o
+obj-$(CONFIG_NETWORK_SECMARK)		+= lsm_secxa.o
 obj-$(CONFIG_MMU)			+= min_addr.o
 
 # Object file lists
diff --git a/security/lsm_secxa.c b/security/lsm_secxa.c
new file mode 100644
index 000000000000..ccbe78095d70
--- /dev/null
+++ b/security/lsm_secxa.c
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/*
+ * Implement functions supporting an x array for LSM properties.
+ *
+ * Copyright (C) 2026 Casey Schaufler <casey@schaufler-ca.com>
+ */
+#define pr_fmt(fmt) "secxa: "fmt
+
+#include <linux/xarray.h>
+#include <linux/export.h>
+#include <linux/security.h>
+#include <linux/lsm_secxa.h>
+#include <linux/skbuff.h>
+
+/*
+ * An Xarray of lsm_prop structures.
+ */
+struct xarray secxa_xa;
+
+/**
+ * secxa_init - initialize the xarry of lsm_prop structures.
+ */
+static int __init secxa_init(void)
+{
+	xa_init_flags(&secxa_xa, XA_FLAGS_ALLOC1 | XA_FLAGS_LOCK_BH);
+
+	return 0;
+}
+core_initcall(secxa_init);
+
+/**
+ * secxa_get_lsmprop - get the lsm_prop associated with a secxa
+ * @pro: destination for the lsm_prop pointer
+ * @secxa: index to look up
+ *
+ * Find the lsm_prop associated with @secxa and place a pointer
+ * to it in @pro.
+ *
+ * Returns 0, or -EINVAL if the mapping can't be found.
+ */
+int secxa_get_lsmprop(struct lsm_prop **pro, u32 secxa)
+{
+	struct lsm_prop *lp;
+
+	if (!secxa)
+		return -EINVAL;
+
+	lp = xa_load(&secxa_xa, secxa);
+	if (!lp)
+		return -EINVAL;
+
+	*pro = lp;
+	return 0;
+}
+EXPORT_SYMBOL(secxa_get_lsmprop);
+
+/**
+ * secxa_from_lsmprop - get the secxa associated with a lsm_prop
+ * @prop: lsm_prop pointer
+ * @secxa: result
+ *
+ * Find the secxa associated with @prop. If there is none, create it.
+ *
+ * Returns 0, or an error if the mapping cannot be created
+ */
+int secxa_from_lsmprop(struct lsm_prop *prop, u32 *secxa)
+{
+	struct lsm_prop *lp;
+	unsigned long il;
+	u32 index = 0;
+	int rc;
+
+	xa_for_each(&secxa_xa, il, lp) {
+		if (!memcmp(prop, lp, sizeof(*prop))) {
+			*secxa = il;
+			return 0;
+		}
+	}
+
+	lp = kzalloc(sizeof(*lp), GFP_ATOMIC);
+	if (!lp)
+		return -ENOMEM;
+	*lp = *prop;
+
+	rc = xa_alloc_bh(&secxa_xa, &index, lp, xa_limit_31b, GFP_ATOMIC);
+	if (rc) {
+		kfree(lp);
+		return -EINVAL;
+	}
+
+	*secxa = index;
+	return 0;
+}
+EXPORT_SYMBOL(secxa_from_lsmprop);
+
+/**
+ * secxa_set_secmark - add LSM information to a secmark
+ * @skb: buffer with the secmark
+ * @secxa: index of the information to add
+ *
+ * If the secmark in @skb is not set, set it to @secxa.
+ */
+void secxa_set_secmark(struct sk_buff *skb, u32 secxa)
+{
+	if (!skb->secmark)
+		skb->secmark = secxa;
+}
+EXPORT_SYMBOL(secxa_set_secmark);
-- 
2.54.0


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

* [PATCH v2 3/7] LSM: Two hooks for manipulating struct lsm_prop
  2026-09-02 22:01 ` [PATCH v2 0/7] Change skb secmarks to x-array indexes Casey Schaufler
  2026-09-02 22:01   ` [PATCH v2 1/7] net, smack: Create a function to set secmarks Casey Schaufler
  2026-09-02 22:01   ` [PATCH v2 2/7] LSM: Implement x array functions for secmarks Casey Schaufler
@ 2026-09-02 22:01   ` Casey Schaufler
  2026-09-02 22:16     ` sashiko-bot
  2026-09-03  9:40     ` John Johansen
  2026-09-02 22:01   ` [PATCH v2 4/7] SELinux: hooks for secctx_to_lsmprop and update_lsmprop Casey Schaufler
                     ` (3 subsequent siblings)
  6 siblings, 2 replies; 22+ messages in thread
From: Casey Schaufler @ 2026-09-02 22:01 UTC (permalink / raw)
  To: casey, paul, linux-security-module, pablo, fw, phil
  Cc: linux-kernel, netfilter-devel, coreteam, jmorris, serge, keescook,
	john.johansen, penguin-kernel, stephen.smalley.work, selinux

security_update_lsmprop() updates the property of the
specified LSM in the @dest structure with that in the @src.

security_secctx_to_lsmprop() sets the @prop field associated
with the LSM specified to the value of the passed security
context.

LSM specific implementations of these hooks to follow.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
 include/linux/lsm_hook_defs.h |  4 ++++
 include/linux/security.h      | 16 ++++++++++++++++
 security/security.c           | 32 ++++++++++++++++++++++++++++++++
 3 files changed, 52 insertions(+)

diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index 65c9609ec207..679c40a8e127 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -305,7 +305,11 @@ LSM_HOOK(int, 0, ismaclabel, const char *name)
 LSM_HOOK(int, -EOPNOTSUPP, secid_to_secctx, u32 secid, struct lsm_context *cp)
 LSM_HOOK(int, -EOPNOTSUPP, lsmprop_to_secctx, struct lsm_prop *prop,
 	 struct lsm_context *cp)
+LSM_HOOK(void, LSM_RET_VOID, update_lsmprop, struct lsm_prop *dest,
+	 struct lsm_prop *src, int lsmid)
 LSM_HOOK(int, 0, secctx_to_secid, const char *secdata, u32 seclen, u32 *secid)
+LSM_HOOK(int, -EINVAL, secctx_to_lsmprop, const char *secdata, u32 seclen,
+	 struct lsm_prop *prop)
 LSM_HOOK(void, LSM_RET_VOID, release_secctx, struct lsm_context *cp)
 LSM_HOOK(void, LSM_RET_VOID, inode_invalidate_secctx, struct inode *inode)
 LSM_HOOK(int, 0, inode_notifysecctx, struct inode *inode, void *ctx, u32 ctxlen)
diff --git a/include/linux/security.h b/include/linux/security.h
index 153e9043058f..19adc19eb9af 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -576,6 +576,11 @@ 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 lsmid);
 int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
+int security_secctx_to_lsmprop(const char *secdata, u32 seclen,
+			       struct lsm_prop *prop, int lsmid);
+
+void security_update_lsmprop(struct lsm_prop *dest, struct lsm_prop *src,
+			     int lsmid);
 void security_release_secctx(struct lsm_context *cp);
 void security_inode_invalidate_secctx(struct inode *inode);
 int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen);
@@ -1581,6 +1586,11 @@ static inline int security_lsmprop_to_secctx(struct lsm_prop *prop,
 	return -EOPNOTSUPP;
 }
 
+static inline void security_update_lsmprop(struct lsm_prop *dest,
+					   struct lsm_prop *src, int lsmid)
+{
+}
+
 static inline int security_secctx_to_secid(const char *secdata,
 					   u32 seclen,
 					   u32 *secid)
@@ -1588,6 +1598,12 @@ static inline int security_secctx_to_secid(const char *secdata,
 	return -EOPNOTSUPP;
 }
 
+static inline int security_secctx_to_lsmprop(const char *secdata, u32 seclen,
+					     struct lsm_prop *prop, int lsmid)
+{
+	return -EOPNOTSUPP;
+}
+
 static inline void security_release_secctx(struct lsm_context *cp)
 {
 }
diff --git a/security/security.c b/security/security.c
index 71aea8fdf014..1dec0037370b 100644
--- a/security/security.c
+++ b/security/security.c
@@ -3965,6 +3965,13 @@ int security_lsmprop_to_secctx(struct lsm_prop *prop, struct lsm_context *cp,
 }
 EXPORT_SYMBOL(security_lsmprop_to_secctx);
 
+void security_update_lsmprop(struct lsm_prop *dest, struct lsm_prop *src,
+			     int lsmid)
+{
+	call_void_hook(update_lsmprop, dest, src, lsmid);
+}
+EXPORT_SYMBOL(security_update_lsmprop);
+
 /**
  * security_secctx_to_secid() - Convert a secctx to a secid
  * @secdata: secctx
@@ -3982,6 +3989,31 @@ int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
 }
 EXPORT_SYMBOL(security_secctx_to_secid);
 
+/**
+ * security_secctx_to_lsmprop() - Convert a secctx to a lsmprop
+ * @secdata: secctx
+ * @seclen: length of secctx
+ * @prop: prop
+ * @lsmid: which LSM the context is appropriate to.
+ *
+ * Convert security context to an lsmprop.
+ *
+ * Return: Returns 0 on success, error on failure.
+ */
+int security_secctx_to_lsmprop(const char *secdata, u32 seclen,
+			       struct lsm_prop *prop, int lsmid)
+{
+	struct lsm_static_call *scall;
+
+	lsm_for_each_hook(scall, secctx_to_lsmprop) {
+		if (lsmid != LSM_ID_UNDEF && lsmid != scall->hl->lsmid->id)
+			continue;
+		return scall->hl->hook.secctx_to_lsmprop(secdata, seclen, prop);
+	}
+	return LSM_RET_DEFAULT(secctx_to_lsmprop);
+}
+EXPORT_SYMBOL(security_secctx_to_lsmprop);
+
 /**
  * security_release_secctx() - Free a secctx buffer
  * @cp: the security context
-- 
2.54.0


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

* [PATCH v2 4/7] SELinux: hooks for secctx_to_lsmprop and update_lsmprop
  2026-09-02 22:01 ` [PATCH v2 0/7] Change skb secmarks to x-array indexes Casey Schaufler
                     ` (2 preceding siblings ...)
  2026-09-02 22:01   ` [PATCH v2 3/7] LSM: Two hooks for manipulating struct lsm_prop Casey Schaufler
@ 2026-09-02 22:01   ` Casey Schaufler
  2026-09-02 22:10     ` sashiko-bot
  2026-09-03  6:10     ` John Johansen
  2026-09-02 22:01   ` [PATCH v2 5/7] Smack: " Casey Schaufler
                     ` (2 subsequent siblings)
  6 siblings, 2 replies; 22+ messages in thread
From: Casey Schaufler @ 2026-09-02 22:01 UTC (permalink / raw)
  To: casey, paul, linux-security-module, pablo, fw, phil
  Cc: linux-kernel, netfilter-devel, coreteam, jmorris, serge, keescook,
	john.johansen, penguin-kernel, stephen.smalley.work, selinux

Implement these hooks.

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

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 18dd28b2bb13..12614478b638 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -6946,6 +6946,13 @@ static int selinux_ismaclabel(const char *name)
 	return (strcmp(name, XATTR_SELINUX_SUFFIX) == 0);
 }
 
+static void selinux_update_lsmprop(struct lsm_prop *dest, struct lsm_prop *src,
+				   int lsmid)
+{
+	if (lsmid == LSM_ID_SELINUX || lsmid == LSM_ID_UNDEF)
+		dest->selinux.secid = src->selinux.secid;
+}
+
 static int selinux_secid_to_secctx(u32 secid, struct lsm_context *cp)
 {
 	u32 seclen;
@@ -6964,6 +6971,13 @@ static int selinux_secid_to_secctx(u32 secid, struct lsm_context *cp)
 	return seclen;
 }
 
+static int selinux_secctx_to_lsmprop(const char *secdata, u32 seclen,
+				     struct lsm_prop *prop)
+{
+	return security_context_to_sid(secdata, seclen, &prop->selinux.secid,
+				       GFP_KERNEL);
+}
+
 static int selinux_lsmprop_to_secctx(struct lsm_prop *prop,
 				     struct lsm_context *cp)
 {
@@ -7694,6 +7708,7 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = {
 
 	LSM_HOOK_INIT(ismaclabel, selinux_ismaclabel),
 	LSM_HOOK_INIT(secctx_to_secid, selinux_secctx_to_secid),
+	LSM_HOOK_INIT(secctx_to_lsmprop, selinux_secctx_to_lsmprop),
 	LSM_HOOK_INIT(release_secctx, selinux_release_secctx),
 	LSM_HOOK_INIT(inode_invalidate_secctx, selinux_inode_invalidate_secctx),
 	LSM_HOOK_INIT(inode_notifysecctx, selinux_inode_notifysecctx),
@@ -7812,6 +7827,7 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = {
 	LSM_HOOK_INIT(sem_alloc_security, selinux_sem_alloc_security),
 	LSM_HOOK_INIT(secid_to_secctx, selinux_secid_to_secctx),
 	LSM_HOOK_INIT(lsmprop_to_secctx, selinux_lsmprop_to_secctx),
+	LSM_HOOK_INIT(update_lsmprop, selinux_update_lsmprop),
 	LSM_HOOK_INIT(inode_getsecctx, selinux_inode_getsecctx),
 	LSM_HOOK_INIT(sk_alloc_security, selinux_sk_alloc_security),
 	LSM_HOOK_INIT(tun_dev_alloc_security, selinux_tun_dev_alloc_security),
-- 
2.54.0


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

* [PATCH v2 5/7] Smack: hooks for secctx_to_lsmprop and update_lsmprop
  2026-09-02 22:01 ` [PATCH v2 0/7] Change skb secmarks to x-array indexes Casey Schaufler
                     ` (3 preceding siblings ...)
  2026-09-02 22:01   ` [PATCH v2 4/7] SELinux: hooks for secctx_to_lsmprop and update_lsmprop Casey Schaufler
@ 2026-09-02 22:01   ` Casey Schaufler
  2026-09-02 22:17     ` sashiko-bot
  2026-09-03  6:15     ` John Johansen
  2026-09-02 22:01   ` [PATCH v2 6/7] Apparmor: " Casey Schaufler
  2026-09-02 22:01   ` [PATCH v2 7/7] net, lsm: Change skb secmarks to x-array indexes Casey Schaufler
  6 siblings, 2 replies; 22+ messages in thread
From: Casey Schaufler @ 2026-09-02 22:01 UTC (permalink / raw)
  To: casey, paul, linux-security-module, pablo, fw, phil
  Cc: linux-kernel, netfilter-devel, coreteam, jmorris, serge, keescook,
	john.johansen, penguin-kernel, stephen.smalley.work, selinux

Implement these hooks.

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

diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index ff115068c5c0..fcfadd5d9994 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -4909,6 +4909,37 @@ static int smack_lsmprop_to_secctx(struct lsm_prop *prop,
 	return smack_to_secctx(prop->smack.skp, cp);
 }
 
+/**
+ * smack_secctx_to_lsmprop - add the smack label to an lsmprop
+ * @secdata: smack label
+ * @seclen: how long label is
+ * @prop: where to put the result
+ *
+ * Exists for audit and networking code.
+ */
+static int smack_secctx_to_lsmprop(const char *secdata, u32 seclen,
+				   struct lsm_prop *prop)
+{
+	prop->smack.skp = smk_find_entry(secdata);
+
+	return 0;
+}
+
+/**
+ * smack_update_lsmprop - set the smack label in an lsmprop
+ * @dest: destination properties
+ * @src: source properties
+ * @lsmid: which LSM is relevant.
+ *
+ * Set the Smack entry in the @dest if appropriate.
+ */
+static void smack_update_lsmprop(struct lsm_prop *dest, struct lsm_prop *src,
+				 int lsmid)
+{
+	if (lsmid == LSM_ID_SMACK || lsmid == LSM_ID_UNDEF)
+		dest->smack.skp = src->smack.skp;
+}
+
 /**
  * smack_secctx_to_secid - return the secid for a smack label
  * @secdata: smack label
@@ -5269,6 +5300,8 @@ static struct security_hook_list smack_hooks[] __ro_after_init = {
 	LSM_HOOK_INIT(secid_to_secctx, smack_secid_to_secctx),
 	LSM_HOOK_INIT(lsmprop_to_secctx, smack_lsmprop_to_secctx),
 	LSM_HOOK_INIT(secctx_to_secid, smack_secctx_to_secid),
+	LSM_HOOK_INIT(secctx_to_lsmprop, smack_secctx_to_lsmprop),
+	LSM_HOOK_INIT(update_lsmprop, smack_update_lsmprop),
 	LSM_HOOK_INIT(inode_notifysecctx, smack_inode_notifysecctx),
 	LSM_HOOK_INIT(inode_setsecctx, smack_inode_setsecctx),
 	LSM_HOOK_INIT(inode_getsecctx, smack_inode_getsecctx),
-- 
2.54.0


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

* [PATCH v2 6/7] Apparmor: hooks for secctx_to_lsmprop and update_lsmprop
  2026-09-02 22:01 ` [PATCH v2 0/7] Change skb secmarks to x-array indexes Casey Schaufler
                     ` (4 preceding siblings ...)
  2026-09-02 22:01   ` [PATCH v2 5/7] Smack: " Casey Schaufler
@ 2026-09-02 22:01   ` Casey Schaufler
  2026-09-02 22:16     ` sashiko-bot
  2026-09-03  9:39     ` John Johansen
  2026-09-02 22:01   ` [PATCH v2 7/7] net, lsm: Change skb secmarks to x-array indexes Casey Schaufler
  6 siblings, 2 replies; 22+ messages in thread
From: Casey Schaufler @ 2026-09-02 22:01 UTC (permalink / raw)
  To: casey, paul, linux-security-module, pablo, fw, phil
  Cc: linux-kernel, netfilter-devel, coreteam, jmorris, serge, keescook,
	john.johansen, penguin-kernel, stephen.smalley.work, selinux

Implement these hooks.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
 security/apparmor/include/secid.h |  4 ++++
 security/apparmor/lsm.c           |  2 ++
 security/apparmor/secid.c         | 21 +++++++++++++++++++++
 3 files changed, 27 insertions(+)

diff --git a/security/apparmor/include/secid.h b/security/apparmor/include/secid.h
index 6025d3849cf8..ba7adf2fc09e 100644
--- a/security/apparmor/include/secid.h
+++ b/security/apparmor/include/secid.h
@@ -28,6 +28,10 @@ struct aa_label *aa_secid_to_label(u32 secid);
 int apparmor_secid_to_secctx(u32 secid, struct lsm_context *cp);
 int apparmor_lsmprop_to_secctx(struct lsm_prop *prop, struct lsm_context *cp);
 int apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
+int apparmor_secctx_to_lsmprop(const char *secdata, u32 seclen,
+			       struct lsm_prop *prop);
+void apparmor_update_lsmprop(struct lsm_prop *dest, struct lsm_prop *src,
+			     int lsmid);
 void apparmor_release_secctx(struct lsm_context *cp);
 
 
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 88d12e89d115..1f304b88eaf9 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -1766,6 +1766,8 @@ static struct security_hook_list apparmor_hooks[] __ro_after_init = {
 	LSM_HOOK_INIT(secid_to_secctx, apparmor_secid_to_secctx),
 	LSM_HOOK_INIT(lsmprop_to_secctx, apparmor_lsmprop_to_secctx),
 	LSM_HOOK_INIT(secctx_to_secid, apparmor_secctx_to_secid),
+	LSM_HOOK_INIT(secctx_to_lsmprop, apparmor_secctx_to_lsmprop),
+	LSM_HOOK_INIT(update_lsmprop, apparmor_update_lsmprop),
 	LSM_HOOK_INIT(release_secctx, apparmor_release_secctx),
 
 #ifdef CONFIG_IO_URING
diff --git a/security/apparmor/secid.c b/security/apparmor/secid.c
index 28caf66b9033..d35fdbf074e0 100644
--- a/security/apparmor/secid.c
+++ b/security/apparmor/secid.c
@@ -106,6 +106,27 @@ int apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
 	return 0;
 }
 
+int apparmor_secctx_to_lsmprop(const char *secdata, u32 seclen,
+			       struct lsm_prop *prop)
+{
+	struct aa_label *label;
+
+	label = aa_label_strn_parse(&root_ns->unconfined->label, secdata,
+				    seclen, GFP_KERNEL, false, false);
+	if (IS_ERR(label))
+		return PTR_ERR(label);
+	prop->apparmor.label = label;
+
+	return 0;
+}
+
+void apparmor_update_lsmprop(struct lsm_prop *dest, struct lsm_prop *src,
+			     int lsmid)
+{
+	if (lsmid == LSM_ID_APPARMOR || lsmid == LSM_ID_UNDEF)
+		dest->apparmor.label = src->apparmor.label;
+}
+
 void apparmor_release_secctx(struct lsm_context *cp)
 {
 	if (cp->id == LSM_ID_APPARMOR) {
-- 
2.54.0


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

* [PATCH v2 7/7] net, lsm: Change skb secmarks to x-array indexes
  2026-09-02 22:01 ` [PATCH v2 0/7] Change skb secmarks to x-array indexes Casey Schaufler
                     ` (5 preceding siblings ...)
  2026-09-02 22:01   ` [PATCH v2 6/7] Apparmor: " Casey Schaufler
@ 2026-09-02 22:01   ` Casey Schaufler
  2026-09-02 22:15     ` sashiko-bot
  2026-09-03  7:31     ` John Johansen
  6 siblings, 2 replies; 22+ messages in thread
From: Casey Schaufler @ 2026-09-02 22:01 UTC (permalink / raw)
  To: casey, paul, linux-security-module, pablo, fw, phil
  Cc: linux-kernel, netfilter-devel, coreteam, jmorris, serge, keescook,
	john.johansen, penguin-kernel, stephen.smalley.work, selinux

Maintain a xarray of lsm_prop structures which represent the
LSM security information passed via skb->secmark. Pass the xarray
index of the appropriate lsm_prop (the secxa) instead of an LSM
specific secid. Allow multiple LSMs to specify their components
in xarray entries, or create new entries as necessary.

Change uses of security_secctx_to_secid() to security_secctx_to_lsmprop()
in the netfilter and iptables code. Change security_secmark_relabel_packet()
to accept an lsm_prop pointer rather than a secid. Change secxa_set_secmark()
to update and create new entries as necessary.

Update the SELinux, Smack and AppArmor hooks that use secmarks to
expect a secxa xarray index instead of a secid.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
 include/linux/lsm_hook_defs.h    |  2 +-
 include/linux/lsm_secxa.h        |  2 +
 include/linux/security.h         |  4 +-
 net/netfilter/nfnetlink_queue.c  | 12 +++++-
 net/netfilter/nft_meta.c         | 15 ++++---
 net/netfilter/xt_SECMARK.c       | 16 +++++--
 security/apparmor/net.c          |  8 +++-
 security/lsm_secxa.c             | 20 ++++++++-
 security/security.c              |  6 +--
 security/selinux/hooks.c         | 71 +++++++++++++++++++++++++++-----
 security/smack/smack_lsm.c       | 10 ++++-
 security/smack/smack_netfilter.c | 10 +++--
 12 files changed, 141 insertions(+), 35 deletions(-)

diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index 679c40a8e127..8ecf07e0e3f0 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -371,7 +371,7 @@ LSM_HOOK(void, LSM_RET_VOID, inet_csk_clone, struct sock *newsk,
 	 const struct request_sock *req)
 LSM_HOOK(void, LSM_RET_VOID, inet_conn_established, struct sock *sk,
 	 struct sk_buff *skb)
-LSM_HOOK(int, 0, secmark_relabel_packet, u32 secid)
+LSM_HOOK(int, 0, secmark_relabel_packet, struct lsm_prop *prop)
 LSM_HOOK(void, LSM_RET_VOID, secmark_refcount_inc, void)
 LSM_HOOK(void, LSM_RET_VOID, secmark_refcount_dec, void)
 LSM_HOOK(void, LSM_RET_VOID, req_classify_flow, const struct request_sock *req,
diff --git a/include/linux/lsm_secxa.h b/include/linux/lsm_secxa.h
index 84b06c093460..5be9d64e67e4 100644
--- a/include/linux/lsm_secxa.h
+++ b/include/linux/lsm_secxa.h
@@ -7,6 +7,8 @@
 #ifndef __LINUX_LSM_SECXA_H
 #define __LINUX_LSM_SECXA_H
 
+#include <linux/types.h>
+
 #ifdef CONFIG_SECURITY
 
 struct lsm_prop;
diff --git a/include/linux/security.h b/include/linux/security.h
index 19adc19eb9af..ffbd1708065f 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -1715,7 +1715,7 @@ void security_inet_csk_clone(struct sock *newsk,
 			const struct request_sock *req);
 void security_inet_conn_established(struct sock *sk,
 			struct sk_buff *skb);
-int security_secmark_relabel_packet(u32 secid);
+int security_secmark_relabel_packet(struct lsm_prop *prop);
 void security_secmark_refcount_inc(void);
 void security_secmark_refcount_dec(void);
 int security_tun_dev_alloc_security(void **security);
@@ -1898,7 +1898,7 @@ static inline void security_inet_conn_established(struct sock *sk,
 {
 }
 
-static inline int security_secmark_relabel_packet(u32 secid)
+static inline int security_secmark_relabel_packet(struct lsm_prop *prop)
 {
 	return 0;
 }
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index b8aaf39cb4d8..ebab037edc6b 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -32,6 +32,7 @@
 #include <linux/cgroup-defs.h>
 #include <linux/rhashtable.h>
 #include <linux/jhash.h>
+#include <linux/lsm_secxa.h>
 #include <net/gso.h>
 #include <net/sock.h>
 #include <net/tcp_states.h>
@@ -606,8 +607,15 @@ static int nfqnl_get_sk_secctx(struct sk_buff *skb, struct lsm_context *ctx)
 {
 	int seclen = 0;
 #if IS_ENABLED(CONFIG_NETWORK_SECMARK)
-	if (skb->secmark)
-		seclen = security_secid_to_secctx(skb->secmark, ctx);
+	struct lsm_prop *prop;
+	int rc;
+
+	if (skb->secmark) {
+		rc = secxa_get_lsmprop(&prop, skb->secmark);
+		if (rc)
+			return 0;
+		seclen = security_lsmprop_to_secctx(prop, ctx, LSM_ID_UNDEF);
+	}
 #endif
 	return seclen;
 }
diff --git a/net/netfilter/nft_meta.c b/net/netfilter/nft_meta.c
index bd0f7a0931f4..664191dfa4b2 100644
--- a/net/netfilter/nft_meta.c
+++ b/net/netfilter/nft_meta.c
@@ -927,21 +927,24 @@ static const struct nla_policy nft_secmark_policy[NFTA_SECMARK_MAX + 1] = {
 
 static int nft_secmark_compute_secid(struct nft_secmark *priv)
 {
-	u32 tmp_secid = 0;
+	struct lsm_prop tmp_prop;
+	u32 secxa = 0;
 	int err;
 
-	err = security_secctx_to_secid(priv->ctx, strlen(priv->ctx), &tmp_secid);
+	err = security_secctx_to_lsmprop(priv->ctx, strlen(priv->ctx),
+					 &tmp_prop, LSM_ID_UNDEF);
 	if (err)
 		return err;
 
-	if (!tmp_secid)
-		return -ENOENT;
+	err = secxa_from_lsmprop(&tmp_prop, &secxa);
+	if (err)
+		return err;
 
-	err = security_secmark_relabel_packet(tmp_secid);
+	err = security_secmark_relabel_packet(&tmp_prop);
 	if (err)
 		return err;
 
-	priv->secid = tmp_secid;
+	priv->secid = secxa;
 	return 0;
 }
 
diff --git a/net/netfilter/xt_SECMARK.c b/net/netfilter/xt_SECMARK.c
index ea67aa92ddc2..05b023a7c576 100644
--- a/net/netfilter/xt_SECMARK.c
+++ b/net/netfilter/xt_SECMARK.c
@@ -43,13 +43,15 @@ secmark_tg(struct sk_buff *skb, const struct xt_secmark_target_info_v1 *info)
 
 static int checkentry_lsm(struct xt_secmark_target_info_v1 *info)
 {
+	struct lsm_prop prop;
 	int err;
 
 	info->secctx[SECMARK_SECCTX_MAX - 1] = '\0';
 	info->secid = 0;
 
-	err = security_secctx_to_secid(info->secctx, strlen(info->secctx),
-				       &info->secid);
+	err = security_secctx_to_lsmprop(info->secctx, strlen(info->secctx),
+					 &prop, LSM_ID_UNDEF);
+
 	if (err) {
 		if (err == -EINVAL)
 			pr_info_ratelimited("invalid security context \'%s\'\n",
@@ -57,18 +59,24 @@ static int checkentry_lsm(struct xt_secmark_target_info_v1 *info)
 		return err;
 	}
 
-	if (!info->secid) {
+	if (!lsmprop_is_set(&prop)) {
 		pr_info_ratelimited("unable to map security context \'%s\'\n",
 				    info->secctx);
 		return -ENOENT;
 	}
 
-	err = security_secmark_relabel_packet(info->secid);
+	err = security_secmark_relabel_packet(&prop);
 	if (err) {
 		pr_info_ratelimited("unable to obtain relabeling permission\n");
 		return err;
 	}
 
+	err = secxa_from_lsmprop(&prop, &info->secid);
+	if (err) {
+		pr_info_ratelimited("unable to obtain secmark\n");
+		return err;
+	}
+
 	security_secmark_refcount_inc();
 	return 0;
 }
diff --git a/security/apparmor/net.c b/security/apparmor/net.c
index cf590dd08540..e26e15c2d947 100644
--- a/security/apparmor/net.c
+++ b/security/apparmor/net.c
@@ -8,6 +8,7 @@
  * Copyright 2009-2017 Canonical Ltd.
  */
 
+#include <linux/lsm_secxa.h>
 #include "include/af_unix.h"
 #include "include/apparmor.h"
 #include "include/audit.h"
@@ -365,12 +366,17 @@ static int aa_secmark_perm(struct aa_profile *profile, u32 request, u32 secid,
 			   struct apparmor_audit_data *ad)
 {
 	int i, ret;
+	struct lsm_prop *prop;
 	struct aa_perms perms = { };
 	struct aa_ruleset *rules = profile->label.rules[0];
 
 	if (rules->secmark_count == 0)
 		return 0;
 
+	ret = secxa_get_lsmprop(&prop, secid);
+	if (ret)
+		return ret;
+
 	for (i = 0; i < rules->secmark_count; i++) {
 		if (!rules->secmark[i].secid) {
 			ret = apparmor_secmark_init(&rules->secmark[i]);
@@ -378,7 +384,7 @@ static int aa_secmark_perm(struct aa_profile *profile, u32 request, u32 secid,
 				return ret;
 		}
 
-		if (rules->secmark[i].secid == secid ||
+		if (rules->secmark[i].secid == prop->apparmor.label->secid ||
 		    rules->secmark[i].secid == AA_SECID_WILDCARD) {
 			if (rules->secmark[i].deny)
 				perms.deny = ALL_PERMS_MASK;
diff --git a/security/lsm_secxa.c b/security/lsm_secxa.c
index ccbe78095d70..f0702ac5601d 100644
--- a/security/lsm_secxa.c
+++ b/security/lsm_secxa.c
@@ -103,7 +103,25 @@ EXPORT_SYMBOL(secxa_from_lsmprop);
  */
 void secxa_set_secmark(struct sk_buff *skb, u32 secxa)
 {
-	if (!skb->secmark)
+	struct lsm_prop *olp;
+	struct lsm_prop *nlp;
+	struct lsm_prop prop;
+	u32 tsecxa;
+	int rc;
+
+	if (!skb->secmark) {
 		skb->secmark = secxa;
+		return;
+	}
+
+	olp = xa_load(&secxa_xa, skb->secmark);
+	nlp = xa_load(&secxa_xa, secxa);
+
+	prop = *olp;
+	security_update_lsmprop(&prop, nlp, LSM_ID_UNDEF);
+
+	rc = secxa_from_lsmprop(&prop, &tsecxa);
+	if (!rc)
+		skb->secmark = tsecxa;
 }
 EXPORT_SYMBOL(secxa_set_secmark);
diff --git a/security/security.c b/security/security.c
index 1dec0037370b..e80e7823ce14 100644
--- a/security/security.c
+++ b/security/security.c
@@ -4646,15 +4646,15 @@ EXPORT_SYMBOL(security_inet_conn_established);
 
 /**
  * security_secmark_relabel_packet() - Check if setting a secmark is allowed
- * @secid: new secmark value
+ * @lsmprop: new secmark value
  *
  * Check if the process should be allowed to relabel packets to @secid.
  *
  * Return: Returns 0 if permission is granted.
  */
-int security_secmark_relabel_packet(u32 secid)
+int security_secmark_relabel_packet(struct lsm_prop *prop)
 {
-	return call_int_hook(secmark_relabel_packet, secid);
+	return call_int_hook(secmark_relabel_packet, prop);
 }
 EXPORT_SYMBOL(security_secmark_relabel_packet);
 
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 12614478b638..bf832eff0b92 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -94,6 +94,7 @@
 #include <linux/io_uring/cmd.h>
 #include <uapi/linux/lsm.h>
 #include <linux/memfd.h>
+#include <linux/lsm_secxa.h>
 
 #include "initcalls.h"
 #include "avc.h"
@@ -5414,7 +5415,16 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
 		return err;
 
 	if (selinux_secmark_enabled()) {
-		err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
+		struct lsm_prop *prop;
+		u32 secmark = 0;
+
+		if (skb->secmark) {
+			err = secxa_get_lsmprop(&prop, skb->secmark);
+			if (!err)
+				secmark = prop->selinux.secid;
+		}
+
+		err = avc_has_perm(sk_sid, secmark, SECCLASS_PACKET,
 				   PACKET__RECV, &ad);
 		if (err)
 			return err;
@@ -5483,7 +5493,15 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
 	}
 
 	if (secmark_active) {
-		err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
+		struct lsm_prop *prop;
+		u32 secmark = 0;
+
+		if (skb->secmark) {
+			err = secxa_get_lsmprop(&prop, skb->secmark);
+			if (!err)
+				secmark = prop->selinux.secid;
+		}
+		err = avc_has_perm(sk_sid, secmark, SECCLASS_PACKET,
 				   PACKET__RECV, &ad);
 		if (err)
 			return err;
@@ -5885,10 +5903,10 @@ static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
 	selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid);
 }
 
-static int selinux_secmark_relabel_packet(u32 sid)
+static int selinux_secmark_relabel_packet(struct lsm_prop *lsmprop)
 {
-	return avc_has_perm(current_sid(), sid, SECCLASS_PACKET, PACKET__RELABELTO,
-			    NULL);
+	return avc_has_perm(current_sid(), lsmprop->selinux.secid,
+			    SECCLASS_PACKET, PACKET__RELABELTO, NULL);
 }
 
 static void selinux_secmark_refcount_inc(void)
@@ -6016,10 +6034,21 @@ static unsigned int selinux_ip_forward(void *priv, struct sk_buff *skb,
 		}
 	}
 
-	if (secmark_active)
-		if (avc_has_perm(peer_sid, skb->secmark,
+	if (secmark_active) {
+		struct lsm_prop *prop;
+		u32 secmark = 0;
+		int err;
+
+		if (skb->secmark) {
+			err = secxa_get_lsmprop(&prop, skb->secmark);
+			if (!err)
+				secmark = prop->selinux.secid;
+		}
+
+		if (avc_has_perm(peer_sid, secmark,
 				 SECCLASS_PACKET, PACKET__FORWARD_IN, &ad))
 			return NF_DROP;
+	}
 
 	if (netlbl_enabled())
 		/* we do this in the FORWARD path and not the POST_ROUTING
@@ -6093,10 +6122,20 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
 	if (selinux_parse_skb(skb, &ad, NULL, 0, &proto))
 		return NF_DROP;
 
-	if (selinux_secmark_enabled())
-		if (avc_has_perm(sksec->sid, skb->secmark,
+	if (selinux_secmark_enabled()) {
+		struct lsm_prop *prop;
+		u32 secmark = 0;
+		int err;
+
+		if (skb->secmark) {
+			err = secxa_get_lsmprop(&prop, skb->secmark);
+			if (!err)
+				secmark = prop->selinux.secid;
+		}
+		if (avc_has_perm(sksec->sid, secmark,
 				 SECCLASS_PACKET, PACKET__SEND, &ad))
 			return NF_DROP_ERR(-ECONNREFUSED);
+	}
 
 	if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto))
 		return NF_DROP_ERR(-ECONNREFUSED);
@@ -6215,10 +6254,20 @@ static unsigned int selinux_ip_postroute(void *priv,
 	if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL))
 		return NF_DROP;
 
-	if (secmark_active)
-		if (avc_has_perm(peer_sid, skb->secmark,
+	if (secmark_active) {
+		struct lsm_prop *prop;
+		u32 secmark = 0;
+		int err;
+
+		if (skb->secmark) {
+			err = secxa_get_lsmprop(&prop, skb->secmark);
+			if (!err)
+				secmark = prop->selinux.secid;
+		}
+		if (avc_has_perm(peer_sid, secmark,
 				 SECCLASS_PACKET, secmark_perm, &ad))
 			return NF_DROP_ERR(-ECONNREFUSED);
+	}
 
 	if (peerlbl_active) {
 		u32 if_sid;
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index fcfadd5d9994..79140e6829a4 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -42,6 +42,7 @@
 #include <linux/fs_context.h>
 #include <linux/fs_parser.h>
 #include <linux/watch_queue.h>
+#include <linux/lsm_secxa.h>
 #include <linux/io_uring/cmd.h>
 #include <uapi/linux/lsm.h>
 #include "smack.h"
@@ -4189,10 +4190,17 @@ 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)
 {
+	struct lsm_prop *prop;
+	int rc;
+
 	if (skb == NULL || skb->secmark == 0)
 		return NULL;
 
-	return smack_from_secid(skb->secmark);
+	rc = secxa_get_lsmprop(&prop, skb->secmark);
+	if (prop)
+		return prop->smack.skp;
+
+	return NULL;
 }
 #else
 static inline struct smack_known *smack_from_skb(struct sk_buff *skb)
diff --git a/security/smack/smack_netfilter.c b/security/smack/smack_netfilter.c
index b363c42f252e..0378f74aa22b 100644
--- a/security/smack/smack_netfilter.c
+++ b/security/smack/smack_netfilter.c
@@ -24,13 +24,17 @@ static unsigned int smack_ip_output(void *priv,
 				    const struct nf_hook_state *state)
 {
 	struct sock *sk = skb_to_full_sk(skb);
+	struct lsm_prop prop = { };
 	struct socket_smack *ssp;
-	struct smack_known *skp;
+	u32 secxa;
+	int rc;
 
 	if (sk) {
 		ssp = smack_sock(sk);
-		skp = ssp->smk_out;
-		secxa_set_secmark(skb, skp->smk_secid);
+		prop.smack.skp = ssp->smk_out;
+		rc = secxa_from_lsmprop(&prop, &secxa);
+		if (!rc)
+			secxa_set_secmark(skb, secxa);
 	}
 
 	return NF_ACCEPT;
-- 
2.54.0


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

* Re: [PATCH v2 4/7] SELinux: hooks for secctx_to_lsmprop and update_lsmprop
  2026-09-02 22:01   ` [PATCH v2 4/7] SELinux: hooks for secctx_to_lsmprop and update_lsmprop Casey Schaufler
@ 2026-09-02 22:10     ` sashiko-bot
  2026-09-03  6:10     ` John Johansen
  1 sibling, 0 replies; 22+ messages in thread
From: sashiko-bot @ 2026-09-02 22:10 UTC (permalink / raw)
  Cc: selinux

> Implement these hooks.
> 
> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>

Sashiko has reviewed this patch and found no issues. It looks great!

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260902220150.18586-1-casey@schaufler-ca.com?part=4


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

* Re: [PATCH v2 1/7] net, smack: Create a function to set secmarks
  2026-09-02 22:01   ` [PATCH v2 1/7] net, smack: Create a function to set secmarks Casey Schaufler
@ 2026-09-02 22:13     ` sashiko-bot
  2026-09-03  5:35     ` John Johansen
  1 sibling, 0 replies; 22+ messages in thread
From: sashiko-bot @ 2026-09-02 22:13 UTC (permalink / raw)
  Cc: selinux

> Rather than open coding assignments to skb->secmark, use a helper function
> secxa_set_secmark(). This allows for a case where assigning a secmark
> is more complex than a simple assignment. The version of the function
> here does the legacy simple assignment.
> 
> Change the functions that currently assign values to skb->secmark to
> use this function.
> 
> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>

Sashiko has reviewed this patch and found no issues. It looks great!

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260902220150.18586-1-casey@schaufler-ca.com?part=1


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

* Re: [PATCH v2 7/7] net, lsm: Change skb secmarks to x-array indexes
  2026-09-02 22:01   ` [PATCH v2 7/7] net, lsm: Change skb secmarks to x-array indexes Casey Schaufler
@ 2026-09-02 22:15     ` sashiko-bot
  2026-09-03  7:31     ` John Johansen
  1 sibling, 0 replies; 22+ messages in thread
From: sashiko-bot @ 2026-09-02 22:15 UTC (permalink / raw)
  Cc: selinux

Thank you for your contribution! Sashiko AI review found 8 potential issue(s) to consider:
- [Critical] The function smack_from_skb() checks an uninitialized pointer instead of the error code after calling secxa_get_lsmprop(), leading to a wild pointer dereference.
- [Critical] The first lsm_prop entry will be allocated ID 0, which is treated as 'no secmark', bypassing security checks.
- [Critical] AppArmor's secmark hook unconditionally dereferences `prop->apparmor.label`, which can be NULL if the entry was created by another LSM.
- [High] secxa_set_secmark() unconditionally dereferences pointers returned by xa_load() without checking for NULL.
- [High] Stack-allocated `struct lsm_prop` variables are passed uninitialized to `secxa_from_lsmprop()`, causing `memcmp()` to read stack garbage, resulting in deduplication failure and memory leaks.
- [High] A TOCTOU race condition in secxa_from_lsmprop causes duplicate xarray entries and memory leaks under concurrent load.
- [High] Per-packet O(N) linear scan over the global secmark xarray introduces a massive performance bottleneck and DoS vector.
- [Medium] Missing garbage collection for dynamically allocated `secxa_xa` xarray entries causes a permanent memory leak.
--

commit a49336f616a25ecd3f9284efec92c647cceaa92a
Author: Casey Schaufler <casey@schaufler-ca.com>

net, lsm: Change skb secmarks to x-array indexes
    
Maintain a xarray of lsm_prop structures which represent the
LSM security information passed via skb->secmark. Pass the xarray
index of the appropriate lsm_prop (the secxa) instead of an LSM
specific secid. Allow multiple LSMs to specify their components
in xarray entries, or create new entries as necessary.

> diff --git a/net/netfilter/nft_meta.c b/net/netfilter/nft_meta.c
> index bd0f7a0931f44..664191dfa4b29 100644
> --- a/net/netfilter/nft_meta.c
> +++ b/net/netfilter/nft_meta.c
> @@ -927,21 +927,24 @@ static const struct nla_policy nft_secmark_policy[NFTA_SECMARK_MAX + 1] = {
>  
>  static int nft_secmark_compute_secid(struct nft_secmark *priv)
>  {
> -	u32 tmp_secid = 0;
> +	struct lsm_prop tmp_prop;

[Severity: High]
Can this pass an uninitialized stack variable to memcmp?

tmp_prop is allocated on the stack but not zero-initialized.
security_secctx_to_lsmprop populates only the active LSM's fields, leaving
the remainder of the struct as stack garbage. When secxa_from_lsmprop is
subsequently called, it uses memcmp on the entire struct. The stack garbage
will cause the strict binary comparison to fail, failing to match identical
logical entries and forcing a new allocation every time.

> +	u32 secxa = 0;
>  	int err;
>  
> -	err = security_secctx_to_secid(priv->ctx, strlen(priv->ctx), &tmp_secid);
> +	err = security_secctx_to_lsmprop(priv->ctx, strlen(priv->ctx),
> +					 &tmp_prop, LSM_ID_UNDEF);

[ ... ]

> diff --git a/net/netfilter/xt_SECMARK.c b/net/netfilter/xt_SECMARK.c
> index ea67aa92ddc2f..05b023a7c5760 100644
> --- a/net/netfilter/xt_SECMARK.c
> +++ b/net/netfilter/xt_SECMARK.c
> @@ -43,13 +43,15 @@ secmark_tg(struct sk_buff *skb, const struct xt_secmark_target_info_v1 *info)
>  
>  static int checkentry_lsm(struct xt_secmark_target_info_v1 *info)
>  {
> +	struct lsm_prop prop;

[Severity: High]
Is this stack variable prop also uninitialized?

It appears to suffer from the exact same memcmp garbage-read issue described
in nft_secmark_compute_secid.

>  	int err;
>  
>  	info->secctx[SECMARK_SECCTX_MAX - 1] = '\0';
>  	info->secid = 0;
>  
> -	err = security_secctx_to_secid(info->secctx, strlen(info->secctx),
> -				       &info->secid);
> +	err = security_secctx_to_lsmprop(info->secctx, strlen(info->secctx),
> +					 &prop, LSM_ID_UNDEF);
> +

[ ... ]

> +	err = secxa_from_lsmprop(&prop, &info->secid);

[Severity: Critical]
Could this inadvertently bypass security checks for the first loaded rule?

Since secxa_from_lsmprop allocates an index using xa_limit_31b
([0, 0x7fffffff]), the very first allocated entry will receive index 0.
Throughout the networking and LSM stacks, a secmark value of 0 is explicitly
treated as no secmark. This means the first secmark rule loaded into the
system will silently fail to enforce security marks on matching traffic.

[Severity: High]
Is there a memory leak and duplicate xarray entry issue when called
concurrently?

secxa_from_lsmprop performs a lockless check-then-act sequence: it searches
the xarray, and if no match is found, allocates and inserts a new entry. If
multiple threads process the same new lsm_prop concurrently, they can all
observe a miss and insert their own duplicate entries at different indices.

[Severity: Medium]
Will this dynamically allocated xarray entry permanently leak memory?

secxa_from_lsmprop dynamically allocates new entries via kzalloc and adds
them to the global xarray, but there appears to be no corresponding mechanism
(like xa_erase and kfree) to remove and free these entries when the
associated netfilter rules are deleted.

> +	if (err) {
> +		pr_info_ratelimited("unable to obtain secmark\n");
> +		return err;
> +	}
> +
>  	security_secmark_refcount_inc();
>  	return 0;
>  }

[ ... ]

> diff --git a/security/apparmor/net.c b/security/apparmor/net.c
> index cf590dd08540c..e26e15c2d9473 100644
> --- a/security/apparmor/net.c
> +++ b/security/apparmor/net.c
> @@ -378,7 +384,7 @@ static int aa_secmark_perm(struct aa_profile *profile, u32 request, u32 secid,
>  				return ret;
>  		}
>  
> -		if (rules->secmark[i].secid == secid ||
> +		if (rules->secmark[i].secid == prop->apparmor.label->secid ||

[Severity: Critical]
Might this unconditionally dereference a NULL pointer?

If an skb is labeled by an LSM other than AppArmor (e.g., SELinux or Smack),
the lsm_prop entry in the xarray will have a NULL apparmor.label. When
AppArmor evaluates this packet, it will unconditionally access
prop->apparmor.label->secid and cause a kernel panic.

>  		    rules->secmark[i].secid == AA_SECID_WILDCARD) {
>  			if (rules->secmark[i].deny)
>  				perms.deny = ALL_PERMS_MASK;

[ ... ]

> diff --git a/security/lsm_secxa.c b/security/lsm_secxa.c
> index ccbe78095d703..f0702ac5601dd 100644
> --- a/security/lsm_secxa.c
> +++ b/security/lsm_secxa.c
> @@ -103,7 +103,25 @@ EXPORT_SYMBOL(secxa_from_lsmprop);
>   */
>  void secxa_set_secmark(struct sk_buff *skb, u32 secxa)
>  {
> -	if (!skb->secmark)
> +	struct lsm_prop *olp;
> +	struct lsm_prop *nlp;
> +	struct lsm_prop prop;
> +	u32 tsecxa;
> +	int rc;
> +
> +	if (!skb->secmark) {
>  		skb->secmark = secxa;
> +		return;
> +	}
> +
> +	olp = xa_load(&secxa_xa, skb->secmark);
> +	nlp = xa_load(&secxa_xa, secxa);
> +
> +	prop = *olp;

[Severity: High]
Are the pointers from xa_load dereferenced without checking for NULL?

If skb->secmark or secxa is an invalid xarray index, xa_load will return
NULL. The function immediately dereferences olp (prop = *olp) and passes
nlp to security_update_lsmprop, which also dereferences it, resulting in a
kernel panic.

> +	security_update_lsmprop(&prop, nlp, LSM_ID_UNDEF);
> +
> +	rc = secxa_from_lsmprop(&prop, &tsecxa);
> +	if (!rc)
> +		skb->secmark = tsecxa;
>  }
>  EXPORT_SYMBOL(secxa_set_secmark);

[ ... ]

> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
> index fcfadd5d99941..79140e6829a47 100644
> --- a/security/smack/smack_lsm.c
> +++ b/security/smack/smack_lsm.c
> @@ -4189,10 +4190,17 @@ 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)
>  {
> +	struct lsm_prop *prop;
> +	int rc;
> +
>  	if (skb == NULL || skb->secmark == 0)
>  		return NULL;
>  
> -	return smack_from_secid(skb->secmark);
> +	rc = secxa_get_lsmprop(&prop, skb->secmark);
> +	if (prop)
> +		return prop->smack.skp;

[Severity: Critical]
Are we checking an uninitialized pointer instead of the error code here?

If an skb has a non-zero secmark that is not found in the xarray,
secxa_get_lsmprop returns an error without initializing prop. The code
ignores rc and checks if prop is valid. This will evaluate uninitialized
stack memory and potentially cause a wild pointer dereference when accessing
prop->smack.skp.

> +
> +	return NULL;
>  }

[ ... ]

> diff --git a/security/smack/smack_netfilter.c b/security/smack/smack_netfilter.c
> index b363c42f252e8..0378f74aa22bc 100644
> --- a/security/smack/smack_netfilter.c
> +++ b/security/smack/smack_netfilter.c
> @@ -24,13 +24,17 @@ static unsigned int smack_ip_output(void *priv,
>  				    struct sk_buff *skb,
>  				    const struct nf_hook_state *state)
>  {
>  	struct sock *sk = skb_to_full_sk(skb);
> +	struct lsm_prop prop = { };
>  	struct socket_smack *ssp;
> -	struct smack_known *skp;
> +	u32 secxa;
> +	int rc;
>  
>  	if (sk) {
>  		ssp = smack_sock(sk);
> -		skp = ssp->smk_out;
> -		secxa_set_secmark(skb, skp->smk_secid);
> +		prop.smack.skp = ssp->smk_out;
> +		rc = secxa_from_lsmprop(&prop, &secxa);

[Severity: High]
Will this introduce a massive performance bottleneck on the outbound network
fast-path?

For every outbound packet, smack_ip_output calls secxa_from_lsmprop. Because
secxa_from_lsmprop linearly scans the entire global secxa_xa xarray using
xa_for_each to find a match, this could cause severe performance degradation
and high CPU usage under network load.

> +		if (!rc)
> +			secxa_set_secmark(skb, secxa);
>  	}
>  
>  	return NF_ACCEPT;

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260902220150.18586-1-casey@schaufler-ca.com?part=7

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

* Re: [PATCH v2 3/7] LSM: Two hooks for manipulating struct lsm_prop
  2026-09-02 22:01   ` [PATCH v2 3/7] LSM: Two hooks for manipulating struct lsm_prop Casey Schaufler
@ 2026-09-02 22:16     ` sashiko-bot
  2026-09-03  9:40     ` John Johansen
  1 sibling, 0 replies; 22+ messages in thread
From: sashiko-bot @ 2026-09-02 22:16 UTC (permalink / raw)
  Cc: selinux

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] The wrapper security_secctx_to_lsmprop() fails to zero-initialize the output struct lsm_prop, risking uninitialized memory usage.
- [Medium] Inconsistent default return value for unsupported security_secctx_to_lsmprop operation (-EINVAL vs -EOPNOTSUPP).
- [Low] The `update_lsmprop` hook leaks framework routing details by requiring `lsmid` as a parameter, forcing LSM implementations to duplicate dispatch filtering instead of handling it centrally in the LSM framework.
--

commit 945240d1e544dee2c2c0632c7b84efeac1548fde
Author: Casey Schaufler <casey@schaufler-ca.com>

LSM: Two hooks for manipulating struct lsm_prop

This commit introduces two new hooks, update_lsmprop and secctx_to_lsmprop,
which allow updating the properties of a specified LSM and setting the 
lsm_prop field based on a passed security context.

> diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
> index 65c9609ec2077..679c40a8e1275 100644
> --- a/include/linux/lsm_hook_defs.h
> +++ b/include/linux/lsm_hook_defs.h
[ ... ]
> @@ -305,7 +305,11 @@ LSM_HOOK(int, 0, ismaclabel, const char *name)
>  LSM_HOOK(int, -EOPNOTSUPP, secid_to_secctx, u32 secid, struct lsm_context *cp)
>  LSM_HOOK(int, -EOPNOTSUPP, lsmprop_to_secctx, struct lsm_prop *prop,
>  	 struct lsm_context *cp)
> +LSM_HOOK(void, LSM_RET_VOID, update_lsmprop, struct lsm_prop *dest,
> +	 struct lsm_prop *src, int lsmid)

[Severity: Low]
Does exposing lsmid directly to the update_lsmprop hook break the
encapsulation of the LSM routing mechanism? In the LSM framework, targeted
hooks usually handle lsmid filtering centrally in security.c using an
explicit loop (e.g., lsmprop_to_secctx). By broadcasting with call_void_hook
and passing lsmid, individual LSMs are forced to implement duplicate
filtering rather than having it handled by the framework.

>  LSM_HOOK(int, 0, secctx_to_secid, const char *secdata, u32 seclen, u32 *secid)
> +LSM_HOOK(int, -EINVAL, secctx_to_lsmprop, const char *secdata, u32 seclen,
> +	 struct lsm_prop *prop)

[Severity: Medium]
Is -EINVAL the correct default return value here? The inline stub for
CONFIG_SECURITY=n in security.h returns -EOPNOTSUPP. Returning -EINVAL when
no LSM handles the hook might incorrectly imply a parsing error rather than
a lack of support, potentially altering user-space visible error codes
(e.g., returning -EINVAL instead of -ENOENT or -EOPNOTSUPP from
xtables/nftables).

>  LSM_HOOK(void, LSM_RET_VOID, release_secctx, struct lsm_context *cp)
>  LSM_HOOK(void, LSM_RET_VOID, inode_invalidate_secctx, struct inode *inode)
>  LSM_HOOK(int, 0, inode_notifysecctx, struct inode *inode, void *ctx, u32 ctxlen)
> diff --git a/security/security.c b/security/security.c
> index 71aea8fdf0142..1dec0037370ba 100644
> --- a/security/security.c
> +++ b/security/security.c
[ ... ]
> @@ -3982,6 +3989,31 @@ int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
>  }
>  EXPORT_SYMBOL(security_secctx_to_secid);
>  
> +/**
> + * security_secctx_to_lsmprop() - Convert a secctx to a lsmprop
> + * @secdata: secctx
> + * @seclen: length of secctx
> + * @prop: prop
> + * @lsmid: which LSM the context is appropriate to.
> + *
> + * Convert security context to an lsmprop.
> + *
> + * Return: Returns 0 on success, error on failure.
> + */
> +int security_secctx_to_lsmprop(const char *secdata, u32 seclen,
> +			       struct lsm_prop *prop, int lsmid)
> +{
> +	struct lsm_static_call *scall;
> +
> +	lsm_for_each_hook(scall, secctx_to_lsmprop) {

[Severity: High]
Should this function zero-initialize the output struct lsm_prop (perhaps
via lsmprop_init) before calling the hooks?

Callers typically allocate struct lsm_prop on the stack without
initialization, and the active LSM hook only populates its own specific
field. This leaves the rest of the struct as uninitialized stack garbage.

If callers pass this partially initialized structure to secxa_from_lsmprop(),
the memcmp() and kmemdup() operations on the entire struct will evaluate the
stack garbage. This could leak kernel stack memory into the secxa_xa xarray
heap object and cause identical contexts to mismatch, potentially leading to
unbounded memory allocation and a denial of service.

> +		if (lsmid != LSM_ID_UNDEF && lsmid != scall->hl->lsmid->id)
> +			continue;
> +		return scall->hl->hook.secctx_to_lsmprop(secdata, seclen, prop);
> +	}
> +	return LSM_RET_DEFAULT(secctx_to_lsmprop);
> +}
> +EXPORT_SYMBOL(security_secctx_to_lsmprop);
> +

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260902220150.18586-1-casey@schaufler-ca.com?part=3

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

* Re: [PATCH v2 6/7] Apparmor: hooks for secctx_to_lsmprop and update_lsmprop
  2026-09-02 22:01   ` [PATCH v2 6/7] Apparmor: " Casey Schaufler
@ 2026-09-02 22:16     ` sashiko-bot
  2026-09-03  9:39     ` John Johansen
  1 sibling, 0 replies; 22+ messages in thread
From: sashiko-bot @ 2026-09-02 22:16 UTC (permalink / raw)
  Cc: selinux

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:

New issues:
- [High] Memory leak of `aa_label` reference in `apparmor_secctx_to_lsmprop()`.

Pre-existing issues:
- [High] Memory leak of `aa_label` reference in `apparmor_secctx_to_secid()`.
--

commit 1e8503b950ea8fae325db00bc26a72d7c257c11e
Author: Casey Schaufler <casey@schaufler-ca.com>

Apparmor: hooks for secctx_to_lsmprop and update_lsmprop

Implement these hooks.

> diff --git a/security/apparmor/secid.c b/security/apparmor/secid.c
> index 28caf66b90335..d35fdbf074e05 100644
> --- a/security/apparmor/secid.c
> +++ b/security/apparmor/secid.c
> @@ -106,6 +106,27 @@ int apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
>  	return 0;
>  }

[Severity: High]
This is a pre-existing issue, but does this function leak the reference
to the aa_label?

Looking at the body of the function:

int apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
{
	struct aa_label *label;

	label = aa_label_strn_parse(&root_ns->unconfined->label, secdata,
				    seclen, GFP_KERNEL, false, false);
	if (IS_ERR(label))
		return PTR_ERR(label);
	*secid = label->secid;

	return 0;
}

It looks like aa_label_strn_parse() returns an aa_label with an
incremented reference count, and apparmor_secctx_to_secid() extracts
label->secid and returns without dropping the reference.

This can be triggered by unprivileged users in a user and network namespace
by repeatedly adding secmark rules (via xt_SECMARK) with an existing
profile name. This allows an unprivileged user to leak references until
refcount_t saturation, triggering kernel warnings and potential crashes
under panic_on_warn.

>  
> +int apparmor_secctx_to_lsmprop(const char *secdata, u32 seclen,
> +			       struct lsm_prop *prop)
> +{
> +	struct aa_label *label;
> +
> +	label = aa_label_strn_parse(&root_ns->unconfined->label, secdata,
> +				    seclen, GFP_KERNEL, false, false);
> +	if (IS_ERR(label))
> +		return PTR_ERR(label);
> +	prop->apparmor.label = label;
> +
> +	return 0;
> +}

[Severity: High]
Does this code leak the aa_label reference?

Similar to apparmor_secctx_to_secid(), aa_label_strn_parse() returns an
aa_label with an incremented reference count. The label pointer is assigned
to prop->apparmor.label but returns without dropping the reference. Because
the lsm_prop struct acts as a simple value container and lacks any release
lifecycle hook across the LSM framework, this reference is permanently leaked.

An unprivileged user can trigger this whenever security_secctx_to_lsmprop()
is called, such as by nft_secmark_compute_secid() when adding a netfilter
secmark rule. By gaining CAP_NET_ADMIN in a user and network namespace, they
can repeatedly add netfilter rules and leak references to an existing AppArmor
profile until the refcount_t saturates.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260902220150.18586-1-casey@schaufler-ca.com?part=6

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

* Re: [PATCH v2 5/7] Smack: hooks for secctx_to_lsmprop and update_lsmprop
  2026-09-02 22:01   ` [PATCH v2 5/7] Smack: " Casey Schaufler
@ 2026-09-02 22:17     ` sashiko-bot
  2026-09-03  6:15     ` John Johansen
  1 sibling, 0 replies; 22+ messages in thread
From: sashiko-bot @ 2026-09-02 22:17 UTC (permalink / raw)
  Cc: selinux

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Critical] smack_secctx_to_lsmprop unconditionally returns success even when a label is unrecognized, setting prop->smack.skp to NULL which causes subsequent LSM hooks to crash.
--

commit f9e66992c2da2f752b05c3f6b558475dc2678c3b
Author: Casey Schaufler <casey@schaufler-ca.com>

Smack: hooks for secctx_to_lsmprop and update_lsmprop

Implement these hooks.

> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
> index ff115068c5c06..fcfadd5d99941 100644
> --- a/security/smack/smack_lsm.c
> +++ b/security/smack/smack_lsm.c
[ ... ]
> @@ -4909,6 +4909,37 @@ static int smack_lsmprop_to_secctx(struct lsm_prop *prop,
>  	return smack_to_secctx(prop->smack.skp, cp);
>  }
>  
> +/**
> + * smack_secctx_to_lsmprop - add the smack label to an lsmprop
> + * @secdata: smack label
> + * @seclen: how long label is
> + * @prop: where to put the result
> + *
> + * Exists for audit and networking code.
> + */
> +static int smack_secctx_to_lsmprop(const char *secdata, u32 seclen,
> +				   struct lsm_prop *prop)
> +{
> +	prop->smack.skp = smk_find_entry(secdata);
> +
> +	return 0;

[Severity: Critical]
Will this return 0 (success) even when a label is unrecognized and 
smk_find_entry() returns NULL?

If an unprivileged user with CAP_NET_ADMIN in a namespace configures an
invalid Smack label via Netfilter (e.g., xt_SECMARK or nft_meta), this
function will return success but leave prop->smack.skp as NULL.

Because it returned success, the networking code will consider the lsm_prop
valid. When a network packet hits an NFQUEUE target, the queue attempts to
retrieve the security context by calling security_lsmprop_to_secctx(), which
invokes smack_lsmprop_to_secctx() and blindly passes the NULL pointer to
smack_to_secctx():

security/smack/smack_lsm.c:smack_lsmprop_to_secctx() {
	return smack_to_secctx(prop->smack.skp, cp);
}

This leads to an immediate kernel panic when the NULL pointer is dereferenced:

security/smack/smack_lsm.c:smack_to_secctx() {
	int len = strlen(skp->smk_known);
    ...
}

Could this function be updated to return an error code such as -EINVAL when
the label is unrecognized, preventing the crash?

> +}

[ ... ]

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260902220150.18586-1-casey@schaufler-ca.com?part=5

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

* Re: [PATCH v2 2/7] LSM: Implement x array functions for secmarks
  2026-09-02 22:01   ` [PATCH v2 2/7] LSM: Implement x array functions for secmarks Casey Schaufler
@ 2026-09-02 22:21     ` sashiko-bot
  2026-09-03  5:36     ` John Johansen
  1 sibling, 0 replies; 22+ messages in thread
From: sashiko-bot @ 2026-09-02 22:21 UTC (permalink / raw)
  Cc: selinux

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Critical] Using `memcmp()` to compare `struct lsm_prop` fails to match identical properties due to uninitialized padding bytes.
- [High] Time-Of-Check to Time-Of-Use (TOCTOU) race condition in `secxa_from_lsmprop` allows duplicate XArray entries and memory leaks.
--

commit 9623dfb3d9ce13325263af52c93bc771e66bc688
Author: Casey Schaufler <casey@schaufler-ca.com>

LSM: Implement x array functions for secmarks

This commit implements the functions required to map lsm_prop structures to
xarray indexes for use in secmarks. It introduces secxa_get_lsmprop() and
secxa_from_lsmprop() to manage the mapping.

> diff --git a/security/lsm_secxa.c b/security/lsm_secxa.c
> new file mode 100644
> index 0000000000000..ccbe78095d703
> --- /dev/null
> +++ b/security/lsm_secxa.c

[ ... ]

> +/**
> + * secxa_from_lsmprop - get the secxa associated with a lsm_prop
> + * @prop: lsm_prop pointer
> + * @secxa: result
> + *
> + * Find the secxa associated with @prop. If there is none, create it.
> + *
> + * Returns 0, or an error if the mapping cannot be created
> + */
> +int secxa_from_lsmprop(struct lsm_prop *prop, u32 *secxa)
> +{
> +	struct lsm_prop *lp;
> +	unsigned long il;
> +	u32 index = 0;
> +	int rc;
> +
> +	xa_for_each(&secxa_xa, il, lp) {
> +		if (!memcmp(prop, lp, sizeof(*prop))) {

[Severity: Critical]
Will this memcmp() check fail to match identical properties due to uninitialized
padding bytes? 

If struct lsm_prop is ever allocated on the stack without zeroing the entire
structure, the padding bytes or inactive fields could contain uninitialized
stack garbage. 

This might cause logically identical properties to fail the memcmp() comparison,
resulting in continuous duplicate allocations and rapid exhaustion of the 31-bit
ID space.

> +			*secxa = il;
> +			return 0;
> +		}
> +	}
> +
> +	lp = kzalloc(sizeof(*lp), GFP_ATOMIC);
> +	if (!lp)
> +		return -ENOMEM;
> +	*lp = *prop;
> +
> +	rc = xa_alloc_bh(&secxa_xa, &index, lp, xa_limit_31b, GFP_ATOMIC);

[Severity: High]
Is there a time-of-check to time-of-use race condition when inserting new
entries into the xarray?

The xa_for_each() loop above performs a lockless search for an existing entry.
If multiple threads execute secxa_from_lsmprop() concurrently and simultaneously
fail to find a match, they will all proceed to allocate memory and call
xa_alloc_bh().

Since xa_alloc_bh() simply acquires the lock to assign a new ID and does not
re-verify if an identical lsm_prop was just inserted by another thread, could
this result in duplicate entries and memory leaks over time?

> +	if (rc) {
> +		kfree(lp);
> +		return -EINVAL;
> +	}
> +
> +	*secxa = index;
> +	return 0;
> +}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260902220150.18586-1-casey@schaufler-ca.com?part=2

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

* Re: [PATCH v2 1/7] net, smack: Create a function to set secmarks
  2026-09-02 22:01   ` [PATCH v2 1/7] net, smack: Create a function to set secmarks Casey Schaufler
  2026-09-02 22:13     ` sashiko-bot
@ 2026-09-03  5:35     ` John Johansen
  1 sibling, 0 replies; 22+ messages in thread
From: John Johansen @ 2026-09-03  5:35 UTC (permalink / raw)
  To: Casey Schaufler, paul, linux-security-module, pablo, fw, phil
  Cc: linux-kernel, netfilter-devel, coreteam, jmorris, serge, keescook,
	penguin-kernel, stephen.smalley.work, selinux

On 9/2/26 15:01, Casey Schaufler wrote:
> Rather than open coding assignments to skb->secmark, use a helper function
> secxa_set_secmark(). This allows for a case where assigning a secmark
> is more complex than a simple assignment. The version of the function
> here does the legacy simple assignment.
> 
> Change the functions that currently assign values to skb->secmark to
> use this function.
> 
> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>

looks good

Reviewed-by: John Johansen <john.johansen@canonical.com>

> ---
>   include/linux/lsm_secxa.h        | 28 ++++++++++++++++++++++++++++
>   net/netfilter/nft_meta.c         |  5 +++--
>   net/netfilter/xt_CONNSECMARK.c   |  3 ++-
>   net/netfilter/xt_SECMARK.c       |  3 ++-
>   security/smack/smack_netfilter.c |  3 ++-
>   5 files changed, 37 insertions(+), 5 deletions(-)
>   create mode 100644 include/linux/lsm_secxa.h
> 
> diff --git a/include/linux/lsm_secxa.h b/include/linux/lsm_secxa.h
> new file mode 100644
> index 000000000000..926257d4730c
> --- /dev/null
> +++ b/include/linux/lsm_secxa.h
> @@ -0,0 +1,28 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +
> +/*
> + * Copyright (C) 2026 Casey Schaufler <casey@schaufler-ca.com>
> + */
> +
> +#ifndef __LINUX_LSM_SECXA_H
> +#define __LINUX_LSM_SECXA_H
> +
> +#ifdef CONFIG_NETWORK_SECMARK
> +
> +#include <linux/security.h>
> +#include <linux/skbuff.h>
> +
> +static inline void secxa_set_secmark(struct sk_buff *skb, u32 secxa)
> +{
> +	skb->secmark = secxa;
> +}
> +#else /* CONFIG_NETWORK_SECMARK */
> +
> +struct sk_buff;
> +
> +static inline void secxa_set_secmark(struct sk_buff *skb, u32 secxa)
> +{
> +}
> +#endif /* CONFIG_NETWORK_SECMARK */
> +
> +#endif  /* __LINUX_LSM_SECXA_H */
> diff --git a/net/netfilter/nft_meta.c b/net/netfilter/nft_meta.c
> index 0a43e0787a68..bd0f7a0931f4 100644
> --- a/net/netfilter/nft_meta.c
> +++ b/net/netfilter/nft_meta.c
> @@ -17,6 +17,7 @@
>   #include <linux/random.h>
>   #include <linux/smp.h>
>   #include <linux/static_key.h>
> +#include <linux/lsm_secxa.h>
>   #include <net/dst.h>
>   #include <net/ip.h>
>   #include <net/sock.h>
> @@ -502,7 +503,7 @@ void nft_meta_set_eval(const struct nft_expr *expr,
>   		break;
>   #ifdef CONFIG_NETWORK_SECMARK
>   	case NFT_META_SECMARK:
> -		skb->secmark = value;
> +		secxa_set_secmark(skb, value);
>   		break;
>   #endif
>   	default:
> @@ -950,7 +951,7 @@ static void nft_secmark_obj_eval(struct nft_object *obj, struct nft_regs *regs,
>   	const struct nft_secmark *priv = nft_obj_data(obj);
>   	struct sk_buff *skb = pkt->skb;
>   
> -	skb->secmark = priv->secid;
> +	secxa_set_secmark(skb, priv->secid);
>   }
>   
>   static int nft_secmark_obj_init(const struct nft_ctx *ctx,
> diff --git a/net/netfilter/xt_CONNSECMARK.c b/net/netfilter/xt_CONNSECMARK.c
> index 1494b3ee30e1..9d799d2459dc 100644
> --- a/net/netfilter/xt_CONNSECMARK.c
> +++ b/net/netfilter/xt_CONNSECMARK.c
> @@ -14,6 +14,7 @@
>   #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
>   #include <linux/module.h>
>   #include <linux/skbuff.h>
> +#include <linux/lsm_secxa.h>
>   #include <linux/netfilter/x_tables.h>
>   #include <linux/netfilter/xt_CONNSECMARK.h>
>   #include <net/netfilter/nf_conntrack.h>
> @@ -55,7 +56,7 @@ static void secmark_restore(struct sk_buff *skb)
>   
>   		ct = nf_ct_get(skb, &ctinfo);
>   		if (ct && ct->secmark)
> -			skb->secmark = ct->secmark;
> +			secxa_set_secmark(skb, ct->secmark);
>   	}
>   }
>   
> diff --git a/net/netfilter/xt_SECMARK.c b/net/netfilter/xt_SECMARK.c
> index 5bc5ea505eb9..ea67aa92ddc2 100644
> --- a/net/netfilter/xt_SECMARK.c
> +++ b/net/netfilter/xt_SECMARK.c
> @@ -11,6 +11,7 @@
>   #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
>   #include <linux/module.h>
>   #include <linux/security.h>
> +#include <linux/lsm_secxa.h>
>   #include <linux/skbuff.h>
>   #include <linux/netfilter/x_tables.h>
>   #include <linux/netfilter/xt_SECMARK.h>
> @@ -36,7 +37,7 @@ secmark_tg(struct sk_buff *skb, const struct xt_secmark_target_info_v1 *info)
>   		BUG();
>   	}
>   
> -	skb->secmark = secmark;
> +	secxa_set_secmark(skb, secmark);
>   	return XT_CONTINUE;
>   }
>   
> diff --git a/security/smack/smack_netfilter.c b/security/smack/smack_netfilter.c
> index 17ba578b1308..b363c42f252e 100644
> --- a/security/smack/smack_netfilter.c
> +++ b/security/smack/smack_netfilter.c
> @@ -14,6 +14,7 @@
>   #include <linux/netfilter_ipv4.h>
>   #include <linux/netfilter_ipv6.h>
>   #include <linux/netdevice.h>
> +#include <linux/lsm_secxa.h>
>   #include <net/inet_sock.h>
>   #include <net/net_namespace.h>
>   #include "smack.h"
> @@ -29,7 +30,7 @@ static unsigned int smack_ip_output(void *priv,
>   	if (sk) {
>   		ssp = smack_sock(sk);
>   		skp = ssp->smk_out;
> -		skb->secmark = skp->smk_secid;
> +		secxa_set_secmark(skb, skp->smk_secid);
>   	}
>   
>   	return NF_ACCEPT;


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

* Re: [PATCH v2 2/7] LSM: Implement x array functions for secmarks
  2026-09-02 22:01   ` [PATCH v2 2/7] LSM: Implement x array functions for secmarks Casey Schaufler
  2026-09-02 22:21     ` sashiko-bot
@ 2026-09-03  5:36     ` John Johansen
  1 sibling, 0 replies; 22+ messages in thread
From: John Johansen @ 2026-09-03  5:36 UTC (permalink / raw)
  To: Casey Schaufler, paul, linux-security-module, pablo, fw, phil
  Cc: linux-kernel, netfilter-devel, coreteam, jmorris, serge, keescook,
	penguin-kernel, stephen.smalley.work, selinux

On 9/2/26 15:01, Casey Schaufler wrote:
> Implement, but don't use (yet) the functions required to use
> xarray indexes in secmarks.
> 
> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>

minor nit below

> ---
>   include/linux/lsm_secxa.h |  19 ++++---
>   security/Makefile         |   1 +
>   security/lsm_secxa.c      | 109 ++++++++++++++++++++++++++++++++++++++
>   3 files changed, 121 insertions(+), 8 deletions(-)
>   create mode 100644 security/lsm_secxa.c
> 
> diff --git a/include/linux/lsm_secxa.h b/include/linux/lsm_secxa.h
> index 926257d4730c..84b06c093460 100644
> --- a/include/linux/lsm_secxa.h
> +++ b/include/linux/lsm_secxa.h
> @@ -7,19 +7,22 @@
>   #ifndef __LINUX_LSM_SECXA_H
>   #define __LINUX_LSM_SECXA_H
>   
> -#ifdef CONFIG_NETWORK_SECMARK
> +#ifdef CONFIG_SECURITY
>   
> -#include <linux/security.h>
> -#include <linux/skbuff.h>
> +struct lsm_prop;
>   
> -static inline void secxa_set_secmark(struct sk_buff *skb, u32 secxa)
> -{
> -	skb->secmark = secxa;
> -}
> -#else /* CONFIG_NETWORK_SECMARK */
> +int secxa_from_lsmprop(struct lsm_prop *prop, u32 *secxa);
> +int secxa_get_lsmprop(struct lsm_prop **pro, u32 secxa);
> +
> +#endif /* CONFIG_SECURITY */
> +
> +#ifdef CONFIG_NETWORK_SECMARK
>   
>   struct sk_buff;
>   
> +void secxa_set_secmark(struct sk_buff *skb, u32 secxa);
> +#else /* CONFIG_NETWORK_SECMARK */
> +
>   static inline void secxa_set_secmark(struct sk_buff *skb, u32 secxa)
>   {
>   }
> diff --git a/security/Makefile b/security/Makefile
> index 4601230ba442..e93be00bb6ae 100644
> --- a/security/Makefile
> +++ b/security/Makefile
> @@ -8,6 +8,7 @@ obj-$(CONFIG_KEYS)			+= keys/
>   # always enable default capabilities
>   obj-y					+= commoncap.o
>   obj-$(CONFIG_SECURITY) 			+= lsm_syscalls.o
> +obj-$(CONFIG_NETWORK_SECMARK)		+= lsm_secxa.o
>   obj-$(CONFIG_MMU)			+= min_addr.o
>   
>   # Object file lists
> diff --git a/security/lsm_secxa.c b/security/lsm_secxa.c
> new file mode 100644
> index 000000000000..ccbe78095d70
> --- /dev/null
> +++ b/security/lsm_secxa.c
> @@ -0,0 +1,109 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +
> +/*
> + * Implement functions supporting an x array for LSM properties.
> + *
> + * Copyright (C) 2026 Casey Schaufler <casey@schaufler-ca.com>
> + */
> +#define pr_fmt(fmt) "secxa: "fmt
> +
> +#include <linux/xarray.h>
> +#include <linux/export.h>
> +#include <linux/security.h>
> +#include <linux/lsm_secxa.h>
> +#include <linux/skbuff.h>
> +
> +/*
> + * An Xarray of lsm_prop structures.
> + */
> +struct xarray secxa_xa;
> +
> +/**
> + * secxa_init - initialize the xarry of lsm_prop structures.
> + */
> +static int __init secxa_init(void)
> +{
> +	xa_init_flags(&secxa_xa, XA_FLAGS_ALLOC1 | XA_FLAGS_LOCK_BH);
> +
> +	return 0;
> +}
> +core_initcall(secxa_init);
> +
> +/**
> + * secxa_get_lsmprop - get the lsm_prop associated with a secxa
> + * @pro: destination for the lsm_prop pointer
> + * @secxa: index to look up
> + *
> + * Find the lsm_prop associated with @secxa and place a pointer
> + * to it in @pro.
> + *
> + * Returns 0, or -EINVAL if the mapping can't be found.
> + */
> +int secxa_get_lsmprop(struct lsm_prop **pro, u32 secxa)
> +{
> +	struct lsm_prop *lp;
> +
> +	if (!secxa)
> +		return -EINVAL;
> +
> +	lp = xa_load(&secxa_xa, secxa);
> +	if (!lp)
> +		return -EINVAL;
> +
> +	*pro = lp;
> +	return 0;
> +}
> +EXPORT_SYMBOL(secxa_get_lsmprop);
> +
> +/**
> + * secxa_from_lsmprop - get the secxa associated with a lsm_prop
> + * @prop: lsm_prop pointer
> + * @secxa: result
> + *
> + * Find the secxa associated with @prop. If there is none, create it.
> + *
> + * Returns 0, or an error if the mapping cannot be created
> + */
> +int secxa_from_lsmprop(struct lsm_prop *prop, u32 *secxa)
> +{
> +	struct lsm_prop *lp;
> +	unsigned long il;
> +	u32 index = 0;
> +	int rc;
> +
> +	xa_for_each(&secxa_xa, il, lp) {
> +		if (!memcmp(prop, lp, sizeof(*prop))) {
> +			*secxa = il;
this needs an explicit cast to (u32) to avoid some warnings
on some architecture + warning flags combinations

> +			return 0;
> +		}
> +	}
> +
> +	lp = kzalloc(sizeof(*lp), GFP_ATOMIC);
> +	if (!lp)
> +		return -ENOMEM;
> +	*lp = *prop;
> +
> +	rc = xa_alloc_bh(&secxa_xa, &index, lp, xa_limit_31b, GFP_ATOMIC);
> +	if (rc) {
> +		kfree(lp);
> +		return -EINVAL;
> +	}
> +
> +	*secxa = index;
> +	return 0;
> +}
> +EXPORT_SYMBOL(secxa_from_lsmprop);
> +
> +/**
> + * secxa_set_secmark - add LSM information to a secmark
> + * @skb: buffer with the secmark
> + * @secxa: index of the information to add
> + *
> + * If the secmark in @skb is not set, set it to @secxa.
> + */
> +void secxa_set_secmark(struct sk_buff *skb, u32 secxa)
> +{
> +	if (!skb->secmark)
> +		skb->secmark = secxa;
> +}
> +EXPORT_SYMBOL(secxa_set_secmark);


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

* Re: [PATCH v2 4/7] SELinux: hooks for secctx_to_lsmprop and update_lsmprop
  2026-09-02 22:01   ` [PATCH v2 4/7] SELinux: hooks for secctx_to_lsmprop and update_lsmprop Casey Schaufler
  2026-09-02 22:10     ` sashiko-bot
@ 2026-09-03  6:10     ` John Johansen
  1 sibling, 0 replies; 22+ messages in thread
From: John Johansen @ 2026-09-03  6:10 UTC (permalink / raw)
  To: Casey Schaufler, paul, linux-security-module, pablo, fw, phil
  Cc: linux-kernel, netfilter-devel, coreteam, jmorris, serge, keescook,
	penguin-kernel, stephen.smalley.work, selinux

On 9/2/26 15:01, Casey Schaufler wrote:
> Implement these hooks.
> 
other than the question below, this is looking good
> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> ---
>   security/selinux/hooks.c | 16 ++++++++++++++++
>   1 file changed, 16 insertions(+)
> 
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index 18dd28b2bb13..12614478b638 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -6946,6 +6946,13 @@ static int selinux_ismaclabel(const char *name)
>   	return (strcmp(name, XATTR_SELINUX_SUFFIX) == 0);
>   }
>   
> +static void selinux_update_lsmprop(struct lsm_prop *dest, struct lsm_prop *src,
> +				   int lsmid)
> +{
> +	if (lsmid == LSM_ID_SELINUX || lsmid == LSM_ID_UNDEF)
you have added similar boiler plate to each of the LSMs using this hook. If
all LSMs are going to do this, then shouldn't we just move this into the
LSM similar to what is done with secctx_to_lsm_prop

		if (lsmid != LSM_ID_UNDEF && lsmid != scall->hl->lsmid->id)
			continue;

> +		dest->selinux.secid = src->selinux.secid;
> +}
> +
>   static int selinux_secid_to_secctx(u32 secid, struct lsm_context *cp)
>   {
>   	u32 seclen;
> @@ -6964,6 +6971,13 @@ static int selinux_secid_to_secctx(u32 secid, struct lsm_context *cp)
>   	return seclen;
>   }
>   
> +static int selinux_secctx_to_lsmprop(const char *secdata, u32 seclen,
> +				     struct lsm_prop *prop)
> +{
> +	return security_context_to_sid(secdata, seclen, &prop->selinux.secid,
> +				       GFP_KERNEL);
> +}
> +
>   static int selinux_lsmprop_to_secctx(struct lsm_prop *prop,
>   				     struct lsm_context *cp)
>   {
> @@ -7694,6 +7708,7 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = {
>   
>   	LSM_HOOK_INIT(ismaclabel, selinux_ismaclabel),
>   	LSM_HOOK_INIT(secctx_to_secid, selinux_secctx_to_secid),
> +	LSM_HOOK_INIT(secctx_to_lsmprop, selinux_secctx_to_lsmprop),
>   	LSM_HOOK_INIT(release_secctx, selinux_release_secctx),
>   	LSM_HOOK_INIT(inode_invalidate_secctx, selinux_inode_invalidate_secctx),
>   	LSM_HOOK_INIT(inode_notifysecctx, selinux_inode_notifysecctx),
> @@ -7812,6 +7827,7 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = {
>   	LSM_HOOK_INIT(sem_alloc_security, selinux_sem_alloc_security),
>   	LSM_HOOK_INIT(secid_to_secctx, selinux_secid_to_secctx),
>   	LSM_HOOK_INIT(lsmprop_to_secctx, selinux_lsmprop_to_secctx),
> +	LSM_HOOK_INIT(update_lsmprop, selinux_update_lsmprop),
>   	LSM_HOOK_INIT(inode_getsecctx, selinux_inode_getsecctx),
>   	LSM_HOOK_INIT(sk_alloc_security, selinux_sk_alloc_security),
>   	LSM_HOOK_INIT(tun_dev_alloc_security, selinux_tun_dev_alloc_security),


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

* Re: [PATCH v2 5/7] Smack: hooks for secctx_to_lsmprop and update_lsmprop
  2026-09-02 22:01   ` [PATCH v2 5/7] Smack: " Casey Schaufler
  2026-09-02 22:17     ` sashiko-bot
@ 2026-09-03  6:15     ` John Johansen
  1 sibling, 0 replies; 22+ messages in thread
From: John Johansen @ 2026-09-03  6:15 UTC (permalink / raw)
  To: Casey Schaufler, paul, linux-security-module, pablo, fw, phil
  Cc: linux-kernel, netfilter-devel, coreteam, jmorris, serge, keescook,
	penguin-kernel, stephen.smalley.work, selinux

On 9/2/26 15:01, Casey Schaufler wrote:
> Implement these hooks.
> 
beyond the question from the previous patch, wanting more in the
description, and the quick double check question below.

This is looks right

> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> ---
>   security/smack/smack_lsm.c | 33 +++++++++++++++++++++++++++++++++
>   1 file changed, 33 insertions(+)
> 
> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
> index ff115068c5c0..fcfadd5d9994 100644
> --- a/security/smack/smack_lsm.c
> +++ b/security/smack/smack_lsm.c
> @@ -4909,6 +4909,37 @@ static int smack_lsmprop_to_secctx(struct lsm_prop *prop,
>   	return smack_to_secctx(prop->smack.skp, cp);
>   }
>   
> +/**
> + * smack_secctx_to_lsmprop - add the smack label to an lsmprop
> + * @secdata: smack label
> + * @seclen: how long label is
> + * @prop: where to put the result
> + *
> + * Exists for audit and networking code.
> + */
> +static int smack_secctx_to_lsmprop(const char *secdata, u32 seclen,
> +				   struct lsm_prop *prop)
> +{
> +	prop->smack.skp = smk_find_entry(secdata);

just double checking a null value here, looks to be okay, but just double
checking as I just did a quick skim of the code.


> +
> +	return 0;
> +}
> +
> +/**
> + * smack_update_lsmprop - set the smack label in an lsmprop
> + * @dest: destination properties
> + * @src: source properties
> + * @lsmid: which LSM is relevant.
> + *
> + * Set the Smack entry in the @dest if appropriate.
> + */
> +static void smack_update_lsmprop(struct lsm_prop *dest, struct lsm_prop *src,
> +				 int lsmid)
> +{
> +	if (lsmid == LSM_ID_SMACK || lsmid == LSM_ID_UNDEF)
> +		dest->smack.skp = src->smack.skp;
> +}
> +
>   /**
>    * smack_secctx_to_secid - return the secid for a smack label
>    * @secdata: smack label
> @@ -5269,6 +5300,8 @@ static struct security_hook_list smack_hooks[] __ro_after_init = {
>   	LSM_HOOK_INIT(secid_to_secctx, smack_secid_to_secctx),
>   	LSM_HOOK_INIT(lsmprop_to_secctx, smack_lsmprop_to_secctx),
>   	LSM_HOOK_INIT(secctx_to_secid, smack_secctx_to_secid),
> +	LSM_HOOK_INIT(secctx_to_lsmprop, smack_secctx_to_lsmprop),
> +	LSM_HOOK_INIT(update_lsmprop, smack_update_lsmprop),
>   	LSM_HOOK_INIT(inode_notifysecctx, smack_inode_notifysecctx),
>   	LSM_HOOK_INIT(inode_setsecctx, smack_inode_setsecctx),
>   	LSM_HOOK_INIT(inode_getsecctx, smack_inode_getsecctx),


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

* Re: [PATCH v2 7/7] net, lsm: Change skb secmarks to x-array indexes
  2026-09-02 22:01   ` [PATCH v2 7/7] net, lsm: Change skb secmarks to x-array indexes Casey Schaufler
  2026-09-02 22:15     ` sashiko-bot
@ 2026-09-03  7:31     ` John Johansen
  1 sibling, 0 replies; 22+ messages in thread
From: John Johansen @ 2026-09-03  7:31 UTC (permalink / raw)
  To: Casey Schaufler, paul, linux-security-module, pablo, fw, phil
  Cc: linux-kernel, netfilter-devel, coreteam, jmorris, serge, keescook,
	penguin-kernel, stephen.smalley.work, selinux

On 9/2/26 15:01, Casey Schaufler wrote:
> Maintain a xarray of lsm_prop structures which represent the
> LSM security information passed via skb->secmark. Pass the xarray
> index of the appropriate lsm_prop (the secxa) instead of an LSM
> specific secid. Allow multiple LSMs to specify their components
> in xarray entries, or create new entries as necessary.
> 
> Change uses of security_secctx_to_secid() to security_secctx_to_lsmprop()
> in the netfilter and iptables code. Change security_secmark_relabel_packet()
> to accept an lsm_prop pointer rather than a secid. Change secxa_set_secmark()
> to update and create new entries as necessary.
> 
> Update the SELinux, Smack and AppArmor hooks that use secmarks to
> expect a secxa xarray index instead of a secid.
> 

see comments below

> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> ---
>   include/linux/lsm_hook_defs.h    |  2 +-
>   include/linux/lsm_secxa.h        |  2 +
>   include/linux/security.h         |  4 +-
>   net/netfilter/nfnetlink_queue.c  | 12 +++++-
>   net/netfilter/nft_meta.c         | 15 ++++---
>   net/netfilter/xt_SECMARK.c       | 16 +++++--
>   security/apparmor/net.c          |  8 +++-
>   security/lsm_secxa.c             | 20 ++++++
>   security/security.c              |  6 +--
>   security/selinux/hooks.c         | 71 +++++++++++++++++++++++++++-----
>   security/smack/smack_lsm.c       | 10 ++++-
>   security/smack/smack_netfilter.c | 10 +++--
>   12 files changed, 141 insertions(+), 35 deletions(-)
> 
> diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
> index 679c40a8e127..8ecf07e0e3f0 100644
> --- a/include/linux/lsm_hook_defs.h
> +++ b/include/linux/lsm_hook_defs.h
> @@ -371,7 +371,7 @@ LSM_HOOK(void, LSM_RET_VOID, inet_csk_clone, struct sock *newsk,
>   	 const struct request_sock *req)
>   LSM_HOOK(void, LSM_RET_VOID, inet_conn_established, struct sock *sk,
>   	 struct sk_buff *skb)
> -LSM_HOOK(int, 0, secmark_relabel_packet, u32 secid)
> +LSM_HOOK(int, 0, secmark_relabel_packet, struct lsm_prop *prop)
>   LSM_HOOK(void, LSM_RET_VOID, secmark_refcount_inc, void)
>   LSM_HOOK(void, LSM_RET_VOID, secmark_refcount_dec, void)
>   LSM_HOOK(void, LSM_RET_VOID, req_classify_flow, const struct request_sock *req,
> diff --git a/include/linux/lsm_secxa.h b/include/linux/lsm_secxa.h
> index 84b06c093460..5be9d64e67e4 100644
> --- a/include/linux/lsm_secxa.h
> +++ b/include/linux/lsm_secxa.h
> @@ -7,6 +7,8 @@
>   #ifndef __LINUX_LSM_SECXA_H
>   #define __LINUX_LSM_SECXA_H
>   
> +#include <linux/types.h>
> +
>   #ifdef CONFIG_SECURITY
>   
>   struct lsm_prop;
> diff --git a/include/linux/security.h b/include/linux/security.h
> index 19adc19eb9af..ffbd1708065f 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -1715,7 +1715,7 @@ void security_inet_csk_clone(struct sock *newsk,
>   			const struct request_sock *req);
>   void security_inet_conn_established(struct sock *sk,
>   			struct sk_buff *skb);
> -int security_secmark_relabel_packet(u32 secid);
> +int security_secmark_relabel_packet(struct lsm_prop *prop);
>   void security_secmark_refcount_inc(void);
>   void security_secmark_refcount_dec(void);
>   int security_tun_dev_alloc_security(void **security);
> @@ -1898,7 +1898,7 @@ static inline void security_inet_conn_established(struct sock *sk,
>   {
>   }
>   
> -static inline int security_secmark_relabel_packet(u32 secid)
> +static inline int security_secmark_relabel_packet(struct lsm_prop *prop)
>   {
>   	return 0;
>   }
> diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
> index b8aaf39cb4d8..ebab037edc6b 100644
> --- a/net/netfilter/nfnetlink_queue.c
> +++ b/net/netfilter/nfnetlink_queue.c
> @@ -32,6 +32,7 @@
>   #include <linux/cgroup-defs.h>
>   #include <linux/rhashtable.h>
>   #include <linux/jhash.h>
> +#include <linux/lsm_secxa.h>
>   #include <net/gso.h>
>   #include <net/sock.h>
>   #include <net/tcp_states.h>
> @@ -606,8 +607,15 @@ static int nfqnl_get_sk_secctx(struct sk_buff *skb, struct lsm_context *ctx)
>   {
>   	int seclen = 0;
>   #if IS_ENABLED(CONFIG_NETWORK_SECMARK)
> -	if (skb->secmark)
> -		seclen = security_secid_to_secctx(skb->secmark, ctx);
> +	struct lsm_prop *prop;
> +	int rc;
> +
> +	if (skb->secmark) {
> +		rc = secxa_get_lsmprop(&prop, skb->secmark);
> +		if (rc)
> +			return 0;
> +		seclen = security_lsmprop_to_secctx(prop, ctx, LSM_ID_UNDEF);
> +	}
>   #endif
>   	return seclen;
>   }
> diff --git a/net/netfilter/nft_meta.c b/net/netfilter/nft_meta.c
> index bd0f7a0931f4..664191dfa4b2 100644
> --- a/net/netfilter/nft_meta.c
> +++ b/net/netfilter/nft_meta.c
> @@ -927,21 +927,24 @@ static const struct nla_policy nft_secmark_policy[NFTA_SECMARK_MAX + 1] = {
>   
>   static int nft_secmark_compute_secid(struct nft_secmark *priv)
>   {
> -	u32 tmp_secid = 0;
> +	struct lsm_prop tmp_prop;
> +	u32 secxa = 0;
>   	int err;
>   
> -	err = security_secctx_to_secid(priv->ctx, strlen(priv->ctx), &tmp_secid);
> +	err = security_secctx_to_lsmprop(priv->ctx, strlen(priv->ctx),
> +					 &tmp_prop, LSM_ID_UNDEF);
>   	if (err)
>   		return err;
>   
> -	if (!tmp_secid)
> -		return -ENOENT;
> +	err = secxa_from_lsmprop(&tmp_prop, &secxa);
> +	if (err)
> +		return err;
>   
> -	err = security_secmark_relabel_packet(tmp_secid);
> +	err = security_secmark_relabel_packet(&tmp_prop);
>   	if (err)
>   		return err;
>   
> -	priv->secid = tmp_secid;
> +	priv->secid = secxa;
>   	return 0;
>   }
>   
> diff --git a/net/netfilter/xt_SECMARK.c b/net/netfilter/xt_SECMARK.c
> index ea67aa92ddc2..05b023a7c576 100644
> --- a/net/netfilter/xt_SECMARK.c
> +++ b/net/netfilter/xt_SECMARK.c
> @@ -43,13 +43,15 @@ secmark_tg(struct sk_buff *skb, const struct xt_secmark_target_info_v1 *info)
>   
>   static int checkentry_lsm(struct xt_secmark_target_info_v1 *info)
>   {
> +	struct lsm_prop prop;
>   	int err;
>   
>   	info->secctx[SECMARK_SECCTX_MAX - 1] = '\0';
>   	info->secid = 0;
>   
> -	err = security_secctx_to_secid(info->secctx, strlen(info->secctx),
> -				       &info->secid);
> +	err = security_secctx_to_lsmprop(info->secctx, strlen(info->secctx),
> +					 &prop, LSM_ID_UNDEF);
> +
>   	if (err) {
>   		if (err == -EINVAL)
>   			pr_info_ratelimited("invalid security context \'%s\'\n",
> @@ -57,18 +59,24 @@ static int checkentry_lsm(struct xt_secmark_target_info_v1 *info)
>   		return err;
>   	}
>   
> -	if (!info->secid) {
> +	if (!lsmprop_is_set(&prop)) {
>   		pr_info_ratelimited("unable to map security context \'%s\'\n",
>   				    info->secctx);
>   		return -ENOENT;
>   	}
>   
> -	err = security_secmark_relabel_packet(info->secid);
> +	err = security_secmark_relabel_packet(&prop);
>   	if (err) {
>   		pr_info_ratelimited("unable to obtain relabeling permission\n");
>   		return err;
>   	}
>   
> +	err = secxa_from_lsmprop(&prop, &info->secid);
> +	if (err) {
> +		pr_info_ratelimited("unable to obtain secmark\n");
> +		return err;
> +	}
> +
>   	security_secmark_refcount_inc();
>   	return 0;
>   }
> diff --git a/security/apparmor/net.c b/security/apparmor/net.c
> index cf590dd08540..e26e15c2d947 100644
> --- a/security/apparmor/net.c
> +++ b/security/apparmor/net.c
> @@ -8,6 +8,7 @@
>    * Copyright 2009-2017 Canonical Ltd.
>    */
>   
> +#include <linux/lsm_secxa.h>
>   #include "include/af_unix.h"
>   #include "include/apparmor.h"
>   #include "include/audit.h"
> @@ -365,12 +366,17 @@ static int aa_secmark_perm(struct aa_profile *profile, u32 request, u32 secid,
>   			   struct apparmor_audit_data *ad)
>   {
>   	int i, ret;
> +	struct lsm_prop *prop;
>   	struct aa_perms perms = { };
>   	struct aa_ruleset *rules = profile->label.rules[0];
>   
>   	if (rules->secmark_count == 0)
>   		return 0;
>   
> +	ret = secxa_get_lsmprop(&prop, secid);
> +	if (ret)
> +		return ret;
> +
>   	for (i = 0; i < rules->secmark_count; i++) {
>   		if (!rules->secmark[i].secid) {
>   			ret = apparmor_secmark_init(&rules->secmark[i]);
> @@ -378,7 +384,7 @@ static int aa_secmark_perm(struct aa_profile *profile, u32 request, u32 secid,
>   				return ret;
>   		}
>   
> -		if (rules->secmark[i].secid == secid ||
> +		if (rules->secmark[i].secid == prop->apparmor.label->secid ||
>   		    rules->secmark[i].secid == AA_SECID_WILDCARD) {
>   			if (rules->secmark[i].deny)
>   				perms.deny = ALL_PERMS_MASK;
> diff --git a/security/lsm_secxa.c b/security/lsm_secxa.c
> index ccbe78095d70..f0702ac5601d 100644
> --- a/security/lsm_secxa.c
> +++ b/security/lsm_secxa.c
> @@ -103,7 +103,25 @@ EXPORT_SYMBOL(secxa_from_lsmprop);
>    */
>   void secxa_set_secmark(struct sk_buff *skb, u32 secxa)
>   {
> -	if (!skb->secmark)
> +	struct lsm_prop *olp;
> +	struct lsm_prop *nlp;
> +	struct lsm_prop prop;
> +	u32 tsecxa;
> +	int rc;
> +
> +	if (!skb->secmark) {
>   		skb->secmark = secxa;
> +		return;
> +	}
> +
> +	olp = xa_load(&secxa_xa, skb->secmark);
> +	nlp = xa_load(&secxa_xa, secxa);
> +
> +	prop = *olp;
> +	security_update_lsmprop(&prop, nlp, LSM_ID_UNDEF);
> +
> +	rc = secxa_from_lsmprop(&prop, &tsecxa);
> +	if (!rc)
> +		skb->secmark = tsecxa;
>   }
>   EXPORT_SYMBOL(secxa_set_secmark);
> diff --git a/security/security.c b/security/security.c
> index 1dec0037370b..e80e7823ce14 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -4646,15 +4646,15 @@ EXPORT_SYMBOL(security_inet_conn_established);
>   
>   /**
>    * security_secmark_relabel_packet() - Check if setting a secmark is allowed
> - * @secid: new secmark value
> + * @lsmprop: new secmark value
>    *
>    * Check if the process should be allowed to relabel packets to @secid.
change @secid to @lsmprop

>    *
>    * Return: Returns 0 if permission is granted.
>    */
> -int security_secmark_relabel_packet(u32 secid)
> +int security_secmark_relabel_packet(struct lsm_prop *prop)
>   {
> -	return call_int_hook(secmark_relabel_packet, secid);
> +	return call_int_hook(secmark_relabel_packet, prop);
>   }
>   EXPORT_SYMBOL(security_secmark_relabel_packet);
>   
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index 12614478b638..bf832eff0b92 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -94,6 +94,7 @@
>   #include <linux/io_uring/cmd.h>
>   #include <uapi/linux/lsm.h>
>   #include <linux/memfd.h>
> +#include <linux/lsm_secxa.h>
>   
>   #include "initcalls.h"
>   #include "avc.h"
> @@ -5414,7 +5415,16 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
>   		return err;
>   
>   	if (selinux_secmark_enabled()) {
> -		err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
> +		struct lsm_prop *prop;
> +		u32 secmark = 0;
> +
> +		if (skb->secmark) {
> +			err = secxa_get_lsmprop(&prop, skb->secmark);
> +			if (!err)
> +				secmark = prop->selinux.secid;
> +		}
> +
> +		err = avc_has_perm(sk_sid, secmark, SECCLASS_PACKET,
>   				   PACKET__RECV, &ad);
>   		if (err)
>   			return err;
> @@ -5483,7 +5493,15 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
>   	}
>   
>   	if (secmark_active) {
> -		err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
> +		struct lsm_prop *prop;
> +		u32 secmark = 0;
> +
> +		if (skb->secmark) {
> +			err = secxa_get_lsmprop(&prop, skb->secmark);
> +			if (!err)
> +				secmark = prop->selinux.secid;
> +		}
> +		err = avc_has_perm(sk_sid, secmark, SECCLASS_PACKET,
>   				   PACKET__RECV, &ad);
>   		if (err)
>   			return err;
> @@ -5885,10 +5903,10 @@ static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
>   	selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid);
>   }
>   
> -static int selinux_secmark_relabel_packet(u32 sid)
> +static int selinux_secmark_relabel_packet(struct lsm_prop *lsmprop)
>   {
> -	return avc_has_perm(current_sid(), sid, SECCLASS_PACKET, PACKET__RELABELTO,
> -			    NULL);
> +	return avc_has_perm(current_sid(), lsmprop->selinux.secid,
> +			    SECCLASS_PACKET, PACKET__RELABELTO, NULL);
>   }
>   
>   static void selinux_secmark_refcount_inc(void)
> @@ -6016,10 +6034,21 @@ static unsigned int selinux_ip_forward(void *priv, struct sk_buff *skb,
>   		}
>   	}
>   
> -	if (secmark_active)
> -		if (avc_has_perm(peer_sid, skb->secmark,
> +	if (secmark_active) {
> +		struct lsm_prop *prop;
> +		u32 secmark = 0;
> +		int err;
> +
> +		if (skb->secmark) {
> +			err = secxa_get_lsmprop(&prop, skb->secmark);
> +			if (!err)
> +				secmark = prop->selinux.secid;
> +		}
> +
> +		if (avc_has_perm(peer_sid, secmark,
>   				 SECCLASS_PACKET, PACKET__FORWARD_IN, &ad))
>   			return NF_DROP;
> +	}
>   
>   	if (netlbl_enabled())
>   		/* we do this in the FORWARD path and not the POST_ROUTING
> @@ -6093,10 +6122,20 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
>   	if (selinux_parse_skb(skb, &ad, NULL, 0, &proto))
>   		return NF_DROP;
>   
> -	if (selinux_secmark_enabled())
> -		if (avc_has_perm(sksec->sid, skb->secmark,
> +	if (selinux_secmark_enabled()) {
> +		struct lsm_prop *prop;
> +		u32 secmark = 0;
> +		int err;
> +
> +		if (skb->secmark) {
> +			err = secxa_get_lsmprop(&prop, skb->secmark);
> +			if (!err)
> +				secmark = prop->selinux.secid;
> +		}
> +		if (avc_has_perm(sksec->sid, secmark,
>   				 SECCLASS_PACKET, PACKET__SEND, &ad))
>   			return NF_DROP_ERR(-ECONNREFUSED);
> +	}
>   
>   	if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto))
>   		return NF_DROP_ERR(-ECONNREFUSED);
> @@ -6215,10 +6254,20 @@ static unsigned int selinux_ip_postroute(void *priv,
>   	if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL))
>   		return NF_DROP;
>   
> -	if (secmark_active)
> -		if (avc_has_perm(peer_sid, skb->secmark,
> +	if (secmark_active) {
> +		struct lsm_prop *prop;
> +		u32 secmark = 0;
> +		int err;
> +
> +		if (skb->secmark) {
> +			err = secxa_get_lsmprop(&prop, skb->secmark);
> +			if (!err)
> +				secmark = prop->selinux.secid;
> +		}
> +		if (avc_has_perm(peer_sid, secmark,
>   				 SECCLASS_PACKET, secmark_perm, &ad))
>   			return NF_DROP_ERR(-ECONNREFUSED);
> +	}


doesn't

   selinux_socket_getpeersec_dgram()
   selinux_req_classify_flow()

I haven't detangled yet whether the xfrm hooks, every grab the
secmark of a packet directly. It looks to me so far to be only
the skb->xfrm->security->ctx_sid. Paul?


overall this conversion bothers me, in that we need to put this
boiler plate into every hook, instead of having the infrastructure
handle the conversion for the specific LSM.

I know this is partly being done because of the
   if (secmakr_active)
check, but I think it would be far cleaner, and less prone to error
if the infra could grab the per LSM property and pass that instead,
and not expose the secid value that has to go through the mapping.
At a minimum the API should identify this mapped secid is different
from the secid being passed in some of the other hooks.

Perhaps we could have a way to store if the LSM is using the secid
so the LSM infra could do the secmark_active check before calling the
hook?

>   
>   	if (peerlbl_active) {
>   		u32 if_sid;
> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
> index fcfadd5d9994..79140e6829a4 100644
> --- a/security/smack/smack_lsm.c
> +++ b/security/smack/smack_lsm.c
> @@ -42,6 +42,7 @@
>   #include <linux/fs_context.h>
>   #include <linux/fs_parser.h>
>   #include <linux/watch_queue.h>
> +#include <linux/lsm_secxa.h>
>   #include <linux/io_uring/cmd.h>
>   #include <uapi/linux/lsm.h>
>   #include "smack.h"
> @@ -4189,10 +4190,17 @@ 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)
>   {
> +	struct lsm_prop *prop;
> +	int rc;
> +
>   	if (skb == NULL || skb->secmark == 0)
>   		return NULL;
>   
> -	return smack_from_secid(skb->secmark);
> +	rc = secxa_get_lsmprop(&prop, skb->secmark);
> +	if (prop)
> +		return prop->smack.skp;
> +
> +	return NULL;
>   }
>   #else
>   static inline struct smack_known *smack_from_skb(struct sk_buff *skb)
> diff --git a/security/smack/smack_netfilter.c b/security/smack/smack_netfilter.c
> index b363c42f252e..0378f74aa22b 100644
> --- a/security/smack/smack_netfilter.c
> +++ b/security/smack/smack_netfilter.c
> @@ -24,13 +24,17 @@ static unsigned int smack_ip_output(void *priv,
>   				    const struct nf_hook_state *state)
>   {
>   	struct sock *sk = skb_to_full_sk(skb);
> +	struct lsm_prop prop = { };
>   	struct socket_smack *ssp;
> -	struct smack_known *skp;
> +	u32 secxa;
> +	int rc;
>   
>   	if (sk) {
>   		ssp = smack_sock(sk);
> -		skp = ssp->smk_out;
> -		secxa_set_secmark(skb, skp->smk_secid);
> +		prop.smack.skp = ssp->smk_out;
> +		rc = secxa_from_lsmprop(&prop, &secxa);
> +		if (!rc)
> +			secxa_set_secmark(skb, secxa);
>   	}
>   
>   	return NF_ACCEPT;


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

* Re: [PATCH v2 6/7] Apparmor: hooks for secctx_to_lsmprop and update_lsmprop
  2026-09-02 22:01   ` [PATCH v2 6/7] Apparmor: " Casey Schaufler
  2026-09-02 22:16     ` sashiko-bot
@ 2026-09-03  9:39     ` John Johansen
  1 sibling, 0 replies; 22+ messages in thread
From: John Johansen @ 2026-09-03  9:39 UTC (permalink / raw)
  To: Casey Schaufler, paul, linux-security-module, pablo, fw, phil
  Cc: linux-kernel, netfilter-devel, coreteam, jmorris, serge, keescook,
	penguin-kernel, stephen.smalley.work, selinux


the code itself looks right
same nit on update_lsmprop as previous two patches.

I know you are working within the insane constraints of the secid, but it really
hurts that apparmor has a local xarray for secids, and now the LSM infra has
one too. I know its a problem to be solved later, I am just griping about the
current state of affairs.


On 9/2/26 15:01, Casey Schaufler wrote:
> Implement these hooks.
> 
> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> ---
>   security/apparmor/include/secid.h |  4 ++++
>   security/apparmor/lsm.c           |  2 ++
>   security/apparmor/secid.c         | 21 +++++++++++++++++++++
>   3 files changed, 27 insertions(+)
> 
> diff --git a/security/apparmor/include/secid.h b/security/apparmor/include/secid.h
> index 6025d3849cf8..ba7adf2fc09e 100644
> --- a/security/apparmor/include/secid.h
> +++ b/security/apparmor/include/secid.h
> @@ -28,6 +28,10 @@ struct aa_label *aa_secid_to_label(u32 secid);
>   int apparmor_secid_to_secctx(u32 secid, struct lsm_context *cp);
>   int apparmor_lsmprop_to_secctx(struct lsm_prop *prop, struct lsm_context *cp);
>   int apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
> +int apparmor_secctx_to_lsmprop(const char *secdata, u32 seclen,
> +			       struct lsm_prop *prop);
> +void apparmor_update_lsmprop(struct lsm_prop *dest, struct lsm_prop *src,
> +			     int lsmid);
>   void apparmor_release_secctx(struct lsm_context *cp);
>   
>   
> diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
> index 88d12e89d115..1f304b88eaf9 100644
> --- a/security/apparmor/lsm.c
> +++ b/security/apparmor/lsm.c
> @@ -1766,6 +1766,8 @@ static struct security_hook_list apparmor_hooks[] __ro_after_init = {
>   	LSM_HOOK_INIT(secid_to_secctx, apparmor_secid_to_secctx),
>   	LSM_HOOK_INIT(lsmprop_to_secctx, apparmor_lsmprop_to_secctx),
>   	LSM_HOOK_INIT(secctx_to_secid, apparmor_secctx_to_secid),
> +	LSM_HOOK_INIT(secctx_to_lsmprop, apparmor_secctx_to_lsmprop),
> +	LSM_HOOK_INIT(update_lsmprop, apparmor_update_lsmprop),
>   	LSM_HOOK_INIT(release_secctx, apparmor_release_secctx),
>   
>   #ifdef CONFIG_IO_URING
> diff --git a/security/apparmor/secid.c b/security/apparmor/secid.c
> index 28caf66b9033..d35fdbf074e0 100644
> --- a/security/apparmor/secid.c
> +++ b/security/apparmor/secid.c
> @@ -106,6 +106,27 @@ int apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
>   	return 0;
>   }
>   
> +int apparmor_secctx_to_lsmprop(const char *secdata, u32 seclen,
> +			       struct lsm_prop *prop)
> +{
> +	struct aa_label *label;
> +
> +	label = aa_label_strn_parse(&root_ns->unconfined->label, secdata,
> +				    seclen, GFP_KERNEL, false, false);
> +	if (IS_ERR(label))
> +		return PTR_ERR(label);
> +	prop->apparmor.label = label;
> +
> +	return 0;
> +}
> +
> +void apparmor_update_lsmprop(struct lsm_prop *dest, struct lsm_prop *src,
> +			     int lsmid)
> +{
> +	if (lsmid == LSM_ID_APPARMOR || lsmid == LSM_ID_UNDEF)
> +		dest->apparmor.label = src->apparmor.label;
> +}
> +
>   void apparmor_release_secctx(struct lsm_context *cp)
>   {
>   	if (cp->id == LSM_ID_APPARMOR) {


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

* Re: [PATCH v2 3/7] LSM: Two hooks for manipulating struct lsm_prop
  2026-09-02 22:01   ` [PATCH v2 3/7] LSM: Two hooks for manipulating struct lsm_prop Casey Schaufler
  2026-09-02 22:16     ` sashiko-bot
@ 2026-09-03  9:40     ` John Johansen
  1 sibling, 0 replies; 22+ messages in thread
From: John Johansen @ 2026-09-03  9:40 UTC (permalink / raw)
  To: Casey Schaufler, paul, linux-security-module, pablo, fw, phil
  Cc: linux-kernel, netfilter-devel, coreteam, jmorris, serge, keescook,
	penguin-kernel, stephen.smalley.work, selinux

On 9/2/26 15:01, Casey Schaufler wrote:
> security_update_lsmprop() updates the property of the
> specified LSM in the @dest structure with that in the @src.
> 
> security_secctx_to_lsmprop() sets the @prop field associated
> with the LSM specified to the value of the passed security
> context.
> 
> LSM specific implementations of these hooks to follow.
> 
> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>

lgtm

Reviewed-by: John Johansen <john.johansen@canonical.com>

> ---
>   include/linux/lsm_hook_defs.h |  4 ++++
>   include/linux/security.h      | 16 ++++++++++++++++
>   security/security.c           | 32 ++++++++++++++++++++++++++++++++
>   3 files changed, 52 insertions(+)
> 
> diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
> index 65c9609ec207..679c40a8e127 100644
> --- a/include/linux/lsm_hook_defs.h
> +++ b/include/linux/lsm_hook_defs.h
> @@ -305,7 +305,11 @@ LSM_HOOK(int, 0, ismaclabel, const char *name)
>   LSM_HOOK(int, -EOPNOTSUPP, secid_to_secctx, u32 secid, struct lsm_context *cp)
>   LSM_HOOK(int, -EOPNOTSUPP, lsmprop_to_secctx, struct lsm_prop *prop,
>   	 struct lsm_context *cp)
> +LSM_HOOK(void, LSM_RET_VOID, update_lsmprop, struct lsm_prop *dest,
> +	 struct lsm_prop *src, int lsmid)
>   LSM_HOOK(int, 0, secctx_to_secid, const char *secdata, u32 seclen, u32 *secid)
> +LSM_HOOK(int, -EINVAL, secctx_to_lsmprop, const char *secdata, u32 seclen,
> +	 struct lsm_prop *prop)
>   LSM_HOOK(void, LSM_RET_VOID, release_secctx, struct lsm_context *cp)
>   LSM_HOOK(void, LSM_RET_VOID, inode_invalidate_secctx, struct inode *inode)
>   LSM_HOOK(int, 0, inode_notifysecctx, struct inode *inode, void *ctx, u32 ctxlen)
> diff --git a/include/linux/security.h b/include/linux/security.h
> index 153e9043058f..19adc19eb9af 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -576,6 +576,11 @@ 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 lsmid);
>   int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
> +int security_secctx_to_lsmprop(const char *secdata, u32 seclen,
> +			       struct lsm_prop *prop, int lsmid);
> +
> +void security_update_lsmprop(struct lsm_prop *dest, struct lsm_prop *src,
> +			     int lsmid);
>   void security_release_secctx(struct lsm_context *cp);
>   void security_inode_invalidate_secctx(struct inode *inode);
>   int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen);
> @@ -1581,6 +1586,11 @@ static inline int security_lsmprop_to_secctx(struct lsm_prop *prop,
>   	return -EOPNOTSUPP;
>   }
>   
> +static inline void security_update_lsmprop(struct lsm_prop *dest,
> +					   struct lsm_prop *src, int lsmid)
> +{
> +}
> +
>   static inline int security_secctx_to_secid(const char *secdata,
>   					   u32 seclen,
>   					   u32 *secid)
> @@ -1588,6 +1598,12 @@ static inline int security_secctx_to_secid(const char *secdata,
>   	return -EOPNOTSUPP;
>   }
>   
> +static inline int security_secctx_to_lsmprop(const char *secdata, u32 seclen,
> +					     struct lsm_prop *prop, int lsmid)
> +{
> +	return -EOPNOTSUPP;
> +}
> +
>   static inline void security_release_secctx(struct lsm_context *cp)
>   {
>   }
> diff --git a/security/security.c b/security/security.c
> index 71aea8fdf014..1dec0037370b 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -3965,6 +3965,13 @@ int security_lsmprop_to_secctx(struct lsm_prop *prop, struct lsm_context *cp,
>   }
>   EXPORT_SYMBOL(security_lsmprop_to_secctx);
>   
> +void security_update_lsmprop(struct lsm_prop *dest, struct lsm_prop *src,
> +			     int lsmid)
> +{
> +	call_void_hook(update_lsmprop, dest, src, lsmid);
> +}
> +EXPORT_SYMBOL(security_update_lsmprop);
> +
>   /**
>    * security_secctx_to_secid() - Convert a secctx to a secid
>    * @secdata: secctx
> @@ -3982,6 +3989,31 @@ int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
>   }
>   EXPORT_SYMBOL(security_secctx_to_secid);
>   
> +/**
> + * security_secctx_to_lsmprop() - Convert a secctx to a lsmprop
> + * @secdata: secctx
> + * @seclen: length of secctx
> + * @prop: prop
> + * @lsmid: which LSM the context is appropriate to.
> + *
> + * Convert security context to an lsmprop.
> + *
> + * Return: Returns 0 on success, error on failure.
> + */
> +int security_secctx_to_lsmprop(const char *secdata, u32 seclen,
> +			       struct lsm_prop *prop, int lsmid)
> +{
> +	struct lsm_static_call *scall;
> +
> +	lsm_for_each_hook(scall, secctx_to_lsmprop) {
> +		if (lsmid != LSM_ID_UNDEF && lsmid != scall->hl->lsmid->id)
> +			continue;
> +		return scall->hl->hook.secctx_to_lsmprop(secdata, seclen, prop);
> +	}
> +	return LSM_RET_DEFAULT(secctx_to_lsmprop);
> +}
> +EXPORT_SYMBOL(security_secctx_to_lsmprop);
> +
>   /**
>    * security_release_secctx() - Free a secctx buffer
>    * @cp: the security context


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

end of thread, other threads:[~2026-09-03  9:40 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <20260902220150.18586-1-casey.ref@schaufler-ca.com>
2026-09-02 22:01 ` [PATCH v2 0/7] Change skb secmarks to x-array indexes Casey Schaufler
2026-09-02 22:01   ` [PATCH v2 1/7] net, smack: Create a function to set secmarks Casey Schaufler
2026-09-02 22:13     ` sashiko-bot
2026-09-03  5:35     ` John Johansen
2026-09-02 22:01   ` [PATCH v2 2/7] LSM: Implement x array functions for secmarks Casey Schaufler
2026-09-02 22:21     ` sashiko-bot
2026-09-03  5:36     ` John Johansen
2026-09-02 22:01   ` [PATCH v2 3/7] LSM: Two hooks for manipulating struct lsm_prop Casey Schaufler
2026-09-02 22:16     ` sashiko-bot
2026-09-03  9:40     ` John Johansen
2026-09-02 22:01   ` [PATCH v2 4/7] SELinux: hooks for secctx_to_lsmprop and update_lsmprop Casey Schaufler
2026-09-02 22:10     ` sashiko-bot
2026-09-03  6:10     ` John Johansen
2026-09-02 22:01   ` [PATCH v2 5/7] Smack: " Casey Schaufler
2026-09-02 22:17     ` sashiko-bot
2026-09-03  6:15     ` John Johansen
2026-09-02 22:01   ` [PATCH v2 6/7] Apparmor: " Casey Schaufler
2026-09-02 22:16     ` sashiko-bot
2026-09-03  9:39     ` John Johansen
2026-09-02 22:01   ` [PATCH v2 7/7] net, lsm: Change skb secmarks to x-array indexes Casey Schaufler
2026-09-02 22:15     ` sashiko-bot
2026-09-03  7:31     ` John Johansen

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.