* [PATCH v6 0/5] lsm: introduce lsm_config_self_policy() and lsm_config_system_policy() syscalls
From: Maxime Bélair @ 2025-10-10 13:25 UTC (permalink / raw)
To: linux-security-module
Cc: john.johansen, paul, jmorris, serge, mic, kees,
stephen.smalley.work, casey, takedakn, penguin-kernel, song,
rdunlap, linux-api, apparmor, linux-kernel, Maxime Bélair
This patchset introduces two new syscalls: lsm_config_self_policy(),
lsm_config_system_policy() and the associated Linux Security Module hooks
security_lsm_config_*_policy(), providing a unified interface for loading
and managing LSM policies. These syscalls complement the existing per‑LSM
pseudo‑filesystem mechanism and work even when those filesystems are not
mounted or available.
With these new syscalls, users and administrators may lock down access to
the pseudo‑filesystem yet still manage LSM policies. Two tightly-scoped
entry points then replace the many file operations exposed by those
filesystems, significantly reducing the attack surface. This is
particularly useful in containers or processes already confined by
Landlock, where these pseudo‑filesystems are typically unavailable.
Because they provide a logical and unified interface, these syscalls are
simpler to use than several heterogeneous pseudo‑filesystems and avoid
edge cases such as partially loaded policies. They also eliminates VFS
overhead, yielding performance gains notably when many policies are
loaded, for instance at boot time.
This initial implementation is intentionally minimal to limit the scope
of changes. Currently, only policy loading is supported. This new LSM
hook is currently registered by AppArmor, SELinux and Smack. However, any
LSM can adopt this interface, and future patches could extend this
syscall to support more operations, such as replacing, removing, or
querying loaded policies.
Landlock already provides three Landlock‑specific syscalls (e.g.
landlock_add_rule()) to restrict ambient rights for sets of processes
without touching any pseudo-filesystem. lsm_config_*_policy() generalizes
that approach to the entire LSM layer, so any module can choose to
support either or both of these syscalls, and expose its policy
operations through a uniform interface and reap the advantages outlined
above.
This patchset is available at [1], a minimal user space example
showing how to use lsm_config_system_policy with AppArmor is at [2] and a
performance benchmark of both syscalls is available at [3].
[1] https://github.com/emixam16/linux/tree/lsm_syscall_v6
[2] https://gitlab.com/emixam16/apparmor/tree/lsm_syscall_v6
[3] https://gitlab.com/-/snippets/4864908
---
Changes in v6
- Add support for SELinux and Smack
Changes in v5
- Improve syscall input verification
- Do not export security_lsm_config_*_policy symbols
Changes in v4
- Make the syscall's maximum buffer size defined per module
- Fix a memory leak
Changes in v3
- Fix typos
Changes in v2
- Split lsm_manage_policy() into two distinct syscalls:
lsm_config_self_policy() and lsm_config_system_policy()
- The LSM hook now calls only the appropriate LSM (and not all LSMs)
- Add a configuration variable to limit the buffer size of these
syscalls
- AppArmor now allows stacking policies through lsm_config_self_policy()
and loading policies in any namespace through
lsm_config_system_policy()
---
Maxime Bélair (5):
Wire up lsm_config_self_policy and lsm_config_system_policy syscalls
lsm: introduce security_lsm_config_*_policy hooks
AppArmor: add support for lsm_config_self_policy and
lsm_config_system_policy
SELinux: add support for lsm_config_system_policy
Smack: add support for lsm_config_self_policy and
lsm_config_system_policy
arch/alpha/kernel/syscalls/syscall.tbl | 2 +
arch/arm/tools/syscall.tbl | 2 +
arch/m68k/kernel/syscalls/syscall.tbl | 2 +
arch/microblaze/kernel/syscalls/syscall.tbl | 2 +
arch/mips/kernel/syscalls/syscall_n32.tbl | 2 +
arch/mips/kernel/syscalls/syscall_n64.tbl | 2 +
arch/mips/kernel/syscalls/syscall_o32.tbl | 2 +
arch/parisc/kernel/syscalls/syscall.tbl | 2 +
arch/powerpc/kernel/syscalls/syscall.tbl | 2 +
arch/s390/kernel/syscalls/syscall.tbl | 2 +
arch/sh/kernel/syscalls/syscall.tbl | 2 +
arch/sparc/kernel/syscalls/syscall.tbl | 2 +
arch/x86/entry/syscalls/syscall_32.tbl | 2 +
arch/x86/entry/syscalls/syscall_64.tbl | 2 +
arch/xtensa/kernel/syscalls/syscall.tbl | 2 +
include/linux/lsm_hook_defs.h | 4 +
include/linux/security.h | 20 +++++
include/linux/syscalls.h | 5 ++
include/uapi/asm-generic/unistd.h | 6 +-
include/uapi/linux/lsm.h | 8 ++
kernel/sys_ni.c | 2 +
security/apparmor/apparmorfs.c | 31 +++++++
security/apparmor/include/apparmor.h | 4 +
security/apparmor/include/apparmorfs.h | 3 +
security/apparmor/lsm.c | 84 +++++++++++++++++++
security/lsm_syscalls.c | 21 +++++
security/security.c | 60 +++++++++++++
security/selinux/hooks.c | 27 ++++++
security/selinux/include/security.h | 7 ++
security/selinux/selinuxfs.c | 16 +++-
security/smack/smack.h | 8 ++
security/smack/smack_lsm.c | 73 ++++++++++++++++
security/smack/smackfs.c | 2 +-
tools/include/uapi/asm-generic/unistd.h | 6 +-
.../arch/x86/entry/syscalls/syscall_64.tbl | 2 +
35 files changed, 412 insertions(+), 7 deletions(-)
base-commit: 9c32cda43eb78f78c73aee4aa344b777714e259b
--
2.48.1
^ permalink raw reply
* [PATCH v6 2/5] lsm: introduce security_lsm_config_*_policy hooks
From: Maxime Bélair @ 2025-10-10 13:25 UTC (permalink / raw)
To: linux-security-module
Cc: john.johansen, paul, jmorris, serge, mic, kees,
stephen.smalley.work, casey, takedakn, penguin-kernel, song,
rdunlap, linux-api, apparmor, linux-kernel, Maxime Bélair
In-Reply-To: <20251010132610.12001-1-maxime.belair@canonical.com>
Define two new LSM hooks: security_lsm_config_self_policy and
security_lsm_config_system_policy and wire them into the corresponding
lsm_config_*_policy() syscalls so that LSMs can register a unified
interface for policy management. This initial, minimal implementation
only supports the LSM_POLICY_LOAD operation to limit changes.
Signed-off-by: Maxime Bélair <maxime.belair@canonical.com>
---
include/linux/lsm_hook_defs.h | 4 +++
include/linux/security.h | 20 ++++++++++++
include/uapi/linux/lsm.h | 8 +++++
security/lsm_syscalls.c | 13 ++++++--
security/security.c | 60 +++++++++++++++++++++++++++++++++++
5 files changed, 103 insertions(+), 2 deletions(-)
diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index bf3bbac4e02a..50b6e8aed787 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -464,3 +464,7 @@ LSM_HOOK(int, 0, bdev_alloc_security, struct block_device *bdev)
LSM_HOOK(void, LSM_RET_VOID, bdev_free_security, struct block_device *bdev)
LSM_HOOK(int, 0, bdev_setintegrity, struct block_device *bdev,
enum lsm_integrity_type type, const void *value, size_t size)
+LSM_HOOK(int, -EINVAL, lsm_config_self_policy, u32 op, void __user *buf,
+ size_t size, u32 flags)
+LSM_HOOK(int, -EINVAL, lsm_config_system_policy, u32 op,
+ void __user *buf, size_t size, u32 flags)
diff --git a/include/linux/security.h b/include/linux/security.h
index cc9b54d95d22..54acaee4a994 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -581,6 +581,11 @@ void security_bdev_free(struct block_device *bdev);
int security_bdev_setintegrity(struct block_device *bdev,
enum lsm_integrity_type type, const void *value,
size_t size);
+int security_lsm_config_self_policy(u32 lsm_id, u32 op, void __user *buf,
+ size_t size, u32 flags);
+int security_lsm_config_system_policy(u32 lsm_id, u32 op, void __user *buf,
+ size_t size, u32 flags);
+
#else /* CONFIG_SECURITY */
/**
@@ -1603,6 +1608,21 @@ static inline int security_bdev_setintegrity(struct block_device *bdev,
return 0;
}
+static inline int security_lsm_config_self_policy(u32 lsm_id, u32 op,
+ void __user *buf,
+ size_t size, u32 flags)
+{
+
+ return -EOPNOTSUPP;
+}
+
+static inline int security_lsm_config_system_policy(u32 lsm_id, u32 op,
+ void __user *buf,
+ size_t size, u32 flags)
+{
+
+ return -EOPNOTSUPP;
+}
#endif /* CONFIG_SECURITY */
#if defined(CONFIG_SECURITY) && defined(CONFIG_WATCH_QUEUE)
diff --git a/include/uapi/linux/lsm.h b/include/uapi/linux/lsm.h
index 938593dfd5da..2b9432a30cdc 100644
--- a/include/uapi/linux/lsm.h
+++ b/include/uapi/linux/lsm.h
@@ -90,4 +90,12 @@ struct lsm_ctx {
*/
#define LSM_FLAG_SINGLE 0x0001
+/*
+ * LSM_POLICY_XXX definitions identify the different operations
+ * to configure LSM policies
+ */
+
+#define LSM_POLICY_UNDEF 0
+#define LSM_POLICY_LOAD 100
+
#endif /* _UAPI_LINUX_LSM_H */
diff --git a/security/lsm_syscalls.c b/security/lsm_syscalls.c
index b02a7623dea6..0796673b6f19 100644
--- a/security/lsm_syscalls.c
+++ b/security/lsm_syscalls.c
@@ -122,11 +122,20 @@ SYSCALL_DEFINE3(lsm_list_modules, u64 __user *, ids, u32 __user *, size,
SYSCALL_DEFINE6(lsm_config_self_policy, u32, lsm_id, u32, op, void __user *,
buf, u32 __user, size, u32, common_flags, u32, flags)
{
- return 0;
+ if (common_flags) // Reserved for future use
+ return -EINVAL;
+
+ return security_lsm_config_self_policy(lsm_id, op, buf, size, flags);
}
SYSCALL_DEFINE6(lsm_config_system_policy, u32, lsm_id, u32, op, void __user *,
buf, u32 __user, size, u32, common_flags, u32, flags)
{
- return 0;
+ if (common_flags) // Reserved for future use
+ return -EINVAL;
+
+ if (!capable(CAP_MAC_ADMIN))
+ return -EPERM;
+
+ return security_lsm_config_system_policy(lsm_id, op, buf, size, flags);
}
diff --git a/security/security.c b/security/security.c
index fb57e8fddd91..eeb61b27cd56 100644
--- a/security/security.c
+++ b/security/security.c
@@ -5883,6 +5883,66 @@ int security_bdev_setintegrity(struct block_device *bdev,
}
EXPORT_SYMBOL(security_bdev_setintegrity);
+/**
+ * security_lsm_config_self_policy() - Configure caller's LSM policies
+ * @lsm_id: id of the LSM to target
+ * @op: Operation to perform (one of the LSM_POLICY_XXX values)
+ * @buf: userspace pointer to policy data
+ * @size: size of @buf
+ * @flags: lsm policy configuration flags
+ *
+ * Configure the policies of a LSM for the current domain/user. This notably
+ * allows to update them even when the lsmfs is unavailable or restricted.
+ * Currently, only LSM_POLICY_LOAD is supported.
+ *
+ * Return: Returns 0 on success, error on failure.
+ */
+int security_lsm_config_self_policy(u32 lsm_id, u32 op, void __user *buf,
+ size_t size, u32 flags)
+{
+ int rc = LSM_RET_DEFAULT(lsm_config_self_policy);
+ struct lsm_static_call *scall;
+
+ lsm_for_each_hook(scall, lsm_config_self_policy) {
+ if ((scall->hl->lsmid->id) == lsm_id) {
+ rc = scall->hl->hook.lsm_config_self_policy(op, buf, size, flags);
+ break;
+ }
+ }
+
+ return rc;
+}
+
+/**
+ * security_lsm_config_system_policy() - Configure system LSM policies
+ * @lsm_id: id of the lsm to target
+ * @op: Operation to perform (one of the LSM_POLICY_XXX values)
+ * @buf: userspace pointer to policy data
+ * @size: size of @buf
+ * @flags: lsm policy configuration flags
+ *
+ * Configure the policies of a LSM for the whole system. This notably allows
+ * to update them even when the lsmfs is unavailable or restricted. Currently,
+ * only LSM_POLICY_LOAD is supported.
+ *
+ * Return: Returns 0 on success, error on failure.
+ */
+int security_lsm_config_system_policy(u32 lsm_id, u32 op, void __user *buf,
+ size_t size, u32 flags)
+{
+ int rc = LSM_RET_DEFAULT(lsm_config_system_policy);
+ struct lsm_static_call *scall;
+
+ lsm_for_each_hook(scall, lsm_config_system_policy) {
+ if ((scall->hl->lsmid->id) == lsm_id) {
+ rc = scall->hl->hook.lsm_config_system_policy(op, buf, size, flags);
+ break;
+ }
+ }
+
+ return rc;
+}
+
#ifdef CONFIG_PERF_EVENTS
/**
* security_perf_event_open() - Check if a perf event open is allowed
--
2.48.1
^ permalink raw reply related
* [PATCH v6 3/5] AppArmor: add support for lsm_config_self_policy and lsm_config_system_policy
From: Maxime Bélair @ 2025-10-10 13:25 UTC (permalink / raw)
To: linux-security-module
Cc: john.johansen, paul, jmorris, serge, mic, kees,
stephen.smalley.work, casey, takedakn, penguin-kernel, song,
rdunlap, linux-api, apparmor, linux-kernel, Maxime Bélair
In-Reply-To: <20251010132610.12001-1-maxime.belair@canonical.com>
Enable users to manage AppArmor policies through the new hooks
lsm_config_self_policy and lsm_config_system_policy.
lsm_config_self_policy allows stacking existing policies in the kernel.
This ensures that it can only further restrict the caller and can never
be used to gain new privileges.
lsm_config_system_policy allows loading or replacing AppArmor policies in
any AppArmor namespace and is restricted to CAP_MAC_ADMIN.
Signed-off-by: Maxime Bélair <maxime.belair@canonical.com>
---
security/apparmor/apparmorfs.c | 31 ++++++++++
security/apparmor/include/apparmor.h | 4 ++
security/apparmor/include/apparmorfs.h | 3 +
security/apparmor/lsm.c | 84 ++++++++++++++++++++++++++
4 files changed, 122 insertions(+)
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index 6039afae4bfc..6df43299b045 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -439,6 +439,37 @@ static ssize_t policy_update(u32 mask, const char __user *buf, size_t size,
return error;
}
+/**
+ * aa_profile_load_ns_name - load a profile into the current namespace identified by name
+ * @name: The name of the namesapce to load the policy in. "" for root_ns
+ * @name_size: size of @name. 0 For root ns
+ * @buf: buffer containing the user-provided policy
+ * @size: size of @buf
+ * @ppos: position pointer in the file
+ *
+ * Returns: 0 on success, negative value on error
+ */
+ssize_t aa_profile_load_ns_name(char *name, size_t name_size, const void __user *buf,
+ size_t size, loff_t *ppos)
+{
+ struct aa_ns *ns;
+
+ if (name_size == 0)
+ ns = aa_get_ns(root_ns);
+ else
+ ns = aa_lookupn_ns(root_ns, name, name_size);
+
+ if (!ns)
+ return -EINVAL;
+
+ int error = policy_update(AA_MAY_LOAD_POLICY | AA_MAY_REPLACE_POLICY,
+ buf, size, ppos, ns);
+
+ aa_put_ns(ns);
+
+ return error >= 0 ? 0 : error;
+}
+
/* .load file hook fn to load policy */
static ssize_t profile_load(struct file *f, const char __user *buf, size_t size,
loff_t *pos)
diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h
index f83934913b0f..1d9a2881a8b9 100644
--- a/security/apparmor/include/apparmor.h
+++ b/security/apparmor/include/apparmor.h
@@ -62,5 +62,9 @@ extern unsigned int aa_g_path_max;
#define AA_DEFAULT_CLEVEL 0
#endif /* CONFIG_SECURITY_APPARMOR_EXPORT_BINARY */
+/* Syscall-related buffer size limits */
+
+#define AA_PROFILE_NAME_MAX_SIZE (1 << 9)
+#define AA_PROFILE_MAX_SIZE (1 << 28)
#endif /* __APPARMOR_H */
diff --git a/security/apparmor/include/apparmorfs.h b/security/apparmor/include/apparmorfs.h
index 1e94904f68d9..fd415afb7659 100644
--- a/security/apparmor/include/apparmorfs.h
+++ b/security/apparmor/include/apparmorfs.h
@@ -112,6 +112,9 @@ int __aafs_profile_mkdir(struct aa_profile *profile, struct dentry *parent);
void __aafs_ns_rmdir(struct aa_ns *ns);
int __aafs_ns_mkdir(struct aa_ns *ns, struct dentry *parent, const char *name,
struct dentry *dent);
+ssize_t aa_profile_load_ns_name(char *name, size_t name_len, const void __user *buf,
+ size_t size, loff_t *ppos);
+
struct aa_loaddata;
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 9b6c2f157f83..0c127f9dae19 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -1275,6 +1275,86 @@ static int apparmor_socket_shutdown(struct socket *sock, int how)
return aa_sock_perm(OP_SHUTDOWN, AA_MAY_SHUTDOWN, sock);
}
+/**
+ * apparmor_lsm_config_self_policy - Stack a profile
+ * @op: operation to perform. Currently, only LSM_POLICY_LOAD is supported
+ * @buf: buffer containing the user-provided name of the profile to stack
+ * @size: size of @buf
+ * @flags: reserved for future use; must be zero
+ *
+ * Returns: 0 on success, negative value on error
+ */
+static int apparmor_lsm_config_self_policy(u32 op, void __user *buf,
+ size_t size, u32 flags)
+{
+ char *name;
+ long name_size;
+ int ret;
+
+ if (op != LSM_POLICY_LOAD || flags)
+ return -EOPNOTSUPP;
+ if (size == 0)
+ return -EINVAL;
+ if (size > AA_PROFILE_NAME_MAX_SIZE)
+ return -E2BIG;
+
+ name = kmalloc(size, GFP_KERNEL);
+ if (!name)
+ return -ENOMEM;
+
+ name_size = strncpy_from_user(name, buf, size);
+ if (name_size <= 0) {
+ kfree(name);
+ return name_size;
+ } else if (name_size == size) {
+ kfree(name);
+ return -E2BIG;
+ }
+
+ ret = aa_change_profile(name, AA_CHANGE_STACK);
+
+ kfree(name);
+
+ return ret;
+}
+
+/**
+ * apparmor_lsm_config_system_policy - Load or replace a system policy
+ * @op: operation to perform. Currently, only LSM_POLICY_LOAD is supported
+ * @buf: user-supplied buffer in the form "<ns>\0<policy>"
+ * <ns> is the namespace to load the policy into (empty string for root)
+ * <policy> is the policy to load
+ * @size: size of @buf
+ * @flags: reserved for future uses; must be zero
+ *
+ * Returns: 0 on success, negative value on error
+ */
+static int apparmor_lsm_config_system_policy(u32 op, void __user *buf,
+ size_t size, u32 flags)
+{
+ loff_t pos = 0; // Partial writing is not currently supported
+ char ns_name[AA_PROFILE_NAME_MAX_SIZE];
+ size_t ns_size;
+ size_t max_ns_size = min(size, AA_PROFILE_NAME_MAX_SIZE);
+
+ if (op != LSM_POLICY_LOAD || flags)
+ return -EOPNOTSUPP;
+ if (size < 2)
+ return -EINVAL;
+ if (size > AA_PROFILE_MAX_SIZE)
+ return -E2BIG;
+
+ ns_size = strncpy_from_user(ns_name, buf, max_ns_size);
+ if (ns_size < 0)
+ return ns_size;
+ if (ns_size == max_ns_size)
+ return -E2BIG;
+
+ return aa_profile_load_ns_name(ns_name, ns_size, buf + ns_size + 1,
+ size - ns_size - 1, &pos);
+}
+
+
#ifdef CONFIG_NETWORK_SECMARK
/**
* apparmor_socket_sock_rcv_skb - check perms before associating skb to sk
@@ -1483,6 +1563,10 @@ static struct security_hook_list apparmor_hooks[] __ro_after_init = {
LSM_HOOK_INIT(socket_getsockopt, apparmor_socket_getsockopt),
LSM_HOOK_INIT(socket_setsockopt, apparmor_socket_setsockopt),
LSM_HOOK_INIT(socket_shutdown, apparmor_socket_shutdown),
+
+ LSM_HOOK_INIT(lsm_config_self_policy, apparmor_lsm_config_self_policy),
+ LSM_HOOK_INIT(lsm_config_system_policy,
+ apparmor_lsm_config_system_policy),
#ifdef CONFIG_NETWORK_SECMARK
LSM_HOOK_INIT(socket_sock_rcv_skb, apparmor_socket_sock_rcv_skb),
#endif
--
2.48.1
^ permalink raw reply related
* [PATCH v6 1/5] Wire up lsm_config_self_policy and lsm_config_system_policy syscalls
From: Maxime Bélair @ 2025-10-10 13:25 UTC (permalink / raw)
To: linux-security-module
Cc: john.johansen, paul, jmorris, serge, mic, kees,
stephen.smalley.work, casey, takedakn, penguin-kernel, song,
rdunlap, linux-api, apparmor, linux-kernel, Maxime Bélair
In-Reply-To: <20251010132610.12001-1-maxime.belair@canonical.com>
Add support for the new lsm_config_self_policy and
lsm_config_system_policy syscalls, providing a unified API for loading
and modifying LSM policies, for the current user and for the entire
system, respectively without requiring the LSM’s pseudo-filesystems.
Benefits:
- Works even if the LSM pseudo-filesystem isn’t mounted or available
(e.g. in containers)
- Offers a logical and unified interface rather than multiple
heterogeneous pseudo-filesystems
- Avoids the overhead of other kernel interfaces for better efficiency
Signed-off-by: Maxime Bélair <maxime.belair@canonical.com>
---
arch/alpha/kernel/syscalls/syscall.tbl | 2 ++
arch/arm/tools/syscall.tbl | 2 ++
arch/m68k/kernel/syscalls/syscall.tbl | 2 ++
arch/microblaze/kernel/syscalls/syscall.tbl | 2 ++
arch/mips/kernel/syscalls/syscall_n32.tbl | 2 ++
arch/mips/kernel/syscalls/syscall_n64.tbl | 2 ++
arch/mips/kernel/syscalls/syscall_o32.tbl | 2 ++
arch/parisc/kernel/syscalls/syscall.tbl | 2 ++
arch/powerpc/kernel/syscalls/syscall.tbl | 2 ++
arch/s390/kernel/syscalls/syscall.tbl | 2 ++
arch/sh/kernel/syscalls/syscall.tbl | 2 ++
arch/sparc/kernel/syscalls/syscall.tbl | 2 ++
arch/x86/entry/syscalls/syscall_32.tbl | 2 ++
arch/x86/entry/syscalls/syscall_64.tbl | 2 ++
arch/xtensa/kernel/syscalls/syscall.tbl | 2 ++
include/linux/syscalls.h | 5 +++++
include/uapi/asm-generic/unistd.h | 6 +++++-
kernel/sys_ni.c | 2 ++
security/lsm_syscalls.c | 12 ++++++++++++
tools/include/uapi/asm-generic/unistd.h | 6 +++++-
tools/perf/arch/x86/entry/syscalls/syscall_64.tbl | 2 ++
21 files changed, 61 insertions(+), 2 deletions(-)
diff --git a/arch/alpha/kernel/syscalls/syscall.tbl b/arch/alpha/kernel/syscalls/syscall.tbl
index 2dd6340de6b4..4fc75352220d 100644
--- a/arch/alpha/kernel/syscalls/syscall.tbl
+++ b/arch/alpha/kernel/syscalls/syscall.tbl
@@ -507,3 +507,5 @@
575 common listxattrat sys_listxattrat
576 common removexattrat sys_removexattrat
577 common open_tree_attr sys_open_tree_attr
+578 common lsm_config_self_policy sys_lsm_config_self_policy
+579 common lsm_config_system_policy sys_lsm_config_system_policy
diff --git a/arch/arm/tools/syscall.tbl b/arch/arm/tools/syscall.tbl
index 27c1d5ebcd91..326483cb94a4 100644
--- a/arch/arm/tools/syscall.tbl
+++ b/arch/arm/tools/syscall.tbl
@@ -482,3 +482,5 @@
465 common listxattrat sys_listxattrat
466 common removexattrat sys_removexattrat
467 common open_tree_attr sys_open_tree_attr
+468 common lsm_config_self_policy sys_lsm_config_self_policy
+469 common lsm_config_system_policy sys_lsm_config_system_policy
diff --git a/arch/m68k/kernel/syscalls/syscall.tbl b/arch/m68k/kernel/syscalls/syscall.tbl
index 9fe47112c586..d37364df1cd7 100644
--- a/arch/m68k/kernel/syscalls/syscall.tbl
+++ b/arch/m68k/kernel/syscalls/syscall.tbl
@@ -467,3 +467,5 @@
465 common listxattrat sys_listxattrat
466 common removexattrat sys_removexattrat
467 common open_tree_attr sys_open_tree_attr
+468 common lsm_config_self_policy sys_lsm_config_self_policy
+469 common lsm_config_system_policy sys_lsm_config_system_policy
diff --git a/arch/microblaze/kernel/syscalls/syscall.tbl b/arch/microblaze/kernel/syscalls/syscall.tbl
index 7b6e97828e55..9d58ebfcf967 100644
--- a/arch/microblaze/kernel/syscalls/syscall.tbl
+++ b/arch/microblaze/kernel/syscalls/syscall.tbl
@@ -473,3 +473,5 @@
465 common listxattrat sys_listxattrat
466 common removexattrat sys_removexattrat
467 common open_tree_attr sys_open_tree_attr
+468 common lsm_config_self_policy sys_lsm_config_self_policy
+469 common lsm_config_system_policy sys_lsm_config_system_policy
diff --git a/arch/mips/kernel/syscalls/syscall_n32.tbl b/arch/mips/kernel/syscalls/syscall_n32.tbl
index aa70e371bb54..8627b5f56280 100644
--- a/arch/mips/kernel/syscalls/syscall_n32.tbl
+++ b/arch/mips/kernel/syscalls/syscall_n32.tbl
@@ -406,3 +406,5 @@
465 n32 listxattrat sys_listxattrat
466 n32 removexattrat sys_removexattrat
467 n32 open_tree_attr sys_open_tree_attr
+468 n32 lsm_config_self_policy sys_lsm_config_self_policy
+469 n32 lsm_config_system_policy sys_lsm_config_system_policy
diff --git a/arch/mips/kernel/syscalls/syscall_n64.tbl b/arch/mips/kernel/syscalls/syscall_n64.tbl
index 1e8c44c7b614..813207b61f58 100644
--- a/arch/mips/kernel/syscalls/syscall_n64.tbl
+++ b/arch/mips/kernel/syscalls/syscall_n64.tbl
@@ -382,3 +382,5 @@
465 n64 listxattrat sys_listxattrat
466 n64 removexattrat sys_removexattrat
467 n64 open_tree_attr sys_open_tree_attr
+468 n64 lsm_config_self_policy sys_lsm_config_self_policy
+469 n64 lsm_config_system_policy sys_lsm_config_system_policy
diff --git a/arch/mips/kernel/syscalls/syscall_o32.tbl b/arch/mips/kernel/syscalls/syscall_o32.tbl
index 114a5a1a6230..9cd0946b4370 100644
--- a/arch/mips/kernel/syscalls/syscall_o32.tbl
+++ b/arch/mips/kernel/syscalls/syscall_o32.tbl
@@ -455,3 +455,5 @@
465 o32 listxattrat sys_listxattrat
466 o32 removexattrat sys_removexattrat
467 o32 open_tree_attr sys_open_tree_attr
+468 o32 lsm_config_self_policy sys_lsm_config_self_policy
+469 o32 lsm_config_system_policy sys_lsm_config_system_policy
diff --git a/arch/parisc/kernel/syscalls/syscall.tbl b/arch/parisc/kernel/syscalls/syscall.tbl
index 94df3cb957e9..9db01dd55793 100644
--- a/arch/parisc/kernel/syscalls/syscall.tbl
+++ b/arch/parisc/kernel/syscalls/syscall.tbl
@@ -466,3 +466,5 @@
465 common listxattrat sys_listxattrat
466 common removexattrat sys_removexattrat
467 common open_tree_attr sys_open_tree_attr
+468 common lsm_config_self_policy sys_lsm_config_self_policy
+469 common lsm_config_system_policy sys_lsm_config_system_policy
diff --git a/arch/powerpc/kernel/syscalls/syscall.tbl b/arch/powerpc/kernel/syscalls/syscall.tbl
index 9a084bdb8926..97714acb39ab 100644
--- a/arch/powerpc/kernel/syscalls/syscall.tbl
+++ b/arch/powerpc/kernel/syscalls/syscall.tbl
@@ -558,3 +558,5 @@
465 common listxattrat sys_listxattrat
466 common removexattrat sys_removexattrat
467 common open_tree_attr sys_open_tree_attr
+468 common lsm_config_self_policy sys_lsm_config_self_policy
+469 common lsm_config_system_policy sys_lsm_config_system_policy
diff --git a/arch/s390/kernel/syscalls/syscall.tbl b/arch/s390/kernel/syscalls/syscall.tbl
index a4569b96ef06..d2b0f14fb516 100644
--- a/arch/s390/kernel/syscalls/syscall.tbl
+++ b/arch/s390/kernel/syscalls/syscall.tbl
@@ -470,3 +470,5 @@
465 common listxattrat sys_listxattrat sys_listxattrat
466 common removexattrat sys_removexattrat sys_removexattrat
467 common open_tree_attr sys_open_tree_attr sys_open_tree_attr
+468 common lsm_config_self_policy sys_lsm_config_self_policy sys_lsm_config_self_policy
+469 common lsm_config_system_policy sys_lsm_config_system_policy sys_lsm_config_system_policy
diff --git a/arch/sh/kernel/syscalls/syscall.tbl b/arch/sh/kernel/syscalls/syscall.tbl
index 52a7652fcff6..210d7118ce16 100644
--- a/arch/sh/kernel/syscalls/syscall.tbl
+++ b/arch/sh/kernel/syscalls/syscall.tbl
@@ -471,3 +471,5 @@
465 common listxattrat sys_listxattrat
466 common removexattrat sys_removexattrat
467 common open_tree_attr sys_open_tree_attr
+468 common lsm_config_self_policy sys_lsm_config_self_policy
+469 common lsm_config_system_policy sys_lsm_config_system_policy
diff --git a/arch/sparc/kernel/syscalls/syscall.tbl b/arch/sparc/kernel/syscalls/syscall.tbl
index 83e45eb6c095..494417d80680 100644
--- a/arch/sparc/kernel/syscalls/syscall.tbl
+++ b/arch/sparc/kernel/syscalls/syscall.tbl
@@ -513,3 +513,5 @@
465 common listxattrat sys_listxattrat
466 common removexattrat sys_removexattrat
467 common open_tree_attr sys_open_tree_attr
+468 common lsm_config_self_policy sys_lsm_config_self_policy
+469 common lsm_config_system_policy sys_lsm_config_system_policy
diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl
index ac007ea00979..36c2c538e04f 100644
--- a/arch/x86/entry/syscalls/syscall_32.tbl
+++ b/arch/x86/entry/syscalls/syscall_32.tbl
@@ -473,3 +473,5 @@
465 i386 listxattrat sys_listxattrat
466 i386 removexattrat sys_removexattrat
467 i386 open_tree_attr sys_open_tree_attr
+468 i386 lsm_config_self_policy sys_lsm_config_self_policy
+469 i386 lsm_config_system_policy sys_lsm_config_system_policy
diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl
index cfb5ca41e30d..7eefbccfe531 100644
--- a/arch/x86/entry/syscalls/syscall_64.tbl
+++ b/arch/x86/entry/syscalls/syscall_64.tbl
@@ -391,6 +391,8 @@
465 common listxattrat sys_listxattrat
466 common removexattrat sys_removexattrat
467 common open_tree_attr sys_open_tree_attr
+468 common lsm_config_self_policy sys_lsm_config_self_policy
+469 common lsm_config_system_policy sys_lsm_config_system_policy
#
# Due to a historical design error, certain syscalls are numbered differently
diff --git a/arch/xtensa/kernel/syscalls/syscall.tbl b/arch/xtensa/kernel/syscalls/syscall.tbl
index f657a77314f8..90d86a54a952 100644
--- a/arch/xtensa/kernel/syscalls/syscall.tbl
+++ b/arch/xtensa/kernel/syscalls/syscall.tbl
@@ -438,3 +438,5 @@
465 common listxattrat sys_listxattrat
466 common removexattrat sys_removexattrat
467 common open_tree_attr sys_open_tree_attr
+468 common lsm_config_self_policy sys_lsm_config_self_policy
+469 common lsm_config_system_policy sys_lsm_config_system_policy
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index e5603cc91963..43b53fbd44be 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -988,6 +988,11 @@ asmlinkage long sys_lsm_get_self_attr(unsigned int attr, struct lsm_ctx __user *
asmlinkage long sys_lsm_set_self_attr(unsigned int attr, struct lsm_ctx __user *ctx,
u32 size, u32 flags);
asmlinkage long sys_lsm_list_modules(u64 __user *ids, u32 __user *size, u32 flags);
+asmlinkage long sys_lsm_config_self_policy(u32 lsm_id, u32 op, void __user *buf,
+ u32 __user size, u32 common_flags, u32 flags);
+asmlinkage long sys_lsm_config_system_policy(u32 lsm_id, u32 op, void __user *buf,
+ u32 __user size, u32 common_flags u32 flags);
+
/*
* Architecture-specific system calls
diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h
index 2892a45023af..021d0689c929 100644
--- a/include/uapi/asm-generic/unistd.h
+++ b/include/uapi/asm-generic/unistd.h
@@ -851,9 +851,13 @@ __SYSCALL(__NR_listxattrat, sys_listxattrat)
__SYSCALL(__NR_removexattrat, sys_removexattrat)
#define __NR_open_tree_attr 467
__SYSCALL(__NR_open_tree_attr, sys_open_tree_attr)
+#define __NR_lsm_config_self_policy 468
+__SYSCALL(__NR_lsm_config_self_policy, sys_lsm_config_self_policy)
+#define __NR_lsm_config_system_policy 469
+__SYSCALL(__NR_lsm_config_system_policy, sys_lsm_config_system_policy)
#undef __NR_syscalls
-#define __NR_syscalls 468
+#define __NR_syscalls 470
/*
* 32 bit systems traditionally used different
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index c00a86931f8c..3ecebcd3fbe0 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -172,6 +172,8 @@ COND_SYSCALL_COMPAT(fadvise64_64);
COND_SYSCALL(lsm_get_self_attr);
COND_SYSCALL(lsm_set_self_attr);
COND_SYSCALL(lsm_list_modules);
+COND_SYSCALL(lsm_config_self_policy);
+COND_SYSCALL(lsm_config_system_policy);
/* CONFIG_MMU only */
COND_SYSCALL(swapon);
diff --git a/security/lsm_syscalls.c b/security/lsm_syscalls.c
index 8440948a690c..b02a7623dea6 100644
--- a/security/lsm_syscalls.c
+++ b/security/lsm_syscalls.c
@@ -118,3 +118,15 @@ SYSCALL_DEFINE3(lsm_list_modules, u64 __user *, ids, u32 __user *, size,
return lsm_active_cnt;
}
+
+SYSCALL_DEFINE6(lsm_config_self_policy, u32, lsm_id, u32, op, void __user *,
+ buf, u32 __user, size, u32, common_flags, u32, flags)
+{
+ return 0;
+}
+
+SYSCALL_DEFINE6(lsm_config_system_policy, u32, lsm_id, u32, op, void __user *,
+ buf, u32 __user, size, u32, common_flags, u32, flags)
+{
+ return 0;
+}
diff --git a/tools/include/uapi/asm-generic/unistd.h b/tools/include/uapi/asm-generic/unistd.h
index 2892a45023af..021d0689c929 100644
--- a/tools/include/uapi/asm-generic/unistd.h
+++ b/tools/include/uapi/asm-generic/unistd.h
@@ -851,9 +851,13 @@ __SYSCALL(__NR_listxattrat, sys_listxattrat)
__SYSCALL(__NR_removexattrat, sys_removexattrat)
#define __NR_open_tree_attr 467
__SYSCALL(__NR_open_tree_attr, sys_open_tree_attr)
+#define __NR_lsm_config_self_policy 468
+__SYSCALL(__NR_lsm_config_self_policy, sys_lsm_config_self_policy)
+#define __NR_lsm_config_system_policy 469
+__SYSCALL(__NR_lsm_config_system_policy, sys_lsm_config_system_policy)
#undef __NR_syscalls
-#define __NR_syscalls 468
+#define __NR_syscalls 470
/*
* 32 bit systems traditionally used different
diff --git a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl
index cfb5ca41e30d..7eefbccfe531 100644
--- a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl
+++ b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl
@@ -391,6 +391,8 @@
465 common listxattrat sys_listxattrat
466 common removexattrat sys_removexattrat
467 common open_tree_attr sys_open_tree_attr
+468 common lsm_config_self_policy sys_lsm_config_self_policy
+469 common lsm_config_system_policy sys_lsm_config_system_policy
#
# Due to a historical design error, certain syscalls are numbered differently
--
2.48.1
^ permalink raw reply related
* [PATCH v6 4/5] SELinux: add support for lsm_config_system_policy
From: Maxime Bélair @ 2025-10-10 13:25 UTC (permalink / raw)
To: linux-security-module
Cc: john.johansen, paul, jmorris, serge, mic, kees,
stephen.smalley.work, casey, takedakn, penguin-kernel, song,
rdunlap, linux-api, apparmor, linux-kernel, Maxime Bélair
In-Reply-To: <20251010132610.12001-1-maxime.belair@canonical.com>
Enable users to manage SELinux policies through the new hook
lsm_config_system_policy. This feature is restricted to CAP_MAC_ADMIN.
Signed-off-by: Maxime Bélair <maxime.belair@canonical.com>
---
security/selinux/hooks.c | 27 +++++++++++++++++++++++++++
security/selinux/include/security.h | 7 +++++++
security/selinux/selinuxfs.c | 16 ++++++++++++----
3 files changed, 46 insertions(+), 4 deletions(-)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index e7a7dcab81db..3d14d4e47937 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -7196,6 +7196,31 @@ static int selinux_uring_allowed(void)
}
#endif /* CONFIG_IO_URING */
+/**
+ * selinux_lsm_config_system_policy - Manage a LSM policy
+ * @op: operation to perform. Currently, only LSM_POLICY_LOAD is supported
+ * @buf: User-supplied buffer
+ * @size: size of @buf
+ * @flags: reserved for future use; must be zero
+ *
+ * Returns: number of written rules on success, negative value on error
+ */
+static int selinux_lsm_config_system_policy(u32 op, void __user *buf,
+ size_t size, u32 flags)
+{
+ loff_t pos = 0;
+
+ if (op != LSM_POLICY_LOAD || flags)
+ return -EOPNOTSUPP;
+
+ if (!selinux_null.dentry || !selinux_null.dentry->d_sb ||
+ !selinux_null.dentry->d_sb->s_fs_info)
+ return -ENODEV;
+
+ return __sel_write_load(selinux_null.dentry->d_sb->s_fs_info, buf, size,
+ &pos);
+}
+
static const struct lsm_id selinux_lsmid = {
.name = "selinux",
.id = LSM_ID_SELINUX,
@@ -7499,6 +7524,8 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = {
#ifdef CONFIG_PERF_EVENTS
LSM_HOOK_INIT(perf_event_alloc, selinux_perf_event_alloc),
#endif
+ LSM_HOOK_INIT(lsm_config_system_policy, selinux_lsm_config_system_policy),
+
};
static __init int selinux_init(void)
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index e7827ed7be5f..7b779ea43cc3 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -389,7 +389,14 @@ struct selinux_kernel_status {
extern void selinux_status_update_setenforce(bool enforcing);
extern void selinux_status_update_policyload(u32 seqno);
extern void selinux_complete_init(void);
+
+struct selinux_fs_info;
+
extern struct path selinux_null;
+extern ssize_t __sel_write_load(struct selinux_fs_info *fsi,
+ const char __user *buf, size_t count,
+ loff_t *ppos);
+
extern void selnl_notify_setenforce(int val);
extern void selnl_notify_policyload(u32 seqno);
extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 47480eb2189b..1f7e611d8300 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -567,11 +567,11 @@ static int sel_make_policy_nodes(struct selinux_fs_info *fsi,
return ret;
}
-static ssize_t sel_write_load(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
+ssize_t __sel_write_load(struct selinux_fs_info *fsi,
+ const char __user *buf, size_t count,
+ loff_t *ppos)
{
- struct selinux_fs_info *fsi;
struct selinux_load_state load_state;
ssize_t length;
void *data = NULL;
@@ -605,7 +605,6 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf,
pr_warn_ratelimited("SELinux: failed to load policy\n");
goto out;
}
- fsi = file_inode(file)->i_sb->s_fs_info;
length = sel_make_policy_nodes(fsi, load_state.policy);
if (length) {
pr_warn_ratelimited("SELinux: failed to initialize selinuxfs\n");
@@ -626,6 +625,15 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf,
return length;
}
+static ssize_t sel_write_load(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
+
+ return __sel_write_load(fsi, buf, count, ppos);
+}
+
+
static const struct file_operations sel_load_ops = {
.write = sel_write_load,
.llseek = generic_file_llseek,
--
2.48.1
^ permalink raw reply related
* Re: [PATCH v5 0/3] lsm: introduce lsm_config_self_policy() and lsm_config_system_policy() syscalls
From: Maxime Bélair @ 2025-10-10 13:34 UTC (permalink / raw)
To: Casey Schaufler, linux-security-module
Cc: john.johansen, paul, jmorris, serge, mic, kees,
stephen.smalley.work, takedakn, penguin-kernel, song, rdunlap,
linux-api, apparmor, linux-kernel
In-Reply-To: <5ae541ce-613f-47c0-8a23-1ec9a0b346cf@schaufler-ca.com>
On 7/9/25 18:48, Casey Schaufler wrote:
> On 7/9/2025 1:00 AM, Maxime Bélair wrote:
>> This patchset introduces two new syscalls: lsm_config_self_policy(),
>> lsm_config_system_policy() and the associated Linux Security Module hooks
>> security_lsm_config_*_policy(), providing a unified interface for loading
>> and managing LSM policies. These syscalls complement the existing per‑LSM
>> pseudo‑filesystem mechanism and work even when those filesystems are not
>> mounted or available.
>>
>> With these new syscalls, users and administrators may lock down access to
>> the pseudo‑filesystem yet still manage LSM policies. Two tightly-scoped
>> entry points then replace the many file operations exposed by those
>> filesystems, significantly reducing the attack surface. This is
>> particularly useful in containers or processes already confined by
>> Landlock, where these pseudo‑filesystems are typically unavailable.
>>
>> Because they provide a logical and unified interface, these syscalls are
>> simpler to use than several heterogeneous pseudo‑filesystems and avoid
>> edge cases such as partially loaded policies. They also eliminates VFS
>> overhead, yielding performance gains notably when many policies are
>> loaded, for instance at boot time.
>>
>> This initial implementation is intentionally minimal to limit the scope
>> of changes. Currently, only policy loading is supported, and only
>> AppArmor registers this LSM hook. However, any LSM can adopt this
>> interface, and future patches could extend this syscall to support more
>> operations, such as replacing, removing, or querying loaded policies.
>
> It would help me be more confident in the interface if you also included
> hooks for SELinux and Smack. The API needs to be general enough to support
> SELinux's atomic policy load, Smack's atomic and incremental load options,
> and Smack's self rule loads. I really don't want to have to implement
> lsm_config_self_policy2() when I decide to us it for Smack.
>
I provided a minimal initial implementation for SELinux and Smack in v6.
For SELinux, I implemented only lsm_config_system_policy, which
currently allows to load policies with this syscall.
For Smack, I supported both hooks, allowing modification of both global
and subject rules. However since modifying even the subject rules is a
privileged operation, both operation are limited to CAP_MAC_ADMIN.
If we could ensure that the new rules only further restrict capabilities,
we could allow to load subject rules with fewer privileges.
>>
>> Landlock already provides three Landlock‑specific syscalls (e.g.
>> landlock_add_rule()) to restrict ambient rights for sets of processes
>> without touching any pseudo-filesystem. lsm_config_*_policy() generalizes
>> that approach to the entire LSM layer, so any module can choose to
>> support either or both of these syscalls, and expose its policy
>> operations through a uniform interface and reap the advantages outlined
>> above.
>>
>> This patchset is available at [1], a minimal user space example
>> showing how to use lsm_config_system_policy with AppArmor is at [2] and a
>> performance benchmark of both syscalls is available at [3].
>>
>> [1] https://github.com/emixam16/linux/tree/lsm_syscall
>> [2] https://gitlab.com/emixam16/apparmor/tree/lsm_syscall
>> [3] https://gitlab.com/-/snippets/4864908
>>
>> ---
>> Changes in v5
>> - Improve syscall input verification
>> - Do not export security_lsm_config_*_policy symbols
>>
>> Changes in v4
>> - Make the syscall's maximum buffer size defined per module
>> - Fix a memory leak
>>
>> Changes in v3
>> - Fix typos
>>
>> Changes in v2
>> - Split lsm_manage_policy() into two distinct syscalls:
>> lsm_config_self_policy() and lsm_config_system_policy()
>> - The LSM hook now calls only the appropriate LSM (and not all LSMs)
>> - Add a configuration variable to limit the buffer size of these
>> syscalls
>> - AppArmor now allows stacking policies through lsm_config_self_policy()
>> and loading policies in any namespace through
>> lsm_config_system_policy()
>> ---
>>
>> Maxime Bélair (3):
>> Wire up lsm_config_self_policy and lsm_config_system_policy syscalls
>> lsm: introduce security_lsm_config_*_policy hooks
>> AppArmor: add support for lsm_config_self_policy and
>> lsm_config_system_policy
>>
>> arch/alpha/kernel/syscalls/syscall.tbl | 2 +
>> arch/arm/tools/syscall.tbl | 2 +
>> arch/m68k/kernel/syscalls/syscall.tbl | 2 +
>> arch/microblaze/kernel/syscalls/syscall.tbl | 2 +
>> arch/mips/kernel/syscalls/syscall_n32.tbl | 2 +
>> arch/mips/kernel/syscalls/syscall_n64.tbl | 2 +
>> arch/mips/kernel/syscalls/syscall_o32.tbl | 2 +
>> arch/parisc/kernel/syscalls/syscall.tbl | 2 +
>> arch/powerpc/kernel/syscalls/syscall.tbl | 2 +
>> arch/s390/kernel/syscalls/syscall.tbl | 2 +
>> arch/sh/kernel/syscalls/syscall.tbl | 2 +
>> arch/sparc/kernel/syscalls/syscall.tbl | 2 +
>> arch/x86/entry/syscalls/syscall_32.tbl | 2 +
>> arch/x86/entry/syscalls/syscall_64.tbl | 2 +
>> arch/xtensa/kernel/syscalls/syscall.tbl | 2 +
>> include/linux/lsm_hook_defs.h | 4 +
>> include/linux/security.h | 20 +++++
>> include/linux/syscalls.h | 5 ++
>> include/uapi/asm-generic/unistd.h | 6 +-
>> include/uapi/linux/lsm.h | 8 ++
>> kernel/sys_ni.c | 2 +
>> security/apparmor/apparmorfs.c | 31 +++++++
>> security/apparmor/include/apparmor.h | 4 +
>> security/apparmor/include/apparmorfs.h | 3 +
>> security/apparmor/lsm.c | 84 +++++++++++++++++++
>> security/lsm_syscalls.c | 25 ++++++
>> security/security.c | 60 +++++++++++++
>> tools/include/uapi/asm-generic/unistd.h | 6 +-
>> .../arch/x86/entry/syscalls/syscall_64.tbl | 2 +
>> 29 files changed, 288 insertions(+), 2 deletions(-)
>>
>>
>> base-commit: 9c32cda43eb78f78c73aee4aa344b777714e259b
^ permalink raw reply
* Re: [PATCH v5 2/3] lsm: introduce security_lsm_config_*_policy hooks
From: Maxime Bélair @ 2025-10-10 13:32 UTC (permalink / raw)
To: Mickaël Salaün
Cc: linux-security-module, john.johansen, paul, jmorris, serge, kees,
stephen.smalley.work, casey, takedakn, penguin-kernel, song,
rdunlap, linux-api, apparmor, linux-kernel
In-Reply-To: <20250820.Ao3iquoshaiB@digikod.net>
On 8/20/25 16:21, Mickaël Salaün wrote:
> On Wed, Jul 09, 2025 at 10:00:55AM +0200, Maxime Bélair wrote:
>> Define two new LSM hooks: security_lsm_config_self_policy and
>> security_lsm_config_system_policy and wire them into the corresponding
>> lsm_config_*_policy() syscalls so that LSMs can register a unified
>> interface for policy management. This initial, minimal implementation
>> only supports the LSM_POLICY_LOAD operation to limit changes.
>>
>> Signed-off-by: Maxime Bélair <maxime.belair@canonical.com>
>> ---
>> include/linux/lsm_hook_defs.h | 4 +++
>> include/linux/security.h | 20 ++++++++++++
>> include/uapi/linux/lsm.h | 8 +++++
>> security/lsm_syscalls.c | 17 ++++++++--
>> security/security.c | 60 +++++++++++++++++++++++++++++++++++
>> 5 files changed, 107 insertions(+), 2 deletions(-)
>>
>> diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
>> index bf3bbac4e02a..fca490444643 100644
>> --- a/include/linux/lsm_hook_defs.h
>> +++ b/include/linux/lsm_hook_defs.h
>> @@ -464,3 +464,7 @@ LSM_HOOK(int, 0, bdev_alloc_security, struct block_device *bdev)
>> LSM_HOOK(void, LSM_RET_VOID, bdev_free_security, struct block_device *bdev)
>> LSM_HOOK(int, 0, bdev_setintegrity, struct block_device *bdev,
>> enum lsm_integrity_type type, const void *value, size_t size)
>> +LSM_HOOK(int, -EINVAL, lsm_config_self_policy, u32 lsm_id, u32 op,
>> + void __user *buf, size_t size, u32 flags)
>> +LSM_HOOK(int, -EINVAL, lsm_config_system_policy, u32 lsm_id, u32 op,
>> + void __user *buf, size_t size, u32 flags)
>> diff --git a/include/linux/security.h b/include/linux/security.h
>> index cc9b54d95d22..54acaee4a994 100644
>> --- a/include/linux/security.h
>> +++ b/include/linux/security.h
>> @@ -581,6 +581,11 @@ void security_bdev_free(struct block_device *bdev);
>> int security_bdev_setintegrity(struct block_device *bdev,
>> enum lsm_integrity_type type, const void *value,
>> size_t size);
>> +int security_lsm_config_self_policy(u32 lsm_id, u32 op, void __user *buf,
>> + size_t size, u32 flags);
>> +int security_lsm_config_system_policy(u32 lsm_id, u32 op, void __user *buf,
>> + size_t size, u32 flags);
>> +
>> #else /* CONFIG_SECURITY */
>>
>> /**
>> @@ -1603,6 +1608,21 @@ static inline int security_bdev_setintegrity(struct block_device *bdev,
>> return 0;
>> }
>>
>> +static inline int security_lsm_config_self_policy(u32 lsm_id, u32 op,
>> + void __user *buf,
>> + size_t size, u32 flags)
>> +{
>> +
>> + return -EOPNOTSUPP;
>> +}
>> +
>> +static inline int security_lsm_config_system_policy(u32 lsm_id, u32 op,
>> + void __user *buf,
>> + size_t size, u32 flags)
>> +{
>> +
>> + return -EOPNOTSUPP;
>> +}
>> #endif /* CONFIG_SECURITY */
>>
>> #if defined(CONFIG_SECURITY) && defined(CONFIG_WATCH_QUEUE)
>> diff --git a/include/uapi/linux/lsm.h b/include/uapi/linux/lsm.h
>> index 938593dfd5da..2b9432a30cdc 100644
>> --- a/include/uapi/linux/lsm.h
>> +++ b/include/uapi/linux/lsm.h
>> @@ -90,4 +90,12 @@ struct lsm_ctx {
>> */
>> #define LSM_FLAG_SINGLE 0x0001
>>
>> +/*
>> + * LSM_POLICY_XXX definitions identify the different operations
>> + * to configure LSM policies
>> + */
>> +
>> +#define LSM_POLICY_UNDEF 0
>> +#define LSM_POLICY_LOAD 100
>
> Why the gap between 0 and 100?
>
>> +
>> #endif /* _UAPI_LINUX_LSM_H */
>> diff --git a/security/lsm_syscalls.c b/security/lsm_syscalls.c
>> index a3cb6dab8102..dd016ba6976c 100644
>> --- a/security/lsm_syscalls.c
>> +++ b/security/lsm_syscalls.c
>> @@ -122,11 +122,24 @@ SYSCALL_DEFINE3(lsm_list_modules, u64 __user *, ids, u32 __user *, size,
>> SYSCALL_DEFINE5(lsm_config_self_policy, u32, lsm_id, u32, op, void __user *,
>> buf, u32 __user *, size, u32, flags)
>
> Given these are a multiplexor syscalls, I'm wondering if they should not
> have common flags and LSM-specific flags. Alternatively, the op
> argument could also contains some optional flags. In either case, the
> documentation should guide LSM developers for flags that may be shared
> amongst LSMs.
>
> Examples of such flags could be to restrict the whole process instead of
> the calling thread.
>
Indeed, in v6 I used both common_flags and flags. For now I didn't
support any of them to keep this patchset simple but we could discuss
which flags we want to support.
>> {
>> - return 0;
>> + size_t usize;
>> +
>> + if (get_user(usize, size))
>
> Size should just be u32, not a pointer.
Indeed
>
>> + return -EFAULT;
>> +
>> + return security_lsm_config_self_policy(lsm_id, op, buf, usize, flags);
>> }
>>
>> SYSCALL_DEFINE5(lsm_config_system_policy, u32, lsm_id, u32, op, void __user *,
>> buf, u32 __user *, size, u32, flags)
>> {
>> - return 0;
>> + size_t usize;
>> +
>> + if (!capable(CAP_SYS_ADMIN))
>> + return -EPERM;
>
> I like this mandatory capability check for this specific syscall. This
> makes the semantic clearer. However, to avoid the superpower of
> CAP_SYS_ADMIN, I'm wondering how we could use the CAP_MAC_ADMIN instead.
> This syscall could require CAP_MAC_ADMIN, and current LSMs (relying on a
> filesystem interface for policy configuration) could also enforce
> CAP_SYS_ADMIN for compatibility reasons.
I agree and lsm_config_system_policy is now restricted to CAP_MAC_ADMIN
in v6.
>
> In fact, this "system" syscall could be a "namespace" syscall, which
> would take a security/LSM namespace file descriptor as argument. If the
> namespace is not the initial namespace, any CAP_SYS_ADMIN implemented by
> current LSMs could be avoided. See
> https://lore.kernel.org/r/CAHC9VhRGMmhxbajwQNfGFy+ZFF1uN=UEBjqQZQ4UBy7yds3eVQ@mail.gmail.com
I would appreciate additional feedback on the best way to handle
namespaces for this syscall.
Possible approaches include:
- Passing a value in buf (as I did patch v6 3/5 for AppArmor). This is
simple and let individual LSM handle namespaces as see fit. However,
it may slightly complicate the policy format.
- Passing a file descriptor as a syscall argument. This offers a cleaner
interface but couples the pseudofs to this syscall, reducing some of
its advantages.
- Providing no support for namespaces at this time.
I tend to prefer the first approach here but I'm open to suggestions
>
>> +
>> + if (get_user(usize, size))
>
> ditto
>
>> + return -EFAULT;
>> +
>> + return security_lsm_config_system_policy(lsm_id, op, buf, usize, flags);
>> }
>> diff --git a/security/security.c b/security/security.c
>> index fb57e8fddd91..166d7d9936d0 100644
>> --- a/security/security.c
>> +++ b/security/security.c
>> @@ -5883,6 +5883,66 @@ int security_bdev_setintegrity(struct block_device *bdev,
>> }
>> EXPORT_SYMBOL(security_bdev_setintegrity);
>>
>> +/**
>> + * security_lsm_config_self_policy() - Configure caller's LSM policies
>> + * @lsm_id: id of the LSM to target
>> + * @op: Operation to perform (one of the LSM_POLICY_XXX values)
>> + * @buf: userspace pointer to policy data
>> + * @size: size of @buf
>> + * @flags: lsm policy configuration flags
>> + *
>> + * Configure the policies of a LSM for the current domain/user. This notably
>> + * allows to update them even when the lsmfs is unavailable or restricted.
>> + * Currently, only LSM_POLICY_LOAD is supported.
>> + *
>> + * Return: Returns 0 on success, error on failure.
>> + */
>> +int security_lsm_config_self_policy(u32 lsm_id, u32 op, void __user *buf,
>> + size_t size, u32 flags)
>> +{
>> + int rc = LSM_RET_DEFAULT(lsm_config_self_policy);
>> + struct lsm_static_call *scall;
>> +
>> + lsm_for_each_hook(scall, lsm_config_self_policy) {
>> + if ((scall->hl->lsmid->id) == lsm_id) {
>> + rc = scall->hl->hook.lsm_config_self_policy(lsm_id, op, buf, size, flags);
>
> The lsm_id should not be passed to the hook.
Indeed
>
> The LSM syscall should manage the argument copy and buffer allocation
> instead of duplicating this code in each LSM hook implementation (see
> other LSM syscalls).
I get your point but methods used internally by LSMs already handle the
allocation themselves through a char __user * parameter.
- smack: smk_write_rules_list
- selinux: sel_write_load
- apparmor: policy_update
Hence, I think that it's actually better to let LSMs handle allocations
>
>> + break;
>> + }
>> + }
>> +
>> + return rc;
>> +}
>> +
>> +/**
>> + * security_lsm_config_system_policy() - Configure system LSM policies
>> + * @lsm_id: id of the lsm to target
>> + * @op: Operation to perform (one of the LSM_POLICY_XXX values)
>> + * @buf: userspace pointer to policy data
>> + * @size: size of @buf
>> + * @flags: lsm policy configuration flags
>> + *
>> + * Configure the policies of a LSM for the whole system. This notably allows
>> + * to update them even when the lsmfs is unavailable or restricted. Currently,
>> + * only LSM_POLICY_LOAD is supported.
>> + *
>> + * Return: Returns 0 on success, error on failure.
>> + */
>> +int security_lsm_config_system_policy(u32 lsm_id, u32 op, void __user *buf,
>> + size_t size, u32 flags)
>> +{
>> + int rc = LSM_RET_DEFAULT(lsm_config_system_policy);
>> + struct lsm_static_call *scall;
>> +
>> + lsm_for_each_hook(scall, lsm_config_system_policy) {
>> + if ((scall->hl->lsmid->id) == lsm_id) {
>> + rc = scall->hl->hook.lsm_config_system_policy(lsm_id, op, buf, size, flags);
>
> ditto
>
>> + break;
>> + }
>> + }
>> +
>> + return rc;
>> +}
>> +
>> #ifdef CONFIG_PERF_EVENTS
>> /**
>> * security_perf_event_open() - Check if a perf event open is allowed
>> --
>> 2.48.1
>>
>>
^ permalink raw reply
* [PATCH v6 5/5] Smack: add support for lsm_config_self_policy and lsm_config_system_policy
From: Maxime Bélair @ 2025-10-10 13:25 UTC (permalink / raw)
To: linux-security-module
Cc: john.johansen, paul, jmorris, serge, mic, kees,
stephen.smalley.work, casey, takedakn, penguin-kernel, song,
rdunlap, linux-api, apparmor, linux-kernel, Maxime Bélair
In-Reply-To: <20251010132610.12001-1-maxime.belair@canonical.com>
Enable users to manage Smack policies through the new hooks
lsm_config_self_policy and lsm_config_system_policy.
lsm_config_self_policy allows adding Smack policies for the current cred.
For now it remains restricted to CAP_MAC_ADMIN.
lsm_config_system_policy allows adding globabl Smack policies. This is
restricted to CAP_MAC_ADMIN.
Signed-off-by: Maxime Bélair <maxime.belair@canonical.com>
---
security/smack/smack.h | 8 +++++
security/smack/smack_lsm.c | 73 ++++++++++++++++++++++++++++++++++++++
security/smack/smackfs.c | 2 +-
3 files changed, 82 insertions(+), 1 deletion(-)
diff --git a/security/smack/smack.h b/security/smack/smack.h
index bf6a6ed3946c..3e3d30dfdcf7 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -275,6 +275,14 @@ struct smk_audit_info {
#endif
};
+/*
+ * This function is in smackfs.c
+ */
+ssize_t smk_write_rules_list(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos,
+ struct list_head *rule_list,
+ struct mutex *rule_lock, int format);
+
/*
* These functions are in smack_access.c
*/
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 99833168604e..bf4bb2242768 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -5027,6 +5027,76 @@ static int smack_uring_cmd(struct io_uring_cmd *ioucmd)
#endif /* CONFIG_IO_URING */
+/**
+ * smack_lsm_config_system_policy - Configure a system smack policy
+ * @op: operation to perform. Currently, only LSM_POLICY_LOAD is supported
+ * @buf: User-supplied buffer in the form "<fmt><policy>"
+ * <fmt> is the 1-byte format of <policy>
+ * <policy> is the policy to load
+ * @size: size of @buf
+ * @flags: reserved for future use; must be zero
+ *
+ * Returns: number of written rules on success, negative value on error
+ */
+static int smack_lsm_config_system_policy(u32 op, void __user *buf, size_t size,
+ u32 flags)
+{
+ loff_t pos = 0;
+ u8 fmt;
+
+ if (op != LSM_POLICY_LOAD || flags)
+ return -EOPNOTSUPP;
+
+ if (size < 2)
+ return -EINVAL;
+
+ if (get_user(fmt, (uint8_t *)buf))
+ return -EFAULT;
+
+ return smk_write_rules_list(NULL, buf + 1, size - 1, &pos, NULL, NULL, fmt);
+}
+
+/**
+ * smack_lsm_config_self_policy - Configure a smack policy for the current cred
+ * @op: operation to perform. Currently, only LSM_POLICY_LOAD is supported
+ * @buf: User-supplied buffer in the form "<fmt><policy>"
+ * <fmt> is the 1-byte format of <policy>
+ * <policy> is the policy to load
+ * @size: size of @buf
+ * @flags: reserved for future use; must be zero
+ *
+ * Returns: number of written rules on success, negative value on error
+ */
+static int smack_lsm_config_self_policy(u32 op, void __user *buf, size_t size,
+ u32 flags)
+{
+ loff_t pos = 0;
+ u8 fmt;
+ struct task_smack *tsp;
+
+ if (op != LSM_POLICY_LOAD || flags)
+ return -EOPNOTSUPP;
+
+ if (size < 2)
+ return -EINVAL;
+
+ if (get_user(fmt, (uint8_t *)buf))
+ return -EFAULT;
+ /**
+ * smk_write_rules_list could be used to gain privileges.
+ * This function is thus restricted to CAP_MAC_ADMIN.
+ * TODO: Ensure that the new rule does not give extra privileges
+ * before dropping this CAP_MAC_ADMIN check.
+ */
+ if (!capable(CAP_MAC_ADMIN))
+ return -EPERM;
+
+
+ tsp = smack_cred(current_cred());
+ return smk_write_rules_list(NULL, buf + 1, size - 1, &pos, &tsp->smk_rules,
+ &tsp->smk_rules_lock, fmt);
+}
+
struct lsm_blob_sizes smack_blob_sizes __ro_after_init = {
.lbs_cred = sizeof(struct task_smack),
.lbs_file = sizeof(struct smack_known *),
@@ -5203,6 +5273,9 @@ static struct security_hook_list smack_hooks[] __ro_after_init = {
LSM_HOOK_INIT(uring_sqpoll, smack_uring_sqpoll),
LSM_HOOK_INIT(uring_cmd, smack_uring_cmd),
#endif
+ LSM_HOOK_INIT(lsm_config_self_policy, smack_lsm_config_self_policy),
+ LSM_HOOK_INIT(lsm_config_system_policy, smack_lsm_config_system_policy),
+
};
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index 90a67e410808..ed1814588d56 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -441,7 +441,7 @@ static ssize_t smk_parse_long_rule(char *data, struct smack_parsed_rule *rule,
* "subject<whitespace>object<whitespace>
* acc_enable<whitespace>acc_disable[<whitespace>...]"
*/
-static ssize_t smk_write_rules_list(struct file *file, const char __user *buf,
+ssize_t smk_write_rules_list(struct file *file, const char __user *buf,
size_t count, loff_t *ppos,
struct list_head *rule_list,
struct mutex *rule_lock, int format)
--
2.48.1
^ permalink raw reply related
* Re: [PATCH v2] nbd: override creds to kernel when calling sock_{send,recv}msg()
From: Stephen Smalley @ 2025-10-10 12:08 UTC (permalink / raw)
To: Ondrej Mosnacek
Cc: Josef Bacik, Jens Axboe, linux-block, nbd, linux-security-module,
selinux, Ming Lei
In-Reply-To: <20251010080900.1680512-1-omosnace@redhat.com>
On Fri, Oct 10, 2025 at 4:09 AM Ondrej Mosnacek <omosnace@redhat.com> wrote:
>
> sock_{send,recv}msg() internally calls security_socket_{send,recv}msg(),
> which does security checks (e.g. SELinux) for socket access against the
> current task. However, _sock_xmit() in drivers/block/nbd.c may be called
> indirectly from a userspace syscall, where the NBD socket access would
> be incorrectly checked against the calling userspace task (which simply
> tries to read/write a file that happens to reside on an NBD device).
>
> To fix this, temporarily override creds to kernel ones before calling
> the sock_*() functions. This allows the security modules to recognize
> this as internal access by the kernel, which will normally be allowed.
>
> A way to trigger the issue is to do the following (on a system with
> SELinux set to enforcing):
>
> ### Create nbd device:
> truncate -s 256M /tmp/testfile
> nbd-server localhost:10809 /tmp/testfile
>
> ### Connect to the nbd server:
> nbd-client localhost
>
> ### Create mdraid array
> mdadm --create -l 1 -n 2 /dev/md/testarray /dev/nbd0 missing
>
> After these steps, assuming the SELinux policy doesn't allow the
> unexpected access pattern, errors will be visible on the kernel console:
>
> [ 142.204243] nbd0: detected capacity change from 0 to 524288
> [ 165.189967] md: async del_gendisk mode will be removed in future, please upgrade to mdadm-4.5+
> [ 165.252299] md/raid1:md127: active with 1 out of 2 mirrors
> [ 165.252725] md127: detected capacity change from 0 to 522240
> [ 165.255434] block nbd0: Send control failed (result -13)
> [ 165.255718] block nbd0: Request send failed, requeueing
> [ 165.256006] block nbd0: Dead connection, failed to find a fallback
> [ 165.256041] block nbd0: Receive control failed (result -32)
> [ 165.256423] block nbd0: shutting down sockets
> [ 165.257196] I/O error, dev nbd0, sector 2048 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 2
> [ 165.257736] Buffer I/O error on dev md127, logical block 0, async page read
> [ 165.258263] I/O error, dev nbd0, sector 2048 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 2
> [ 165.259376] Buffer I/O error on dev md127, logical block 0, async page read
> [ 165.259920] I/O error, dev nbd0, sector 2048 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 2
> [ 165.260628] Buffer I/O error on dev md127, logical block 0, async page read
> [ 165.261661] ldm_validate_partition_table(): Disk read failed.
> [ 165.262108] I/O error, dev nbd0, sector 2048 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 2
> [ 165.262769] Buffer I/O error on dev md127, logical block 0, async page read
> [ 165.263697] I/O error, dev nbd0, sector 2048 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 2
> [ 165.264412] Buffer I/O error on dev md127, logical block 0, async page read
> [ 165.265412] I/O error, dev nbd0, sector 2048 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 2
> [ 165.265872] Buffer I/O error on dev md127, logical block 0, async page read
> [ 165.266378] I/O error, dev nbd0, sector 2048 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 2
> [ 165.267168] Buffer I/O error on dev md127, logical block 0, async page read
> [ 165.267564] md127: unable to read partition table
> [ 165.269581] I/O error, dev nbd0, sector 0 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 2
> [ 165.269960] Buffer I/O error on dev nbd0, logical block 0, async page read
> [ 165.270316] I/O error, dev nbd0, sector 0 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 2
> [ 165.270913] Buffer I/O error on dev nbd0, logical block 0, async page read
> [ 165.271253] I/O error, dev nbd0, sector 0 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 2
> [ 165.271809] Buffer I/O error on dev nbd0, logical block 0, async page read
> [ 165.272074] ldm_validate_partition_table(): Disk read failed.
> [ 165.272360] nbd0: unable to read partition table
> [ 165.289004] ldm_validate_partition_table(): Disk read failed.
> [ 165.289614] nbd0: unable to read partition table
>
> The corresponding SELinux denial on Fedora/RHEL will look like this
> (assuming it's not silenced):
> type=AVC msg=audit(1758104872.510:116): avc: denied { write } for pid=1908 comm="mdadm" laddr=::1 lport=32772 faddr=::1 fport=10809 scontext=system_u:system_r:mdadm_t:s0-s0:c0.c1023 tcontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tclass=tcp_socket permissive=0
>
> The respective backtrace looks like this:
> @security[mdadm, -13,
> handshake_exit+221615650
> handshake_exit+221615650
> handshake_exit+221616465
> security_socket_sendmsg+5
> sock_sendmsg+106
> handshake_exit+221616150
> sock_sendmsg+5
> __sock_xmit+162
> nbd_send_cmd+597
> nbd_handle_cmd+377
> nbd_queue_rq+63
> blk_mq_dispatch_rq_list+653
> __blk_mq_do_dispatch_sched+184
> __blk_mq_sched_dispatch_requests+333
> blk_mq_sched_dispatch_requests+38
> blk_mq_run_hw_queue+239
> blk_mq_dispatch_plug_list+382
> blk_mq_flush_plug_list.part.0+55
> __blk_flush_plug+241
> __submit_bio+353
> submit_bio_noacct_nocheck+364
> submit_bio_wait+84
> __blkdev_direct_IO_simple+232
> blkdev_read_iter+162
> vfs_read+591
> ksys_read+95
> do_syscall_64+92
> entry_SYSCALL_64_after_hwframe+120
> ]: 1
>
> The issue has started to appear since commit 060406c61c7c ("block: add
> plug while submitting IO").
>
> Cc: Ming Lei <ming.lei@redhat.com>
> Link: https://bugzilla.redhat.com/show_bug.cgi?id=2348878
> Fixes: 060406c61c7c ("block: add plug while submitting IO")
> Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
Acked-by: Stephen Smalley <stephen.smalley.work@gmail.com>
> ---
>
> Changes in v2:
> * Move put_cred() after destroy_workqueue() in nbd_cleanup() to avoid a UAF
> * Add some more details into the commit message
> * Add a Fixes: tag
>
> v1: https://lore.kernel.org/linux-block/20251009134542.1529148-1-omosnace@redhat.com/
>
> drivers/block/nbd.c | 15 +++++++++++++++
> 1 file changed, 15 insertions(+)
>
> diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
> index 6463d0e8d0cef..3903186e8a4e4 100644
> --- a/drivers/block/nbd.c
> +++ b/drivers/block/nbd.c
> @@ -52,6 +52,7 @@
> static DEFINE_IDR(nbd_index_idr);
> static DEFINE_MUTEX(nbd_index_mutex);
> static struct workqueue_struct *nbd_del_wq;
> +static struct cred *nbd_cred;
> static int nbd_total_devices = 0;
>
> struct nbd_sock {
> @@ -554,6 +555,7 @@ static int __sock_xmit(struct nbd_device *nbd, struct socket *sock, int send,
> int result;
> struct msghdr msg = {} ;
> unsigned int noreclaim_flag;
> + const struct cred *old_cred;
>
> if (unlikely(!sock)) {
> dev_err_ratelimited(disk_to_dev(nbd->disk),
> @@ -562,6 +564,8 @@ static int __sock_xmit(struct nbd_device *nbd, struct socket *sock, int send,
> return -EINVAL;
> }
>
> + old_cred = override_creds(nbd_cred);
> +
> msg.msg_iter = *iter;
>
> noreclaim_flag = memalloc_noreclaim_save();
> @@ -586,6 +590,8 @@ static int __sock_xmit(struct nbd_device *nbd, struct socket *sock, int send,
>
> memalloc_noreclaim_restore(noreclaim_flag);
>
> + revert_creds(old_cred);
> +
> return result;
> }
>
> @@ -2669,7 +2675,15 @@ static int __init nbd_init(void)
> return -ENOMEM;
> }
>
> + nbd_cred = prepare_kernel_cred(&init_task);
> + if (!nbd_cred) {
> + destroy_workqueue(nbd_del_wq);
> + unregister_blkdev(NBD_MAJOR, "nbd");
> + return -ENOMEM;
> + }
> +
> if (genl_register_family(&nbd_genl_family)) {
> + put_cred(nbd_cred);
> destroy_workqueue(nbd_del_wq);
> unregister_blkdev(NBD_MAJOR, "nbd");
> return -EINVAL;
> @@ -2724,6 +2738,7 @@ static void __exit nbd_cleanup(void)
> /* Also wait for nbd_dev_remove_work() completes */
> destroy_workqueue(nbd_del_wq);
>
> + put_cred(nbd_cred);
> idr_destroy(&nbd_index_idr);
> unregister_blkdev(NBD_MAJOR, "nbd");
> }
> --
> 2.51.0
>
>
^ permalink raw reply
* Re: [PATCH v4 31/34] ima,evm: move initcalls to the LSM framework
From: Mimi Zohar @ 2025-10-10 10:19 UTC (permalink / raw)
To: Paul Moore, linux-security-module, linux-integrity, selinux
Cc: John Johansen, Roberto Sassu, Fan Wu, Mickaël Salaün,
Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
Tetsuo Handa, Nicolas Bouchinet, Xiu Jianfeng
In-Reply-To: <20250916220355.252592-67-paul@paul-moore.com>
On Tue, 2025-09-16 at 18:03 -0400, Paul Moore wrote:
> From: Roberto Sassu <roberto.sassu@huawei.com>
>
> This patch converts IMA and EVM to use the LSM frameworks's initcall
> mechanism. It moved the integrity_fs_init() call to ima_fs_init() and
> evm_init_secfs(), to work around the fact that there is no "integrity" LSM,
> and introduced integrity_fs_fini() to remove the integrity directory, if
> empty. Both integrity_fs_init() and integrity_fs_fini() support the
> scenario of being called by both the IMA and EVM LSMs.
>
> This patch does not touch any of the platform certificate code that
> lives under the security/integrity/platform_certs directory as the
> IMA/EVM developers would prefer to address that in a future patchset.
>
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> [PM: adjust description as discussed over email]
> Signed-off-by: Paul Moore <paul@paul-moore.com>
Acked-by: Mimi Zohar <zohar@linux.ibm.com>
^ permalink raw reply
* Re: [PATCH v2] nbd: override creds to kernel when calling sock_{send,recv}msg()
From: Ming Lei @ 2025-10-10 8:42 UTC (permalink / raw)
To: Ondrej Mosnacek
Cc: Josef Bacik, Jens Axboe, linux-block, nbd, linux-security-module,
selinux
In-Reply-To: <20251010080900.1680512-1-omosnace@redhat.com>
On Fri, Oct 10, 2025 at 10:09:00AM +0200, Ondrej Mosnacek wrote:
> sock_{send,recv}msg() internally calls security_socket_{send,recv}msg(),
> which does security checks (e.g. SELinux) for socket access against the
> current task. However, _sock_xmit() in drivers/block/nbd.c may be called
> indirectly from a userspace syscall, where the NBD socket access would
> be incorrectly checked against the calling userspace task (which simply
> tries to read/write a file that happens to reside on an NBD device).
>
> To fix this, temporarily override creds to kernel ones before calling
> the sock_*() functions. This allows the security modules to recognize
> this as internal access by the kernel, which will normally be allowed.
>
> A way to trigger the issue is to do the following (on a system with
> SELinux set to enforcing):
>
> ### Create nbd device:
> truncate -s 256M /tmp/testfile
> nbd-server localhost:10809 /tmp/testfile
>
> ### Connect to the nbd server:
> nbd-client localhost
>
> ### Create mdraid array
> mdadm --create -l 1 -n 2 /dev/md/testarray /dev/nbd0 missing
>
> After these steps, assuming the SELinux policy doesn't allow the
> unexpected access pattern, errors will be visible on the kernel console:
>
> [ 142.204243] nbd0: detected capacity change from 0 to 524288
> [ 165.189967] md: async del_gendisk mode will be removed in future, please upgrade to mdadm-4.5+
> [ 165.252299] md/raid1:md127: active with 1 out of 2 mirrors
> [ 165.252725] md127: detected capacity change from 0 to 522240
> [ 165.255434] block nbd0: Send control failed (result -13)
> [ 165.255718] block nbd0: Request send failed, requeueing
> [ 165.256006] block nbd0: Dead connection, failed to find a fallback
> [ 165.256041] block nbd0: Receive control failed (result -32)
> [ 165.256423] block nbd0: shutting down sockets
> [ 165.257196] I/O error, dev nbd0, sector 2048 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 2
> [ 165.257736] Buffer I/O error on dev md127, logical block 0, async page read
> [ 165.258263] I/O error, dev nbd0, sector 2048 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 2
> [ 165.259376] Buffer I/O error on dev md127, logical block 0, async page read
> [ 165.259920] I/O error, dev nbd0, sector 2048 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 2
> [ 165.260628] Buffer I/O error on dev md127, logical block 0, async page read
> [ 165.261661] ldm_validate_partition_table(): Disk read failed.
> [ 165.262108] I/O error, dev nbd0, sector 2048 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 2
> [ 165.262769] Buffer I/O error on dev md127, logical block 0, async page read
> [ 165.263697] I/O error, dev nbd0, sector 2048 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 2
> [ 165.264412] Buffer I/O error on dev md127, logical block 0, async page read
> [ 165.265412] I/O error, dev nbd0, sector 2048 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 2
> [ 165.265872] Buffer I/O error on dev md127, logical block 0, async page read
> [ 165.266378] I/O error, dev nbd0, sector 2048 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 2
> [ 165.267168] Buffer I/O error on dev md127, logical block 0, async page read
> [ 165.267564] md127: unable to read partition table
> [ 165.269581] I/O error, dev nbd0, sector 0 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 2
> [ 165.269960] Buffer I/O error on dev nbd0, logical block 0, async page read
> [ 165.270316] I/O error, dev nbd0, sector 0 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 2
> [ 165.270913] Buffer I/O error on dev nbd0, logical block 0, async page read
> [ 165.271253] I/O error, dev nbd0, sector 0 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 2
> [ 165.271809] Buffer I/O error on dev nbd0, logical block 0, async page read
> [ 165.272074] ldm_validate_partition_table(): Disk read failed.
> [ 165.272360] nbd0: unable to read partition table
> [ 165.289004] ldm_validate_partition_table(): Disk read failed.
> [ 165.289614] nbd0: unable to read partition table
>
> The corresponding SELinux denial on Fedora/RHEL will look like this
> (assuming it's not silenced):
> type=AVC msg=audit(1758104872.510:116): avc: denied { write } for pid=1908 comm="mdadm" laddr=::1 lport=32772 faddr=::1 fport=10809 scontext=system_u:system_r:mdadm_t:s0-s0:c0.c1023 tcontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tclass=tcp_socket permissive=0
>
> The respective backtrace looks like this:
> @security[mdadm, -13,
> handshake_exit+221615650
> handshake_exit+221615650
> handshake_exit+221616465
> security_socket_sendmsg+5
> sock_sendmsg+106
> handshake_exit+221616150
> sock_sendmsg+5
> __sock_xmit+162
> nbd_send_cmd+597
> nbd_handle_cmd+377
> nbd_queue_rq+63
> blk_mq_dispatch_rq_list+653
> __blk_mq_do_dispatch_sched+184
> __blk_mq_sched_dispatch_requests+333
> blk_mq_sched_dispatch_requests+38
> blk_mq_run_hw_queue+239
> blk_mq_dispatch_plug_list+382
> blk_mq_flush_plug_list.part.0+55
> __blk_flush_plug+241
> __submit_bio+353
> submit_bio_noacct_nocheck+364
> submit_bio_wait+84
> __blkdev_direct_IO_simple+232
> blkdev_read_iter+162
> vfs_read+591
> ksys_read+95
> do_syscall_64+92
> entry_SYSCALL_64_after_hwframe+120
> ]: 1
>
> The issue has started to appear since commit 060406c61c7c ("block: add
> plug while submitting IO").
>
> Cc: Ming Lei <ming.lei@redhat.com>
> Link: https://bugzilla.redhat.com/show_bug.cgi?id=2348878
> Fixes: 060406c61c7c ("block: add plug while submitting IO")
> Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
Looks fine:
Reviewed-by: Ming Lei <ming.lei@redhat.com>
Tested-by: Ming Lei <ming.lei@redhat.com>
Thanks,
Ming
^ permalink raw reply
* [PATCH v2] nbd: override creds to kernel when calling sock_{send,recv}msg()
From: Ondrej Mosnacek @ 2025-10-10 8:09 UTC (permalink / raw)
To: Josef Bacik, Jens Axboe
Cc: linux-block, nbd, linux-security-module, selinux, Ming Lei
sock_{send,recv}msg() internally calls security_socket_{send,recv}msg(),
which does security checks (e.g. SELinux) for socket access against the
current task. However, _sock_xmit() in drivers/block/nbd.c may be called
indirectly from a userspace syscall, where the NBD socket access would
be incorrectly checked against the calling userspace task (which simply
tries to read/write a file that happens to reside on an NBD device).
To fix this, temporarily override creds to kernel ones before calling
the sock_*() functions. This allows the security modules to recognize
this as internal access by the kernel, which will normally be allowed.
A way to trigger the issue is to do the following (on a system with
SELinux set to enforcing):
### Create nbd device:
truncate -s 256M /tmp/testfile
nbd-server localhost:10809 /tmp/testfile
### Connect to the nbd server:
nbd-client localhost
### Create mdraid array
mdadm --create -l 1 -n 2 /dev/md/testarray /dev/nbd0 missing
After these steps, assuming the SELinux policy doesn't allow the
unexpected access pattern, errors will be visible on the kernel console:
[ 142.204243] nbd0: detected capacity change from 0 to 524288
[ 165.189967] md: async del_gendisk mode will be removed in future, please upgrade to mdadm-4.5+
[ 165.252299] md/raid1:md127: active with 1 out of 2 mirrors
[ 165.252725] md127: detected capacity change from 0 to 522240
[ 165.255434] block nbd0: Send control failed (result -13)
[ 165.255718] block nbd0: Request send failed, requeueing
[ 165.256006] block nbd0: Dead connection, failed to find a fallback
[ 165.256041] block nbd0: Receive control failed (result -32)
[ 165.256423] block nbd0: shutting down sockets
[ 165.257196] I/O error, dev nbd0, sector 2048 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 2
[ 165.257736] Buffer I/O error on dev md127, logical block 0, async page read
[ 165.258263] I/O error, dev nbd0, sector 2048 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 2
[ 165.259376] Buffer I/O error on dev md127, logical block 0, async page read
[ 165.259920] I/O error, dev nbd0, sector 2048 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 2
[ 165.260628] Buffer I/O error on dev md127, logical block 0, async page read
[ 165.261661] ldm_validate_partition_table(): Disk read failed.
[ 165.262108] I/O error, dev nbd0, sector 2048 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 2
[ 165.262769] Buffer I/O error on dev md127, logical block 0, async page read
[ 165.263697] I/O error, dev nbd0, sector 2048 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 2
[ 165.264412] Buffer I/O error on dev md127, logical block 0, async page read
[ 165.265412] I/O error, dev nbd0, sector 2048 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 2
[ 165.265872] Buffer I/O error on dev md127, logical block 0, async page read
[ 165.266378] I/O error, dev nbd0, sector 2048 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 2
[ 165.267168] Buffer I/O error on dev md127, logical block 0, async page read
[ 165.267564] md127: unable to read partition table
[ 165.269581] I/O error, dev nbd0, sector 0 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 2
[ 165.269960] Buffer I/O error on dev nbd0, logical block 0, async page read
[ 165.270316] I/O error, dev nbd0, sector 0 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 2
[ 165.270913] Buffer I/O error on dev nbd0, logical block 0, async page read
[ 165.271253] I/O error, dev nbd0, sector 0 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 2
[ 165.271809] Buffer I/O error on dev nbd0, logical block 0, async page read
[ 165.272074] ldm_validate_partition_table(): Disk read failed.
[ 165.272360] nbd0: unable to read partition table
[ 165.289004] ldm_validate_partition_table(): Disk read failed.
[ 165.289614] nbd0: unable to read partition table
The corresponding SELinux denial on Fedora/RHEL will look like this
(assuming it's not silenced):
type=AVC msg=audit(1758104872.510:116): avc: denied { write } for pid=1908 comm="mdadm" laddr=::1 lport=32772 faddr=::1 fport=10809 scontext=system_u:system_r:mdadm_t:s0-s0:c0.c1023 tcontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tclass=tcp_socket permissive=0
The respective backtrace looks like this:
@security[mdadm, -13,
handshake_exit+221615650
handshake_exit+221615650
handshake_exit+221616465
security_socket_sendmsg+5
sock_sendmsg+106
handshake_exit+221616150
sock_sendmsg+5
__sock_xmit+162
nbd_send_cmd+597
nbd_handle_cmd+377
nbd_queue_rq+63
blk_mq_dispatch_rq_list+653
__blk_mq_do_dispatch_sched+184
__blk_mq_sched_dispatch_requests+333
blk_mq_sched_dispatch_requests+38
blk_mq_run_hw_queue+239
blk_mq_dispatch_plug_list+382
blk_mq_flush_plug_list.part.0+55
__blk_flush_plug+241
__submit_bio+353
submit_bio_noacct_nocheck+364
submit_bio_wait+84
__blkdev_direct_IO_simple+232
blkdev_read_iter+162
vfs_read+591
ksys_read+95
do_syscall_64+92
entry_SYSCALL_64_after_hwframe+120
]: 1
The issue has started to appear since commit 060406c61c7c ("block: add
plug while submitting IO").
Cc: Ming Lei <ming.lei@redhat.com>
Link: https://bugzilla.redhat.com/show_bug.cgi?id=2348878
Fixes: 060406c61c7c ("block: add plug while submitting IO")
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
---
Changes in v2:
* Move put_cred() after destroy_workqueue() in nbd_cleanup() to avoid a UAF
* Add some more details into the commit message
* Add a Fixes: tag
v1: https://lore.kernel.org/linux-block/20251009134542.1529148-1-omosnace@redhat.com/
drivers/block/nbd.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 6463d0e8d0cef..3903186e8a4e4 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -52,6 +52,7 @@
static DEFINE_IDR(nbd_index_idr);
static DEFINE_MUTEX(nbd_index_mutex);
static struct workqueue_struct *nbd_del_wq;
+static struct cred *nbd_cred;
static int nbd_total_devices = 0;
struct nbd_sock {
@@ -554,6 +555,7 @@ static int __sock_xmit(struct nbd_device *nbd, struct socket *sock, int send,
int result;
struct msghdr msg = {} ;
unsigned int noreclaim_flag;
+ const struct cred *old_cred;
if (unlikely(!sock)) {
dev_err_ratelimited(disk_to_dev(nbd->disk),
@@ -562,6 +564,8 @@ static int __sock_xmit(struct nbd_device *nbd, struct socket *sock, int send,
return -EINVAL;
}
+ old_cred = override_creds(nbd_cred);
+
msg.msg_iter = *iter;
noreclaim_flag = memalloc_noreclaim_save();
@@ -586,6 +590,8 @@ static int __sock_xmit(struct nbd_device *nbd, struct socket *sock, int send,
memalloc_noreclaim_restore(noreclaim_flag);
+ revert_creds(old_cred);
+
return result;
}
@@ -2669,7 +2675,15 @@ static int __init nbd_init(void)
return -ENOMEM;
}
+ nbd_cred = prepare_kernel_cred(&init_task);
+ if (!nbd_cred) {
+ destroy_workqueue(nbd_del_wq);
+ unregister_blkdev(NBD_MAJOR, "nbd");
+ return -ENOMEM;
+ }
+
if (genl_register_family(&nbd_genl_family)) {
+ put_cred(nbd_cred);
destroy_workqueue(nbd_del_wq);
unregister_blkdev(NBD_MAJOR, "nbd");
return -EINVAL;
@@ -2724,6 +2738,7 @@ static void __exit nbd_cleanup(void)
/* Also wait for nbd_dev_remove_work() completes */
destroy_workqueue(nbd_del_wq);
+ put_cred(nbd_cred);
idr_destroy(&nbd_index_idr);
unregister_blkdev(NBD_MAJOR, "nbd");
}
--
2.51.0
^ permalink raw reply related
* Re: [PATCH] KEYS: encrypted: Use designated initializers for match_table_t structs
From: Jarkko Sakkinen @ 2025-10-10 4:01 UTC (permalink / raw)
To: Thorsten Blum
Cc: Mimi Zohar, David Howells, Paul Moore, James Morris,
Serge E. Hallyn, linux-integrity, keyrings, linux-security-module,
linux-kernel
In-Reply-To: <aOiDqjEyowUkegbd@kernel.org>
On Fri, Oct 10, 2025 at 06:55:26AM +0300, Jarkko Sakkinen wrote:
> On Thu, Oct 09, 2025 at 01:58:17PM +0200, Thorsten Blum wrote:
> > Use designated initializers for 'key_format_tokens' and 'key_tokens' to
> > allow struct fields to be reordered more easily and to improve
> > readability.
> >
> > Signed-off-by: Thorsten Blum <thorsten.blum@linux.dev>
> > ---
> > security/keys/encrypted-keys/encrypted.c | 16 ++++++++--------
> > 1 file changed, 8 insertions(+), 8 deletions(-)
> >
> > diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c
> > index aef438d18da8..76a6dab2f4d2 100644
> > --- a/security/keys/encrypted-keys/encrypted.c
> > +++ b/security/keys/encrypted-keys/encrypted.c
> > @@ -62,17 +62,17 @@ enum {
> > };
> >
> > static const match_table_t key_format_tokens = {
> > - {Opt_default, "default"},
> > - {Opt_ecryptfs, "ecryptfs"},
> > - {Opt_enc32, "enc32"},
> > - {Opt_error, NULL}
> > + { .token = Opt_default, .pattern = "default"},
> > + { .token = Opt_ecryptfs, .pattern = "ecryptfs"},
> > + { .token = Opt_enc32, .pattern = "enc32"},
> > + { .token = Opt_error, .pattern = NULL}
> > };
> >
> > static const match_table_t key_tokens = {
> > - {Opt_new, "new"},
> > - {Opt_load, "load"},
> > - {Opt_update, "update"},
> > - {Opt_err, NULL}
> > + { .token = Opt_new, .pattern = "new"},
> > + { .token = Opt_load, .pattern = "load"},
> > + { .token = Opt_update, .pattern = "update"},
> > + { .token = Opt_err, .pattern = NULL}
> > };
> >
> > static bool user_decrypted_data = IS_ENABLED(CONFIG_USER_DECRYPTED_DATA);
> > --
> > 2.51.0
> >
>
> For me this look like a "convert tuple alike initializations into struct
> alike initializations" type of change :-)
>
> In a context the change would make sense. E.g., if an optional field was
> required.
If we had struct initializers I would equally nak "convert struct
initializers to tuple initializers" type of change.
BR, Jarkko
^ permalink raw reply
* Re: [PATCH] KEYS: encrypted: Use designated initializers for match_table_t structs
From: Jarkko Sakkinen @ 2025-10-10 3:55 UTC (permalink / raw)
To: Thorsten Blum
Cc: Mimi Zohar, David Howells, Paul Moore, James Morris,
Serge E. Hallyn, linux-integrity, keyrings, linux-security-module,
linux-kernel
In-Reply-To: <20251009115817.368170-2-thorsten.blum@linux.dev>
On Thu, Oct 09, 2025 at 01:58:17PM +0200, Thorsten Blum wrote:
> Use designated initializers for 'key_format_tokens' and 'key_tokens' to
> allow struct fields to be reordered more easily and to improve
> readability.
>
> Signed-off-by: Thorsten Blum <thorsten.blum@linux.dev>
> ---
> security/keys/encrypted-keys/encrypted.c | 16 ++++++++--------
> 1 file changed, 8 insertions(+), 8 deletions(-)
>
> diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c
> index aef438d18da8..76a6dab2f4d2 100644
> --- a/security/keys/encrypted-keys/encrypted.c
> +++ b/security/keys/encrypted-keys/encrypted.c
> @@ -62,17 +62,17 @@ enum {
> };
>
> static const match_table_t key_format_tokens = {
> - {Opt_default, "default"},
> - {Opt_ecryptfs, "ecryptfs"},
> - {Opt_enc32, "enc32"},
> - {Opt_error, NULL}
> + { .token = Opt_default, .pattern = "default"},
> + { .token = Opt_ecryptfs, .pattern = "ecryptfs"},
> + { .token = Opt_enc32, .pattern = "enc32"},
> + { .token = Opt_error, .pattern = NULL}
> };
>
> static const match_table_t key_tokens = {
> - {Opt_new, "new"},
> - {Opt_load, "load"},
> - {Opt_update, "update"},
> - {Opt_err, NULL}
> + { .token = Opt_new, .pattern = "new"},
> + { .token = Opt_load, .pattern = "load"},
> + { .token = Opt_update, .pattern = "update"},
> + { .token = Opt_err, .pattern = NULL}
> };
>
> static bool user_decrypted_data = IS_ENABLED(CONFIG_USER_DECRYPTED_DATA);
> --
> 2.51.0
>
For me this look like a "convert tuple alike initializations into struct
alike initializations" type of change :-)
In a context the change would make sense. E.g., if an optional field was
required.
BR, Jarkko
^ permalink raw reply
* Re: [PATCH] keys: Replace deprecated strncpy in ecryptfs_fill_auth_tok
From: Jarkko Sakkinen @ 2025-10-10 3:40 UTC (permalink / raw)
To: Thorsten Blum
Cc: Mimi Zohar, David Howells, Paul Moore, James Morris,
Serge E. Hallyn, linux-hardening, linux-integrity, keyrings,
linux-security-module, linux-kernel
In-Reply-To: <20251009180316.394708-3-thorsten.blum@linux.dev>
On Thu, Oct 09, 2025 at 08:03:17PM +0200, Thorsten Blum wrote:
> strncpy() is deprecated for NUL-terminated destination buffers; use
> strscpy_pad() instead.
>
> Link: https://github.com/KSPP/linux/issues/90
> Signed-off-by: Thorsten Blum <thorsten.blum@linux.dev>
Deprecated or not but commit message still should have a better
explanation :-) Sure there's also the link too that explains it
all but still one should get the gist without cross-referencing
into it.
It's a permanent amortized cost as everytime when revisiting this
commit (e.g. over the course of bisecting or whatever), you need
a web browser in order to make anything out of the message.
> ---
> security/keys/encrypted-keys/ecryptfs_format.c | 3 +--
> 1 file changed, 1 insertion(+), 2 deletions(-)
>
> diff --git a/security/keys/encrypted-keys/ecryptfs_format.c b/security/keys/encrypted-keys/ecryptfs_format.c
> index 8fdd76105ce3..2fc6f3a66135 100644
> --- a/security/keys/encrypted-keys/ecryptfs_format.c
> +++ b/security/keys/encrypted-keys/ecryptfs_format.c
> @@ -54,8 +54,7 @@ int ecryptfs_fill_auth_tok(struct ecryptfs_auth_tok *auth_tok,
> auth_tok->version = (((uint16_t)(major << 8) & 0xFF00)
> | ((uint16_t)minor & 0x00FF));
> auth_tok->token_type = ECRYPTFS_PASSWORD;
> - strncpy((char *)auth_tok->token.password.signature, key_desc,
> - ECRYPTFS_PASSWORD_SIG_SIZE);
> + strscpy_pad(auth_tok->token.password.signature, key_desc);
> auth_tok->token.password.session_key_encryption_key_bytes =
> ECRYPTFS_MAX_KEY_BYTES;
> /*
> --
> 2.51.0
>
BR, Jarkko
^ permalink raw reply
* Re: [PATCH] ipe: Drop a duplicated CONFIG_ prefix in the ifdeffery
From: Fan Wu @ 2025-10-10 3:29 UTC (permalink / raw)
To: Borislav Petkov
Cc: Fan Wu, Paul Moore, James Morris, Serge E. Hallyn,
linux-security-module, LKML, Borislav Petkov (AMD)
In-Reply-To: <20251009154525.31932-1-bp@kernel.org>
On Thu, Oct 9, 2025 at 8:45 AM Borislav Petkov <bp@kernel.org> wrote:
>
> From: "Borislav Petkov (AMD)" <bp@alien8.de>
>
> Looks like it got added by mistake, perhaps editor auto-completion
> artifact. Drop it.
>
> No functional changes.
>
> Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Thanks, applied to ipe-next.
-Fan
^ permalink raw reply
* Re: [PATCH] nbd: override creds to kernel when calling sock_{send,recv}msg()
From: Ming Lei @ 2025-10-10 1:56 UTC (permalink / raw)
To: Ondrej Mosnacek
Cc: Josef Bacik, Jens Axboe, linux-block, nbd, linux-security-module,
selinux
In-Reply-To: <20251009134542.1529148-1-omosnace@redhat.com>
On Thu, Oct 09, 2025 at 03:45:42PM +0200, Ondrej Mosnacek wrote:
> sock_{send,recv}msg() internally calls security_socket_{send,recv}msg(),
> which does security checks (e.g. SELinux) for socket access against the
> current task. However, _sock_xmit() in drivers/block/nbd.c may be called
> indirectly from a userspace syscall, where the NBD socket access would
> be incorrectly checked against the calling userspace task (which simply
> tries to read/write a file that happens to reside on an NBD device).
>
> To fix this, temporarily override creds to kernel ones before calling
> the sock_*() functions. This allows the security modules to recognize
> this as internal access by the kernel, which will normally be allowed.
>
> A way to trigger the issue is to do the following (on a system with
> SELinux set to enforcing):
>
> ### Create nbd device:
> truncate -s 256M /tmp/testfile
> nbd-server localhost:10809 /tmp/testfile
>
> ### Connect to the nbd server:
> nbd-client localhost
>
> ### Create mdraid array
> mdadm --create -l 1 -n 2 /dev/md/testarray /dev/nbd0 missing
-EACCESS is triggered when reading data from mdadm process:
@security[mdadm, -13,
handshake_exit+221615650
handshake_exit+221615650
handshake_exit+221616465
security_socket_sendmsg+5
sock_sendmsg+106
handshake_exit+221616150
sock_sendmsg+5
__sock_xmit+162
nbd_send_cmd+597
nbd_handle_cmd+377
nbd_queue_rq+63
blk_mq_dispatch_rq_list+653
__blk_mq_do_dispatch_sched+184
__blk_mq_sched_dispatch_requests+333
blk_mq_sched_dispatch_requests+38
blk_mq_run_hw_queue+239
blk_mq_dispatch_plug_list+382
blk_mq_flush_plug_list.part.0+55
__blk_flush_plug+241
__submit_bio+353
submit_bio_noacct_nocheck+364
submit_bio_wait+84
__blkdev_direct_IO_simple+232
blkdev_read_iter+162
vfs_read+591
ksys_read+95
do_syscall_64+92
entry_SYSCALL_64_after_hwframe+120
]: 1
The issue is started to expose since f1daaaf0c1fa ("block: add plug while submitting IO").
>
> ### Stop the array
> mdadm --stop /dev/md/testarray
>
> ### Disconnect the nbd device
> nbd-client -d /dev/nbd0
>
> ### Reconnect to nbd devices:
> nbd-client localhost
The above steps don't matter actually.
>
> After these steps, assuming the SELinux policy doesn't allow the
> unexpected access pattern, errors will be visible on the kernel console:
>
> [ 93.997980] nbd2: detected capacity change from 0 to 524288
> [ 100.314271] md/raid1:md126: active with 1 out of 2 mirrors
> [ 100.314301] md126: detected capacity change from 0 to 522240
> [ 100.317288] block nbd2: Send control failed (result -13) <-----
> [ 100.317306] block nbd2: Request send failed, requeueing <-----
> [ 100.318765] block nbd2: Receive control failed (result -32) <-----
> [ 100.318783] block nbd2: Dead connection, failed to find a fallback
> [ 100.318794] block nbd2: shutting down sockets
> [ 100.318802] I/O error, dev nbd2, sector 2048 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 0
> [ 100.318817] Buffer I/O error on dev md126, logical block 0, async page read
> [ 100.322000] I/O error, dev nbd2, sector 2048 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 0
> [ 100.322016] Buffer I/O error on dev md126, logical block 0, async page read
> [ 100.323244] I/O error, dev nbd2, sector 2048 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 0
> [ 100.323253] Buffer I/O error on dev md126, logical block 0, async page read
> [ 100.324436] I/O error, dev nbd2, sector 2048 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 0
> [ 100.324444] Buffer I/O error on dev md126, logical block 0, async page read
> [ 100.325621] I/O error, dev nbd2, sector 2048 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 0
> [ 100.325630] Buffer I/O error on dev md126, logical block 0, async page read
> [ 100.326813] I/O error, dev nbd2, sector 2048 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 0
> [ 100.326822] Buffer I/O error on dev md126, logical block 0, async page read
> [ 100.326834] md126: unable to read partition table
> [ 100.329872] I/O error, dev nbd2, sector 0 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 0
> [ 100.329889] Buffer I/O error on dev nbd2, logical block 0, async page read
> [ 100.331186] I/O error, dev nbd2, sector 0 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 0
> [ 100.331195] Buffer I/O error on dev nbd2, logical block 0, async page read
> [ 100.332371] I/O error, dev nbd2, sector 0 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 0
> [ 100.332379] Buffer I/O error on dev nbd2, logical block 0, async page read
> [ 100.333550] I/O error, dev nbd2, sector 0 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 0
> [ 100.333559] Buffer I/O error on dev nbd2, logical block 0, async page read
> [ 100.334721] nbd2: unable to read partition table
> [ 100.350993] nbd2: unable to read partition table
>
> The corresponding SELinux denial on Fedora/RHEL will look like this
> (assuming it's not silenced):
> type=AVC msg=audit(1758104872.510:116): avc: denied { write } for pid=1908 comm="mdadm" laddr=::1 lport=32772 faddr=::1 fport=10809 scontext=system_u:system_r:mdadm_t:s0-s0:c0.c1023 tcontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tclass=tcp_socket permissive=0
>
> Cc: Ming Lei <ming.lei@redhat.com>
> Link: https://bugzilla.redhat.com/show_bug.cgi?id=2348878
> Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
> ---
> drivers/block/nbd.c | 16 ++++++++++++++++
> 1 file changed, 16 insertions(+)
>
> diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
> index 6463d0e8d0cef..d50055c974a6b 100644
> --- a/drivers/block/nbd.c
> +++ b/drivers/block/nbd.c
> @@ -52,6 +52,7 @@
> static DEFINE_IDR(nbd_index_idr);
> static DEFINE_MUTEX(nbd_index_mutex);
> static struct workqueue_struct *nbd_del_wq;
> +static struct cred *nbd_cred;
> static int nbd_total_devices = 0;
>
> struct nbd_sock {
> @@ -554,6 +555,7 @@ static int __sock_xmit(struct nbd_device *nbd, struct socket *sock, int send,
> int result;
> struct msghdr msg = {} ;
> unsigned int noreclaim_flag;
> + const struct cred *old_cred;
>
> if (unlikely(!sock)) {
> dev_err_ratelimited(disk_to_dev(nbd->disk),
> @@ -562,6 +564,8 @@ static int __sock_xmit(struct nbd_device *nbd, struct socket *sock, int send,
> return -EINVAL;
> }
>
> + old_cred = override_creds(nbd_cred);
> +
> msg.msg_iter = *iter;
>
> noreclaim_flag = memalloc_noreclaim_save();
> @@ -586,6 +590,8 @@ static int __sock_xmit(struct nbd_device *nbd, struct socket *sock, int send,
>
> memalloc_noreclaim_restore(noreclaim_flag);
>
> + revert_creds(old_cred);
> +
> return result;
> }
>
> @@ -2669,7 +2675,15 @@ static int __init nbd_init(void)
> return -ENOMEM;
> }
>
> + nbd_cred = prepare_kernel_cred(&init_task);
> + if (!nbd_cred) {
> + destroy_workqueue(nbd_del_wq);
> + unregister_blkdev(NBD_MAJOR, "nbd");
> + return -ENOMEM;
> + }
> +
> if (genl_register_family(&nbd_genl_family)) {
> + put_cred(nbd_cred);
> destroy_workqueue(nbd_del_wq);
> unregister_blkdev(NBD_MAJOR, "nbd");
> return -EINVAL;
> @@ -2706,6 +2720,8 @@ static void __exit nbd_cleanup(void)
>
> nbd_dbg_close();
>
> + put_cred(nbd_cred);
> +
> mutex_lock(&nbd_index_mutex);
> idr_for_each(&nbd_index_idr, &nbd_exit_cb, &del_list);
> mutex_unlock(&nbd_index_mutex);
Yeah, as commented by Stephen and Paul, put_cred() need to be moved after
destroy_workqueue(nbd_del_wq) in which wq function nbd disk is removed and
recv wq is destroyed.
Otherwise, this patch looks fine from block layer viewpoint, and I verified
that it does fix the -EACCESS failure for madadm to read from nbd.
Thanks,
Ming
^ permalink raw reply
* Re: [PATCH bpf-next v2 0/3] BPF signature hash chains
From: Alexei Starovoitov @ 2025-10-10 1:00 UTC (permalink / raw)
To: Paul Moore
Cc: Alexei Starovoitov, KP Singh, Linus Torvalds, Blaise Boscaccy,
James Bottomley, bpf, LSM List, K. Y. Srinivasan, Daniel Borkmann,
Andrii Nakryiko, wufan, Quentin Monnet
In-Reply-To: <CAHC9VhRyG9ooMz6wVA17WKA9xkDy=UEPVkD4zOJf5mqrANMR9g@mail.gmail.com>
On Thu, Oct 9, 2025 at 1:47 PM Paul Moore <paul@paul-moore.com> wrote:
>
> On Tue, Oct 7, 2025 at 9:53 AM KP Singh <kpsingh@kernel.org> wrote:
> > On Mon, Oct 6, 2025 at 5:08 AM Paul Moore <paul@paul-moore.com> wrote:
> > > On Fri, Oct 3, 2025 at 12:25 PM KP Singh <kpsingh@kernel.org> wrote:
> > > > On Fri, Oct 3, 2025 at 4:36 AM Paul Moore <paul@paul-moore.com> wrote:
> > > > > On Thu, Oct 2, 2025 at 9:48 AM KP Singh <kpsingh@kernel.org> wrote:
> > > > > > On Wed, Oct 1, 2025 at 11:37 PM Paul Moore <paul@paul-moore.com> wrote:
>
> ...
>
> > I feel we will keep going in circles on this and I will leave it up to
> > the maintainers to resolve this.
>
> Yes, I think we can all agree that the discussion has reached a point
> where both sides are simply repeating ourselves.
>
> I believe we've outlined why the code merged into Linus' tree during
> this merge window does not meet the BPF signature verification
> requirements of a number of different user groups, with Blaise
> proposing an addition to KP's code to satisfy those needs. Further, I
> believe that either Blaise, James, or I have responded to all of KP's
> concerns regarding Blaise's patchset, and while KP may not be happy
> with those answers, no one has yet to offer an alternative solution to
> Blaise's patchset.
>
> With that in mind, I agree with KP that it's time for "the maintainers
> to resolve this". Alexei, will you be merging Blaise's patchset and
> sending it up to Linus?
Nope. Both you and James did not understand what Blaise
patch set is actually doing, and that followed the whole set of
arguments and reasons that made no sense.
James's concern is valid though:
> However, the rub for LSM
> is that the verification of the program map by the loader happens
> *after* the security_bpf_prog_load() hook has been called.
I understand the discomfort, but that's what the kernel module loading
process is doing as well, so you should be concerned with both.
Since both are doing pretty much the same work.
Both allocate and populate kernel memory with data.
For kernel module it's bss, data, rodata.
For bpf it's BTF, maps.
Then the kernel applies relocations to .text against .data and against
the kernel.
bpf is doing the same. It applies relocation against maps, btf, kfuncs.
The only difference here is that ko loading is done by
kernel/module/main.c which is pretty complex on its own,
since it's parsing ELF, symbols, etc
While bpf loader is doing a fraction of that.
It doesn't need to parse ELF. It's a dumb sequence of commands:
load mapA, load mapB, apply relocation at off N to prog M.
If bpf loader has a bug it will still be caught by the verifier,
since it effectively runs multiple times. Once for loader prog,
and then for each prog that loader wants to load.
For kernel modules and for bpf we trust the build system to be correct.
gcc, clang, linker, objtool, pahole, various scripts/* need to do the
right thing for the kernel modules.
In bpf case it's only libbpf that is trusted to produce
valid loader bpf program for a set of bpf programs and maps.
I share the discomfort that tools/lib/bpf/gen_loader.c
is doing something that you don't understand,
but, really, do you understand what gcc, clang, objtool are doing?
You have to trust the build process otherwise it's all pointless.
Malicious "gcc" can inject special code into a signed kernel module.
Malicious "libbpf" can inject something into "loader prog",
but again the verifier is still there even if "loader prog" is busted.
^ permalink raw reply
* Re: [syzbot] [fs?] BUG: sleeping function called from invalid context in hook_sb_delete
From: syzbot @ 2025-10-09 20:56 UTC (permalink / raw)
To: brauner, eadavis, gnoack, hdanton, jack, linux-fsdevel,
linux-kernel, linux-security-module, max.kellermann, mic,
syzkaller-bugs, twuufnxlz, viro
In-Reply-To: <68d32659.a70a0220.4f78.0012.GAE@google.com>
syzbot has bisected this issue to:
commit 2ef435a872abc347dc0a92f1c213bb0af3cbf195
Author: Max Kellermann <max.kellermann@ionos.com>
Date: Wed Sep 17 15:36:31 2025 +0000
fs: add might_sleep() annotation to iput() and more
bisection log: https://syzkaller.appspot.com/x/bisect.txt?x=1092ba7c580000
start commit: 7c3ba4249a36 Add linux-next specific files for 20251008
git tree: linux-next
final oops: https://syzkaller.appspot.com/x/report.txt?x=1292ba7c580000
console output: https://syzkaller.appspot.com/x/log.txt?x=1492ba7c580000
kernel config: https://syzkaller.appspot.com/x/.config?x=fa7a95b14b1eaa
dashboard link: https://syzkaller.appspot.com/bug?extid=12479ae15958fc3f54ec
syz repro: https://syzkaller.appspot.com/x/repro.syz?x=12280dcd980000
C reproducer: https://syzkaller.appspot.com/x/repro.c?x=111d852f980000
Reported-by: syzbot+12479ae15958fc3f54ec@syzkaller.appspotmail.com
Fixes: 2ef435a872ab ("fs: add might_sleep() annotation to iput() and more")
For information about bisection process see: https://goo.gl/tpsmEJ#bisection
^ permalink raw reply
* Re: [PATCH bpf-next v2 0/3] BPF signature hash chains
From: Paul Moore @ 2025-10-09 20:47 UTC (permalink / raw)
To: ast, KP Singh, Linus Torvalds
Cc: Blaise Boscaccy, james.bottomley, bpf, linux-security-module, kys,
daniel, andrii, wufan, qmo
In-Reply-To: <CACYkzJ4mJ6eJBzTLgbPG9A6i_dN2e0B=1WNp6XkAr-WmaEyzkA@mail.gmail.com>
On Tue, Oct 7, 2025 at 9:53 AM KP Singh <kpsingh@kernel.org> wrote:
> On Mon, Oct 6, 2025 at 5:08 AM Paul Moore <paul@paul-moore.com> wrote:
> > On Fri, Oct 3, 2025 at 12:25 PM KP Singh <kpsingh@kernel.org> wrote:
> > > On Fri, Oct 3, 2025 at 4:36 AM Paul Moore <paul@paul-moore.com> wrote:
> > > > On Thu, Oct 2, 2025 at 9:48 AM KP Singh <kpsingh@kernel.org> wrote:
> > > > > On Wed, Oct 1, 2025 at 11:37 PM Paul Moore <paul@paul-moore.com> wrote:
...
> I feel we will keep going in circles on this and I will leave it up to
> the maintainers to resolve this.
Yes, I think we can all agree that the discussion has reached a point
where both sides are simply repeating ourselves.
I believe we've outlined why the code merged into Linus' tree during
this merge window does not meet the BPF signature verification
requirements of a number of different user groups, with Blaise
proposing an addition to KP's code to satisfy those needs. Further, I
believe that either Blaise, James, or I have responded to all of KP's
concerns regarding Blaise's patchset, and while KP may not be happy
with those answers, no one has yet to offer an alternative solution to
Blaise's patchset.
With that in mind, I agree with KP that it's time for "the maintainers
to resolve this". Alexei, will you be merging Blaise's patchset and
sending it up to Linus?
--
paul-moore.com
^ permalink raw reply
* Re: [PATCH 2/2] LSM: Allow reservation of netlabel
From: Stephen Smalley @ 2025-10-09 18:53 UTC (permalink / raw)
To: Casey Schaufler
Cc: paul, linux-security-module, jmorris, serge, keescook,
john.johansen, penguin-kernel, linux-kernel, selinux
In-Reply-To: <20251001215643.31465-3-casey@schaufler-ca.com>
On Wed, Oct 1, 2025 at 5:56 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
>
> Allow LSMs to request exclusive access to the netlabel facility.
> Provide mechanism for LSMs to determine if they have access to
> netlabel. Update the current users of netlabel, SELinux and Smack,
> to use and respect the exclusive use of netlabel.
>
> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> ---
> diff --git a/security/security.c b/security/security.c
> index e59e3d403de6..9eca10844b56 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -289,6 +289,12 @@ static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed)
> else
> blob_sizes.lbs_secmark = true;
> }
> + if (needed->lbs_netlabel) {
> + if (blob_sizes.lbs_netlabel)
> + needed->lbs_netlabel = false;
> + else
> + blob_sizes.lbs_netlabel = true;
> +
Same principle here - if a LSM wants to use netlabel, it may want to
guarantee that it truly has exclusive access to it no matter what the
LSM order is.
^ permalink raw reply
* Re: [PATCH 1/2] LSM: Exclusive secmark usage
From: Stephen Smalley @ 2025-10-09 18:49 UTC (permalink / raw)
To: Casey Schaufler
Cc: paul, linux-security-module, jmorris, serge, keescook,
john.johansen, penguin-kernel, linux-kernel, selinux
In-Reply-To: <20251001215643.31465-2-casey@schaufler-ca.com>
On Wed, Oct 1, 2025 at 5:56 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
>
> The network secmark can only be used by one security module
> at a time. Establish mechanism to identify to security modules
a mechanism to inform security modules?
> whether they have access to the secmark. SELinux already
> incorparates mechanism, but it has to be added to Smack and
incorporates
> AppArmor.
>
> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> ---
> include/linux/lsm_hooks.h | 1 +
> security/apparmor/include/net.h | 5 +++++
> security/apparmor/lsm.c | 7 ++++---
> security/security.c | 6 ++++++
> security/selinux/hooks.c | 4 +++-
> security/smack/smack.h | 5 +++++
> security/smack/smack_lsm.c | 3 ++-
> security/smack/smack_netfilter.c | 10 ++++++++--
> 8 files changed, 34 insertions(+), 7 deletions(-)
>
> diff --git a/security/security.c b/security/security.c
> index ad163f06bf7a..e59e3d403de6 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -283,6 +283,12 @@ static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed)
> lsm_set_blob_size(&needed->lbs_xattr_count,
> &blob_sizes.lbs_xattr_count);
> lsm_set_blob_size(&needed->lbs_bdev, &blob_sizes.lbs_bdev);
> + if (needed->lbs_secmark) {
> + if (blob_sizes.lbs_secmark)
> + needed->lbs_secmark = false;
> + else
> + blob_sizes.lbs_secmark = true;
> + }
So if I understand correctly, the first LSM to register with
lbs_secmark set wins.
Not sure that's a great idea - seemingly some LSMs may want to insist
that they get to use secmark regardless of registration order?
^ permalink raw reply
* Re: [PATCH v2 2/2] LSM: Infrastructure management of the mnt_opts security blob
From: Stephen Smalley @ 2025-10-09 18:38 UTC (permalink / raw)
To: Casey Schaufler, Ondrej Mosnacek
Cc: paul, eparis, linux-security-module, jmorris, serge, keescook,
john.johansen, penguin-kernel, linux-kernel, selinux
In-Reply-To: <20250925171208.5997-3-casey@schaufler-ca.com>
On Thu, Sep 25, 2025 at 1:12 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
>
> Move management of the mnt_opts->security blob out of the individual
> security modules and into the security infrastructure. The modules
> tell the infrastructure how much space is required, and the space is
> allocated as required in the interfaces that use the blob.
>
> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> ---
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index 4bba9d119713..1ccf880e4894 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -656,19 +651,13 @@ static int selinux_set_mnt_opts(struct super_block *sb,
> mutex_lock(&sbsec->lock);
>
> if (!selinux_initialized()) {
> - if (!opts) {
> - /* Defer initialization until selinux_complete_init,
> - after the initial policy is loaded and the security
> - server is ready to handle calls. */
> - if (kern_flags & SECURITY_LSM_NATIVE_LABELS) {
> - sbsec->flags |= SE_SBNATIVE;
> - *set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
> - }
> - goto out;
> + /* Defer initialization until selinux_complete_init,
> + after the initial policy is loaded and the security
> + server is ready to handle calls. */
> + if (kern_flags & SECURITY_LSM_NATIVE_LABELS) {
> + sbsec->flags |= SE_SBNATIVE;
> + *set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
This seemingly would produce a change in behavior for SELinux.
Previously we would only do this if there were no SELinux mount
options specified.
> }
> - rc = -EINVAL;
> - pr_warn("SELinux: Unable to set superblock options "
> - "before the security server is initialized\n");
Ditto.
> goto out;
> }
>
>
^ permalink raw reply
* [PATCH] keys: Replace deprecated strncpy in ecryptfs_fill_auth_tok
From: Thorsten Blum @ 2025-10-09 18:03 UTC (permalink / raw)
To: Mimi Zohar, David Howells, Jarkko Sakkinen, Paul Moore,
James Morris, Serge E. Hallyn
Cc: linux-hardening, Thorsten Blum, linux-integrity, keyrings,
linux-security-module, linux-kernel
strncpy() is deprecated for NUL-terminated destination buffers; use
strscpy_pad() instead.
Link: https://github.com/KSPP/linux/issues/90
Signed-off-by: Thorsten Blum <thorsten.blum@linux.dev>
---
security/keys/encrypted-keys/ecryptfs_format.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/security/keys/encrypted-keys/ecryptfs_format.c b/security/keys/encrypted-keys/ecryptfs_format.c
index 8fdd76105ce3..2fc6f3a66135 100644
--- a/security/keys/encrypted-keys/ecryptfs_format.c
+++ b/security/keys/encrypted-keys/ecryptfs_format.c
@@ -54,8 +54,7 @@ int ecryptfs_fill_auth_tok(struct ecryptfs_auth_tok *auth_tok,
auth_tok->version = (((uint16_t)(major << 8) & 0xFF00)
| ((uint16_t)minor & 0x00FF));
auth_tok->token_type = ECRYPTFS_PASSWORD;
- strncpy((char *)auth_tok->token.password.signature, key_desc,
- ECRYPTFS_PASSWORD_SIG_SIZE);
+ strscpy_pad(auth_tok->token.password.signature, key_desc);
auth_tok->token.password.session_key_encryption_key_bytes =
ECRYPTFS_MAX_KEY_BYTES;
/*
--
2.51.0
^ permalink raw reply related
* The Matrix
From: Albin Lidén @ 2025-10-09 16:42 UTC (permalink / raw)
To: linux-security-module
[-- Attachment #1.1: Type: text/plain, Size: 3343 bytes --]
Hello linux-security-module folks,
We’re exploring a primarily userland approach to safe, reversible
“deception” environments for training and incident response rehearsals on
Linux, built on existing kernel primitives.
Problem
- Blue teams need repeatable ways to expose “adversaries” (or trainees)
to believable yet harmless system states while recording interaction and
preventing tampering of the ground truth.
- Today, ad‑hoc chroot/jail scripts or brittle VM snapshots are commonly
used. We’d like something more controlled, lower overhead, and scriptable.
Approach (prototype)
- Session-scoped illusions: A subject (role/user) is placed into a mount
namespace that presents carefully curated “decoy” trees for select paths
(e.g., /var/log, /etc, /proc facade via ps-name tricks), plus harmless
network listeners (e.g., nc) and realistic processes (exec -a).
- Storage/WORM: All session keystrokes and key system events are written
to an append-only store (WORM), with auditd rules and/or LSM hooks
producing verifiable logs. Optional remote sink.
- Compliance-only mode: A profile set that uses the same engine but
without deception—hardening/monitoring only.
Kernel interfaces used
- Namespaces: mount, user, net (per-session isolation)
- Overlay layering: overlayfs where permissible; otherwise
fuse-overlayfs for unpriv illusions
- LSM policies: AppArmor/SELinux for confinement; Landlock (where
appropriate) for “write‑deny” outside staging areas
- Audit: auditd rules to flag decoy exits and WORM path tampering
- eBPF/BPF LSM (optional): for stronger WORM semantics (e.g., deny
unlink/rename on protected trees) and targeted audit
Open questions for the list
1. For append-only/WORM semantics at userland granularity, is a BPF LSM
policy pattern recommended over relying on chattr +a and audit alone? Any
reference patterns for inode_unlink/rename guards with minimal perf impact?
2. Overlayfs guidance: best practices to trigger useful audit events
when decoy trees are mutated (whiteouts, renames) and to ensure we don’t
degrade I/O paths?
3. Landlock scope: pragmatically useful here to carve out
mutation-protected trees for unpriv sessions while still allowing realistic
“writes” into decoy overlays?
4. Any concerns with fuse-overlayfs for non‑priv illusions in training
environments vs. kernel overlayfs (perf, reliability)?
5. If we later propose small kernel changes, where might they live?
(e.g., opt‑in audit points in overlayfs; minor helpers for session-scope
WORM meta)
We’re not proposing a new in‑tree LSM. The project is userland‑first with
existing LSMs/policies, and potentially BPF LSM snippets if that’s
appropriate. Our ask right now is guidance and prior-art pointers.
If helpful, we can share a minimal PoC repo (Go) with:
- matrixd: session manager (namespaces + mounts), recorder
- websion: small Go/HTML UI for operators
- profiles: deception and compliance-only
- seeds: curated decoy bundles (web/bastion/dev/db)
- auditd rules + example BPF LSM (if advisable)
Thanks for your time and for any direction you can offer.
Best, Albin Lidén and Simtheory
[-- Attachment #1.2: Type: text/html, Size: 5081 bytes --]
[-- Attachment #2: the-matrix-poc-full.zip --]
[-- Type: application/zip, Size: 53584 bytes --]
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox