From: Justin Suess <utilityemal77@gmail.com>
To: ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org,
kpsingh@kernel.org, paul@paul-moore.com, mic@digikod.net,
viro@zeniv.linux.org.uk, brauner@kernel.org, kees@kernel.org
Cc: gnoack@google.com, jack@suse.cz, song@kernel.org,
yonghong.song@linux.dev, martin.lau@linux.dev, m@maowtm.org,
bpf@vger.kernel.org, linux-security-module@vger.kernel.org,
linux-kernel@vger.kernel.org,
Casey Schaufler <casey@schaufler-ca.com>
Subject: Re: [PATCH v2 01/15] lsm: Add the LSM policy object lifetime hooks
Date: Wed, 2 Sep 2026 09:05:03 -0400 [thread overview]
Message-ID: <apgX1HKQ7b973YV-@zenbox> (raw)
In-Reply-To: <20260831145858.3869191-2-utilityemal77@gmail.com>
On Mon, Aug 31, 2026 at 10:58:43AM -0400, Justin Suess wrote:
> Add struct lsm_policy_object, the identity an LSM embeds in a policy
> object it shares with BPF programs, and the three hooks managing such
> an object's lifetime:
>
> policy_object_from_fd(fd, &object)
> policy_object_get(object)
> policy_object_put(object)
>
> The object records the owning LSM's LSM_ID_* value. The BPF kfuncs
> built on these hooks dispatch each call on an object to the one LSM
> matching its lsmid, which resolves the containing object with
> container_of(); the framework never interprets an object beyond its
> lsmid. The type field discriminates between the owning LSM's own
> policy object kinds and is private to it, with 0 reserved as "unset"
> so a zeroed, untagged object fails every type check.
>
> from_fd has no object to route by: the fd refers to a file set up
> through the owning LSM's own userspace interface, so the fd itself
> identifies its LSM. The framework offers the fd to every
> implementation in turn; an LSM declines a fd that is not one of its
> policy objects with -EOPNOTSUPP, and any other error is a definitive
> translation failure.
>
> The hooks back referenced BPF kptrs, which imposes the same lifetime
> contract on every implementation: from_fd returns a reference on a
> live object, get acquires with inc-not-zero semantics and fails with
> -ENOENT once the count dropped to zero, put may be called from
> contexts that cannot sleep (BPF drives it from map destructors), and
> the containing object is freed only after an RCU grace period, as
> programs load policy object kptrs from maps under RCU and may examine
> an object concurrently with its last put.
>
> The hooks are excluded from the "bpf" LSM's attachment points. The
> object-routed hooks are unreachable there, as LSM_ID_BPF policy
> objects cannot exist; for from_fd, whose walk visits every
> implementation, a BPF program cannot fill the object out parameter,
> so an attachment returning 0 would hand the caller an uninitialized
> pointer.
>
> Cc: Paul Moore <paul@paul-moore.com>
> Cc: Casey Schaufler <casey@schaufler-ca.com>
> Signed-off-by: Justin Suess <utilityemal77@gmail.com>
> ---
> include/linux/lsm_hook_defs.h | 4 ++++
> include/linux/security.h | 11 +++++++++++
> kernel/bpf/bpf_lsm.c | 3 +++
> 3 files changed, 18 insertions(+)
>
> diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
> index 65c9609ec207..d7684407737a 100644
> --- a/include/linux/lsm_hook_defs.h
> +++ b/include/linux/lsm_hook_defs.h
> @@ -452,6 +452,10 @@ LSM_HOOK(int, 0, bpf_token_create, struct bpf_token *token, union bpf_attr *attr
> LSM_HOOK(void, LSM_RET_VOID, bpf_token_free, struct bpf_token *token)
> LSM_HOOK(int, 0, bpf_token_cmd, const struct bpf_token *token, enum bpf_cmd cmd)
> LSM_HOOK(int, 0, bpf_token_capable, const struct bpf_token *token, int cap)
> +LSM_HOOK(int, -EOPNOTSUPP, policy_object_from_fd, int fd,
> + struct lsm_policy_object **object)
> +LSM_HOOK(int, -EOPNOTSUPP, policy_object_get, struct lsm_policy_object *object)
> +LSM_HOOK(void, LSM_RET_VOID, policy_object_put, struct lsm_policy_object *object)
> #endif /* CONFIG_BPF_SYSCALL */
>
> LSM_HOOK(int, 0, locked_down, enum lockdown_reason what)
> diff --git a/include/linux/security.h b/include/linux/security.h
> index 153e9043058f..5e423bea080e 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -168,6 +168,17 @@ struct lsm_prop {
> struct lsm_prop_bpf bpf;
> };
>
> +/*
> + * Identity of a policy object an LSM shares with BPF programs,
> + * embedded in the LSM's own object. @lsmid identifies the owning
> + * LSM; @type discriminates that LSM's policy object types, with 0
> + * reserved as "unset".
> + */
> +struct lsm_policy_object {
> + u64 lsmid;
> + u32 type;
> +};
For some clarity:
lsm_policy_object is just a handle to a refcounted lsm-private struct.
It can't be forged / created manually because it's a trusted kernel
pointer, so the only way to get it is through policy_object_from_fd.
And you cannot mutate any part of it from BPF.
But it's what enables the generic model. Calling it a "policy object"
may be short sighted though, that term is heavily overloaded in the LSM
space. I don't want to prescribe any restrictions on what an LSM can use
it for, after all some LSM have no notion of "policy" at all or have a
different meaning for it.
For SELinux, this "lsm_policy_object" could be an sid, for AppArmor an aa_label,
for Smack a label, etc. The intention was to allow writing programs that
don't care about any details of a particular LSM.
Justin
> +
> extern const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX+1];
>
> /* These functions are in security/commoncap.c */
> diff --git a/kernel/bpf/bpf_lsm.c b/kernel/bpf/bpf_lsm.c
> index 1433809bb166..d06744d72e04 100644
> --- a/kernel/bpf/bpf_lsm.c
> +++ b/kernel/bpf/bpf_lsm.c
> @@ -56,6 +56,9 @@ BTF_ID(func, bpf_lsm_xfrm_decode_session)
> #endif
> BTF_ID(func, bpf_lsm_ismaclabel)
> BTF_ID(func, bpf_lsm_file_alloc_security)
> +BTF_ID(func, bpf_lsm_policy_object_from_fd)
> +BTF_ID(func, bpf_lsm_policy_object_get)
> +BTF_ID(func, bpf_lsm_policy_object_put)
> BTF_SET_END(bpf_lsm_disabled_hooks)
>
> /* List of LSM hooks that should operate on 'current' cgroup regardless
> --
> 2.55.0
>
next prev parent reply other threads:[~2026-09-02 13:05 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-31 14:58 [PATCH v2 00/15] BPF interface for applying Landlock rulesets Justin Suess
2026-08-31 14:58 ` [PATCH v2 01/15] lsm: Add the LSM policy object lifetime hooks Justin Suess
2026-08-31 17:17 ` Casey Schaufler
2026-08-31 17:41 ` Justin Suess
2026-09-02 13:05 ` Justin Suess [this message]
2026-09-02 17:51 ` Casey Schaufler
2026-09-02 18:28 ` Justin Suess
2026-08-31 14:58 ` [PATCH v2 02/15] lsm: Add the bprm_apply_policy_object LSM hook Justin Suess
2026-08-31 14:58 ` [PATCH v2 03/15] lsm: Move the lsm_for_each_hook() macro to security/lsm.h Justin Suess
2026-08-31 14:58 ` [PATCH v2 04/15] lsm: Add the bpf_lsm_policy_release kfunc and policy object destructor Justin Suess
2026-08-31 14:58 ` [PATCH v2 05/15] lsm: Add the bpf_lsm_policy_from_fd kfunc Justin Suess
2026-08-31 14:58 ` [PATCH v2 06/15] lsm: Add the bpf_lsm_policy_acquire kfunc Justin Suess
2026-08-31 14:58 ` [PATCH v2 07/15] lsm: Add the bpf_lsm_policy_apply_bprm kfunc Justin Suess
2026-08-31 14:58 ` [PATCH v2 08/15] lsm: Document the LSM policy object interface Justin Suess
2026-08-31 14:58 ` [PATCH v2 09/15] selftests/bpf: Add tests for the LSM policy object kfuncs Justin Suess
2026-08-31 14:58 ` [PATCH v2 10/15] landlock: Expose the ruleset fd lookup to the rest of Landlock Justin Suess
2026-08-31 14:58 ` [PATCH v2 11/15] landlock: Factor the credential restriction out of landlock_restrict_self() Justin Suess
2026-08-31 14:58 ` [PATCH v2 12/15] landlock: Free rulesets after an RCU grace period Justin Suess
2026-08-31 14:58 ` [PATCH v2 13/15] landlock: Implement the LSM policy object hooks Justin Suess
2026-08-31 14:58 ` [PATCH v2 14/15] selftests/bpf: Test the LSM policy object kfuncs with Landlock Justin Suess
2026-08-31 19:53 ` sashiko-bot
2026-09-02 12:24 ` Justin Suess
2026-08-31 14:58 ` [PATCH v2 15/15] landlock: Document the BPF policy interface Justin Suess
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=apgX1HKQ7b973YV-@zenbox \
--to=utilityemal77@gmail.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=brauner@kernel.org \
--cc=casey@schaufler-ca.com \
--cc=daniel@iogearbox.net \
--cc=gnoack@google.com \
--cc=jack@suse.cz \
--cc=kees@kernel.org \
--cc=kpsingh@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-security-module@vger.kernel.org \
--cc=m@maowtm.org \
--cc=martin.lau@linux.dev \
--cc=mic@digikod.net \
--cc=paul@paul-moore.com \
--cc=song@kernel.org \
--cc=viro@zeniv.linux.org.uk \
--cc=yonghong.song@linux.dev \
/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