* [PATCH 1/7] net, smack: Create a function to set secmarks
2026-08-31 22:37 ` [PATCH 0/7] Change skb secmarks to x-array indexes Casey Schaufler
@ 2026-08-31 22:37 ` Casey Schaufler
2026-08-31 22:57 ` sashiko-bot
2026-08-31 22:37 ` [PATCH 2/7] LSM: Implement x array functions for secmarks Casey Schaufler
` (5 subsequent siblings)
6 siblings, 1 reply; 17+ messages in thread
From: Casey Schaufler @ 2026-08-31 22:37 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] 17+ messages in thread* [PATCH 2/7] LSM: Implement x array functions for secmarks
2026-08-31 22:37 ` [PATCH 0/7] Change skb secmarks to x-array indexes Casey Schaufler
2026-08-31 22:37 ` [PATCH 1/7] net, smack: Create a function to set secmarks Casey Schaufler
@ 2026-08-31 22:37 ` Casey Schaufler
2026-08-31 22:59 ` sashiko-bot
2026-08-31 22:37 ` [PATCH 3/7] LSM: Two hooks for manipulating struct lsm_prop Casey Schaufler
` (4 subsequent siblings)
6 siblings, 1 reply; 17+ messages in thread
From: Casey Schaufler @ 2026-08-31 22:37 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 | 105 ++++++++++++++++++++++++++++++++++++++
3 files changed, 117 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..569c7f242b78 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..50ce613e35c0
--- /dev/null
+++ b/security/lsm_secxa.c
@@ -0,0 +1,105 @@
+// 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 CBS * @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; CBS }
+ }
+
+ 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; CBS
+}
+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] 17+ messages in thread* Re: [PATCH 2/7] LSM: Implement x array functions for secmarks
2026-08-31 22:37 ` [PATCH 2/7] LSM: Implement x array functions for secmarks Casey Schaufler
@ 2026-08-31 22:59 ` sashiko-bot
0 siblings, 0 replies; 17+ messages in thread
From: sashiko-bot @ 2026-08-31 22:59 UTC (permalink / raw)
Cc: selinux
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [High] Iterating over XArray without holding RCU read lock causes Use-After-Free.
- [High] Uninitialized stack memory compared via `memcmp` leads to unbounded memory leaks.
- [High] Missing validation of xa_load() returns leads to a NULL pointer dereference.
- [Medium] Time-of-check to time-of-use (TOCTOU) race condition allows duplicate entries in the xarray.
- [Low] Syntax error due to literal 'CBS' in source code.
--
commit a6930d2d8e929c19f0987dd477cc0280c1d486a1
Author: Casey Schaufler <casey@schaufler-ca.com>
LSM: Implement x array functions for secmarks
Implement, but don't use (yet) the functions required to use xarray
indexes in secmarks.
> diff --git a/security/lsm_secxa.c b/security/lsm_secxa.c
> new file mode 100644
> index 0000000000000..361ce6770edc4
> --- /dev/null
> +++ b/security/lsm_secxa.c
[ ... ]
> +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) {
[Severity: High]
Does this iteration need an RCU read lock or the xarray lock? Iterating
over an XArray locklessly without an RCU read lock can lead to a
use-after-free if concurrent calls split or free XArray nodes via RCU.
[Severity: Medium]
Is there a time-of-check to time-of-use (TOCTOU) race condition here?
This code checks for an existing property using xa_for_each(), and if
not found, inserts it later using xa_alloc_bh(). Without holding a lock
that spans both the check and the insertion, two threads could concurrently
observe the property missing and both insert identical properties at
different indices.
> + if (!memcmp(prop, lp, sizeof(*prop))) {
[Severity: High]
Can this memcmp() over the full sizeof(*prop) cause duplicate entries
and memory leaks? If callers allocate struct lsm_prop on the stack without
zero-initializing the entire structure, this comparison will include
uninitialized padding bytes. This could cause memcmp() to fail to match
existing identical properties, resulting in a new entry allocated for every
lookup and eventually exhausting the index space.
> + *secxa = il; return 0; CBS }
[Severity: Low]
This isn't a bug in logic, but is this literal CBS a typo? It appears
to be a syntax error that will prevent compilation.
> + }
> +
> + 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; CBS
[Severity: Low]
This isn't a bug in logic, but again, does this literal CBS cause a
compilation failure?
> +}
> +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)
> +{
[Severity: High]
Does this function properly validate xa_load() returns before dereferencing
them?
If the code evaluates:
olp = xa_load(&secxa_xa, skb->secmark);
prop = *olp;
Unconditionally dereferencing the pointer can lead to a kernel panic.
This can happen if an invalid or unmapped secmark is present on the packet,
such as one restored from a connection tracking entry synced from another
node.
> + if (!skb->secmark)
> + skb->secmark = secxa;
> +}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260831223748.4304-1-casey@schaufler-ca.com?part=2
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 3/7] LSM: Two hooks for manipulating struct lsm_prop
2026-08-31 22:37 ` [PATCH 0/7] Change skb secmarks to x-array indexes Casey Schaufler
2026-08-31 22:37 ` [PATCH 1/7] net, smack: Create a function to set secmarks Casey Schaufler
2026-08-31 22:37 ` [PATCH 2/7] LSM: Implement x array functions for secmarks Casey Schaufler
@ 2026-08-31 22:37 ` Casey Schaufler
2026-08-31 23:03 ` sashiko-bot
2026-08-31 22:37 ` [PATCH 4/7] SELinux: hooks for secctx_to_lsmprop and update_lsmprop Casey Schaufler
` (3 subsequent siblings)
6 siblings, 1 reply; 17+ messages in thread
From: Casey Schaufler @ 2026-08-31 22:37 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] 17+ messages in thread* Re: [PATCH 3/7] LSM: Two hooks for manipulating struct lsm_prop
2026-08-31 22:37 ` [PATCH 3/7] LSM: Two hooks for manipulating struct lsm_prop Casey Schaufler
@ 2026-08-31 23:03 ` sashiko-bot
0 siblings, 0 replies; 17+ messages in thread
From: sashiko-bot @ 2026-08-31 23:03 UTC (permalink / raw)
Cc: selinux
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] security_secctx_to_lsmprop() fails to zero-initialize the output `struct lsm_prop` before invoking the LSM hooks, leading to uninitialized memory usage, kernel stack leaks, and memory exhaustion.
--
commit 13e7b169a884dc3bcbf465977a96e0509ce74a40
Author: Casey Schaufler <casey@schaufler-ca.com>
LSM: Two hooks for manipulating struct lsm_prop
This commit introduces security_update_lsmprop() to update a destination
LSM property from a source, and security_secctx_to_lsmprop() to set an
LSM property based on a security context. LSM specific implementations
will follow.
> 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]
Does this code leave prop partially uninitialized?
If callers allocate struct lsm_prop on the stack without zeroing it (such as
in nft_secmark_compute_secid or checkentry_lsm), failing to call
lsmprop_init(prop) here before invoking the LSM hooks might leave stack
garbage in untouched fields.
When a single LSM populates its specific field, the remainder of the struct
could retain this uninitialized data.
Later on, if the caller passes this struct to secxa_from_lsmprop(), the
memcmp used for deduplication will evaluate the entire struct. Because of the
stack garbage, identical security contexts could fail the memcmp check.
This could lead to uninitialized kernel stack data being copied into new heap
allocations in the xarray, and potentially cause unbounded memory consumption
since identical contexts wouldn't be deduplicated as expected.
Should lsmprop_init(prop) be called before iterating over the hooks?
> + 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/20260831223748.4304-1-casey@schaufler-ca.com?part=3
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 4/7] SELinux: hooks for secctx_to_lsmprop and update_lsmprop
2026-08-31 22:37 ` [PATCH 0/7] Change skb secmarks to x-array indexes Casey Schaufler
` (2 preceding siblings ...)
2026-08-31 22:37 ` [PATCH 3/7] LSM: Two hooks for manipulating struct lsm_prop Casey Schaufler
@ 2026-08-31 22:37 ` Casey Schaufler
2026-08-31 22:55 ` sashiko-bot
2026-08-31 22:37 ` [PATCH 5/7] Smack: " Casey Schaufler
` (2 subsequent siblings)
6 siblings, 1 reply; 17+ messages in thread
From: Casey Schaufler @ 2026-08-31 22:37 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] 17+ messages in thread* [PATCH 5/7] Smack: hooks for secctx_to_lsmprop and update_lsmprop
2026-08-31 22:37 ` [PATCH 0/7] Change skb secmarks to x-array indexes Casey Schaufler
` (3 preceding siblings ...)
2026-08-31 22:37 ` [PATCH 4/7] SELinux: hooks for secctx_to_lsmprop and update_lsmprop Casey Schaufler
@ 2026-08-31 22:37 ` Casey Schaufler
2026-08-31 23:01 ` sashiko-bot
2026-08-31 22:37 ` [PATCH 6/7] Apparmor: " Casey Schaufler
2026-08-31 22:37 ` [PATCH 7/7] net, lsm: Change skb secmarks to x-array indexes Casey Schaufler
6 siblings, 1 reply; 17+ messages in thread
From: Casey Schaufler @ 2026-08-31 22:37 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] 17+ messages in thread* Re: [PATCH 5/7] Smack: hooks for secctx_to_lsmprop and update_lsmprop
2026-08-31 22:37 ` [PATCH 5/7] Smack: " Casey Schaufler
@ 2026-08-31 23:01 ` sashiko-bot
0 siblings, 0 replies; 17+ messages in thread
From: sashiko-bot @ 2026-08-31 23:01 UTC (permalink / raw)
Cc: selinux
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [High] `smack_secctx_to_lsmprop` sets `prop->smack.skp` to NULL for unknown contexts but returns success, leading to a later NULL pointer dereference in `smack_lsmprop_to_secctx`.
Pre-existing issues:
- [High] The `smack_secctx_to_lsmprop` function ignores the `seclen` parameter and passes a potentially non-NUL-terminated buffer to `smk_find_entry()`, resulting in an out-of-bounds read.
--
commit 7c2ef4130b3b7eeea3057be8cb9283a398ff6cf7
Author: Casey Schaufler <casey@schaufler-ca.com>
Smack: hooks for secctx_to_lsmprop and update_lsmprop
This commit implements the secctx_to_lsmprop and update_lsmprop hooks for
the Smack LSM module. These hooks provide conversions and updates between
security contexts and lsm_prop structures.
> 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);
[Severity: High]
This isn't a bug introduced by this patch, but does this ignore the seclen
parameter and pass a potentially non-NUL-terminated buffer to
smk_find_entry()?
If secdata comes from a netlink NLA_BINARY attribute and isn't inherently
NUL-terminated, passing it directly to smk_find_entry() will trigger an
out-of-bounds read, because smk_find_entry() in security/smack/smack_access.c
unconditionally calls strlen() on the string. This seems to duplicate a
pre-existing flaw from smack_secctx_to_secid, but re-establishes it in this
new API contract.
> +
> + return 0;
[Severity: High]
Can smk_find_entry() return NULL for an unknown context, and if so, is it
safe to return 0 (success) here?
If an unknown context is passed in, prop->smack.skp becomes NULL. Because
this returns 0, the caller (such as SECMARK via iptables) might assume the
property is fully populated. Later, if the system tries to convert this
property back to a security context string via smack_lsmprop_to_secctx(), it
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);
}
security/smack/smack_lsm.c:smack_to_secctx() {
int len = strlen(skp->smk_known);
...
}
Will this cause a NULL pointer dereference and kernel panic when skp is NULL?
> +}
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260831223748.4304-1-casey@schaufler-ca.com?part=5
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 6/7] Apparmor: hooks for secctx_to_lsmprop and update_lsmprop
2026-08-31 22:37 ` [PATCH 0/7] Change skb secmarks to x-array indexes Casey Schaufler
` (4 preceding siblings ...)
2026-08-31 22:37 ` [PATCH 5/7] Smack: " Casey Schaufler
@ 2026-08-31 22:37 ` Casey Schaufler
2026-08-31 23:00 ` sashiko-bot
2026-08-31 22:37 ` [PATCH 7/7] net, lsm: Change skb secmarks to x-array indexes Casey Schaufler
6 siblings, 1 reply; 17+ messages in thread
From: Casey Schaufler @ 2026-08-31 22:37 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] 17+ messages in thread* Re: [PATCH 6/7] Apparmor: hooks for secctx_to_lsmprop and update_lsmprop
2026-08-31 22:37 ` [PATCH 6/7] Apparmor: " Casey Schaufler
@ 2026-08-31 23:00 ` sashiko-bot
0 siblings, 0 replies; 17+ messages in thread
From: sashiko-bot @ 2026-08-31 23:00 UTC (permalink / raw)
Cc: selinux
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] apparmor_secctx_to_lsmprop and apparmor_secctx_to_secid leak aa_label reference counts.
--
commit 571cc7b76439569c095b0f5a60fbb3a11fc2aa6b
Author: Casey Schaufler <casey@schaufler-ca.com>
Apparmor: hooks for secctx_to_lsmprop and update_lsmprop
Implement the secctx_to_lsmprop and update_lsmprop hooks for AppArmor.
> 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 isn't a bug introduced by this patch, but apparmor_secctx_to_secid()
appears to leak the ref-counted aa_label object. When aa_label_strn_parse()
is called earlier in this function, it returns a label with an incremented
reference count. The secid is extracted, but aa_put_label() is never called
before returning, leaving the reference permanently leaked.
>
> +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 leak the newly acquired label reference?
When security_secctx_to_lsmprop() is called (for example, by
nft_secmark_compute_secid() to create a new nftables SECMARK rule),
aa_label_strn_parse() parses the string and returns an aa_label pointer
with an incremented reference count.
The reference is placed into prop->apparmor.label here, but since the
generic LSM framework treats struct lsm_prop as a transient unmanaged
container and lacks a release_lsmprop hook, this reference is never
dropped.
If the lsm_prop matches an existing entry in secxa_xa, secxa_from_lsmprop()
simply discards the duplicate prop, permanently leaking the newly acquired
reference. Since this is reachable by unprivileged userspaces configuring
SECMARK rules, could this be abused to cause memory exhaustion?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260831223748.4304-1-casey@schaufler-ca.com?part=6
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 7/7] net, lsm: Change skb secmarks to x-array indexes
2026-08-31 22:37 ` [PATCH 0/7] Change skb secmarks to x-array indexes Casey Schaufler
` (5 preceding siblings ...)
2026-08-31 22:37 ` [PATCH 6/7] Apparmor: " Casey Schaufler
@ 2026-08-31 22:37 ` Casey Schaufler
2026-08-31 23:07 ` sashiko-bot
6 siblings, 1 reply; 17+ messages in thread
From: Casey Schaufler @ 2026-08-31 22:37 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 | 4 +-
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 | 37 +++++++++++++----
security/security.c | 6 +--
security/selinux/hooks.c | 71 +++++++++++++++++++++++++++-----
security/smack/smack_lsm.c | 10 ++++-
security/smack/smack_netfilter.c | 10 +++--
12 files changed, 153 insertions(+), 42 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 569c7f242b78..5be9d64e67e4 100644
--- a/include/linux/lsm_secxa.h
+++ b/include/linux/lsm_secxa.h
@@ -7,11 +7,13 @@
#ifndef __LINUX_LSM_SECXA_H
#define __LINUX_LSM_SECXA_H
+#include <linux/types.h>
+
#ifdef CONFIG_SECURITY
struct lsm_prop;
-int secxa_from_lsmprop(struct lsm_prop *prop, u32 *secxa);
+int secxa_from_lsmprop(struct lsm_prop *prop, u32 *secxa);
int secxa_get_lsmprop(struct lsm_prop **pro, u32 secxa);
#endif /* CONFIG_SECURITY */
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 50ce613e35c0..2991aee204df 100644
--- a/security/lsm_secxa.c
+++ b/security/lsm_secxa.c
@@ -99,7 +104,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] 17+ messages in thread* Re: [PATCH 7/7] net, lsm: Change skb secmarks to x-array indexes
2026-08-31 22:37 ` [PATCH 7/7] net, lsm: Change skb secmarks to x-array indexes Casey Schaufler
@ 2026-08-31 23:07 ` sashiko-bot
0 siblings, 0 replies; 17+ messages in thread
From: sashiko-bot @ 2026-08-31 23:07 UTC (permalink / raw)
Cc: selinux
Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:
- [High] Uninitialized stack memory in `struct lsm_prop` causes duplicate xarray insertions and potential kernel stack leaks.
- [High] Unconditional NULL pointer dereference in `secxa_set_secmark` on invalid secmarks.
- [High] UAPI Breakage / Type Confusion in Netfilter conntrack secmark dumps.
- [High] Unconditional NULL pointer dereference in AppArmor secmark evaluation.
- [High] Uninitialized pointer dereference in `smack_from_skb` due to ignored error code.
- [Medium] Check-then-act (TOCTOU) race condition in `secxa_from_lsmprop`.
- [Low] Syntax error due to stray `CBS` tokens in `secxa_from_lsmprop`.
--
commit c9d03ed061e68de8297b30e74360121ca809d4cc
Author: Casey Schaufler <casey@schaufler-ca.com>
net, lsm: Change skb secmarks to x-array indexes
This commit changes skb->secmark to store an xarray index representing an
lsm_prop structure instead of a direct LSM secid. It updates various netfilter
modules and LSM hooks to translate between this index and the underlying
security properties.
> 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.
[Severity: High]
Are there missing updates for connection tracking? The commit updates
netfilter and iptables code, but it appears conntrack dumps via netlink
(ctnetlink_dump_secctx) and procfs (seq_print_acct) still pass ct->secmark
directly to security_secid_to_secctx(). Since the secmark is now an xarray
index rather than an LSM secid, won't this result in invalid memory lookups
and broken userspace dumps?
[ ... ]
> 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;
> + 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);
[Severity: High]
Can this leak uninitialized stack memory into the xarray cache? The tmp_prop
structure is declared on the stack without zeroing. When
security_secctx_to_lsmprop() populates it, it may only write to the specific
active LSM's fields, leaving the padding and other fields uninitialized.
Later, when secxa_from_lsmprop() performs a memcmp on this struct, the
uninitialized stack garbage will prevent matches on identical labels and cause
boundless duplicate entries to be allocated.
[ ... ]
> 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;
> 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);
> +
[Severity: High]
Similar to the issue in nft_secmark_compute_secid(), does this code also pass
an uninitialized struct lsm_prop to security_secctx_to_lsmprop()? This looks
like it could cause the same memcmp failures and duplicate xarray allocations.
[ ... ]
> 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
> @@ -365,12 +366,17 @@ static int aa_secmark_perm(struct aa_profile *profile, u32 request, u32 secid,
> struct apparmor_audit_data *ad)
> {
[ ... ]
> + 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 ||
[Severity: High]
Will this unconditionally dereference a NULL pointer if the packet was labeled
by a different LSM? If another LSM (like SELinux) populated the lsm_prop
structure but AppArmor did not, prop->apparmor.label would be NULL, causing
a panic when accessing its secid field.
[ ... ]
> diff --git a/security/lsm_secxa.c b/security/lsm_secxa.c
> index 361ce6770edc4..7ad6a6711f881 100644
> --- a/security/lsm_secxa.c
> +++ b/security/lsm_secxa.c
> @@ -99,7 +99,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]
Can xa_load() return NULL here and cause an unconditional NULL pointer
dereference? If network packets arrive with an invalid or untrusted secmark,
the xarray lookup could fail. Does this code need to check if olp and nlp
are valid before dereferencing them?
[ ... ]
> 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: High]
Does this code ignore the return value of secxa_get_lsmprop() and evaluate
an uninitialized pointer? If the lookup fails, prop remains uninitialized
and checking if (prop) will evaluate stack garbage, potentially leading to
a wild pointer dereference when accessing prop->smack.skp. Should this check
if (!rc) instead?
[ ... ]
Additionally, in the new secxa_from_lsmprop() function introduced in this
series:
[Severity: Low]
Is there a syntax error here that will prevent the kernel from compiling?
security/lsm_secxa.c:secxa_from_lsmprop() {
...
xa_for_each(&secxa_xa, il, lp) {
if (!memcmp(prop, lp, sizeof(*prop))) {
*secxa = il; return 0; CBS }
^^^
The CBS token appears to be a stray undeclared identifier at the end of the
return statement.
[Severity: Medium]
Is there a check-then-act (TOCTOU) race condition during concurrent xarray
insertions?
security/lsm_secxa.c:secxa_from_lsmprop() {
...
xa_for_each(&secxa_xa, il, lp) {
if (!memcmp(prop, lp, sizeof(*prop))) {
*secxa = il; return 0;
}
}
...
rc = xa_alloc_bh(&secxa_xa, &index, lp, xa_limit_31b, GFP_ATOMIC);
...
}
The lockless xa_for_each search and the subsequent xa_alloc_bh insertion
are not atomic. If two threads check for the same property simultaneously,
could they both fail the initial check and blindly insert duplicates into
the xarray cache?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260831223748.4304-1-casey@schaufler-ca.com?part=7
^ permalink raw reply [flat|nested] 17+ messages in thread