From: "Mickaël Salaün" <mic@digikod.net>
To: "Maxime Bélair" <maxime.belair@canonical.com>
Cc: linux-security-module@vger.kernel.org,
john.johansen@canonical.com, paul@paul-moore.com,
jmorris@namei.org, serge@hallyn.com, kees@kernel.org,
stephen.smalley.work@gmail.com, casey@schaufler-ca.com,
takedakn@nttdata.co.jp, penguin-kernel@i-love.sakura.ne.jp,
song@kernel.org, rdunlap@infradead.org,
linux-api@vger.kernel.org, apparmor@lists.ubuntu.com,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH v5 2/3] lsm: introduce security_lsm_config_*_policy hooks
Date: Wed, 20 Aug 2025 16:21:18 +0200 [thread overview]
Message-ID: <20250820.Ao3iquoshaiB@digikod.net> (raw)
In-Reply-To: <20250709080220.110947-3-maxime.belair@canonical.com>
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.
> {
> - return 0;
> + size_t usize;
> +
> + if (get_user(usize, size))
Size should just be u32, not a pointer.
> + 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.
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
> +
> + 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.
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).
> + 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
>
>
next prev parent reply other threads:[~2025-08-20 14:21 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-07-09 8:00 [PATCH v5 0/3] lsm: introduce lsm_config_self_policy() and lsm_config_system_policy() syscalls Maxime Bélair
2025-07-09 8:00 ` [PATCH v5 1/3] Wire up lsm_config_self_policy and lsm_config_system_policy syscalls Maxime Bélair
2025-07-09 8:00 ` [PATCH v5 2/3] lsm: introduce security_lsm_config_*_policy hooks Maxime Bélair
2025-08-20 14:21 ` Mickaël Salaün [this message]
2025-08-20 15:30 ` Casey Schaufler
2025-10-10 14:59 ` Paul Moore
2025-10-10 13:32 ` Maxime Bélair
2025-07-09 8:00 ` [PATCH v5 3/3] AppArmor: add support for lsm_config_self_policy and lsm_config_system_policy Maxime Bélair
2025-07-09 10:59 ` Tetsuo Handa
2025-07-14 18:07 ` kernel test robot
2025-08-20 14:21 ` Mickaël Salaün
2025-07-09 16:48 ` [PATCH v5 0/3] lsm: introduce lsm_config_self_policy() and lsm_config_system_policy() syscalls Casey Schaufler
2025-10-10 13:34 ` Maxime Bélair
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250820.Ao3iquoshaiB@digikod.net \
--to=mic@digikod.net \
--cc=apparmor@lists.ubuntu.com \
--cc=casey@schaufler-ca.com \
--cc=jmorris@namei.org \
--cc=john.johansen@canonical.com \
--cc=kees@kernel.org \
--cc=linux-api@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-security-module@vger.kernel.org \
--cc=maxime.belair@canonical.com \
--cc=paul@paul-moore.com \
--cc=penguin-kernel@i-love.sakura.ne.jp \
--cc=rdunlap@infradead.org \
--cc=serge@hallyn.com \
--cc=song@kernel.org \
--cc=stephen.smalley.work@gmail.com \
--cc=takedakn@nttdata.co.jp \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®