From: "Mickaël Salaün" <mic@digikod.net>
To: Justin Suess <utilityemal77@gmail.com>
Cc: Song Liu <song@kernel.org>,
ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org,
kpsingh@kernel.org, paul@paul-moore.com, viro@zeniv.linux.org.uk,
brauner@kernel.org, kees@kernel.org, gnoack@google.com,
jack@suse.cz, jmorris@namei.org, serge@hallyn.com,
yonghong.song@linux.dev, martin.lau@linux.dev, m@maowtm.org,
eddyz87@gmail.com, john.fastabend@gmail.com, sdf@fomichev.me,
skhan@linuxfoundation.org, bpf@vger.kernel.org,
linux-security-module@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org
Subject: Re: [RFC PATCH 08/20] bpf: Add Landlock ruleset map type
Date: Fri, 17 Apr 2026 20:03:14 +0200 [thread overview]
Message-ID: <20260417.aPh1ooQu8esh@digikod.net> (raw)
In-Reply-To: <aeJlHIoSjVPmccDx@suesslenovo>
On Fri, Apr 17, 2026 at 12:51:40PM -0400, Justin Suess wrote:
> On Fri, Apr 17, 2026 at 05:18:05PM +0200, Mickaël Salaün wrote:
> > On Fri, Apr 17, 2026 at 10:09:13AM -0400, Justin Suess wrote:
> > > On Thu, Apr 16, 2026 at 04:47:40PM -0700, Song Liu wrote:
> > > > On Thu, Apr 16, 2026 at 2:53 PM Justin Suess <utilityemal77@gmail.com> wrote:
> > > > [...]
> > > > > I don't think we can pass the FD number via a map, since the FD is
> > > > > process specific. And it needs to be done in a way where we can lookup
> > > > > the specific ruleset the FD points to safely.
> > > > >
> > > > > So we'd need some other way to load the ruleset from a file descriptor,
> > > > > either through a new userspace side BPF call or similar mechanism.
> > > > >
> > > > > Is there some other common pattern for FDs --> kptr I can follow?
> > > >
> > > > I didn't find an exact example like this. There must be a way to achieve
> > > > this. In the worst case, we can add a kfunc for this.
> > > >
> > >
> > > I think new kfunc is a doable approach. I could make a kfunc taking a struct
> > > *task_struct and an FD that looks up a landlock ruleset within a given
> > > task that returns a trusted kptr.
> > >
> > > Something like:
> > >
> > > struct bpf_landlock_ruleset* bpf_landlock_get_ruleset_from_fd(struct
> > > task_struct* task, int fd)
>
> Thanks Mickaël and Song,
>
> There are definitely pros and cons to both approaches.
>
> I think it would be OK to have a dedicated map and indeed cleaner from
> the userspace side since there would be no intermediate step to find the
> task and lookup the fd since that would be handled by the map_ops.
>
> Cons of the new map type:
>
> The main issue is with the new map type is then we are limited to the
> specific data structure we define in the map. For instance if we want
> to use a hash or other data structure instead of an array to store
> rulesets, we'd need to define variants of the landlock map type for
> all data structures.
>
> So this kind of bungles the "data structure" and "data type" layers.
>
> Pros of the new map type:
>
> The ruleset_fd conversion would be implicitly handled by the map_ops.
> Userspace could insert the fd and bpf would not have to deal with it at
> all.
>
> Cons of bpf_landlock_get_ruleset_from_fd:
>
> Awkward conversion step. We need to find the task of the original
> ruleset creator and recieve the fd before looking it up and converting
> it to a kptr to the bpf_landlock_ruleset.
>
> Pros of bpf_landlock_get_ruleset_from_fd:
>
> We can use any existing map data structure to store our kptrs.
>
> Not having a dedicated map type simplifies implementation.
>
> ...
>
> Appreciate the feedback from both of you.
> >
> > That looks like a hack that would not handle FD's (object) lifetime
> > (e.g. what happen when the task is gone?).
> >
>
> If we take an underlying reference on the ruleset backing the fd, then the fd
> being closed shouldn't matter right?
>
> This is how the lifetime management works for that
> bpf_landlock_get_ruleset_from fd, in my draft implementation prior to
> the RFC:
>
> /**
> * bpf_landlock_get_ruleset_from_fd - acquire a Landlock ruleset from a task FD
> * @task: task owning the file descriptor table to look up
> * @fd: Landlock ruleset file descriptor in @task
> *
> * Returns: a referenced opaque Landlock ruleset, or NULL if the FD lookup or
> * validation fails.
> */
> __bpf_kfunc struct bpf_landlock_ruleset *
> bpf_landlock_get_ruleset_from_fd(struct task_struct *task, int fd)
> {
> struct landlock_ruleset *ruleset;
> /* does landlock_get_ruleset and increments refcount */
> ruleset = landlock_get_task_ruleset_from_fd(task, fd, FMODE_CAN_READ);
> if (IS_ERR(ruleset))
> return NULL;
>
> return (struct bpf_landlock_ruleset *)ruleset;
> }
>
> The landlock_get_task_ruleset_from_fd increments the usage with
> landlock_get_ruleset. (This may sleep, so it must be tagged with
> KF_SLEEPABLE)
>
> If the fd is closed before landlock_get_ruleset_from_fd, then null is returned.
> The verifier will force the program to do the null check b/c of KF_RET_NULL.
>
> __kptr also have destructor kfuncs. So if we get the reference in
> bpf_landlock_get_ruleset_from_fd with landlock_get_ruleset_from_fd, and
> put the reference to the ruleset.
>
> The destructor path looks like this:
>
> /* Define ID for destructor * /
> BTF_ID_LIST(bpf_landlock_dtor_ids)
> BTF_ID(struct, bpf_landlock_ruleset)
> BTF_ID(func, bpf_landlock_put_ruleset_dtor)
> ...
> /**
> * bpf_landlock_put_ruleset - put a Landlock ruleset
> * @ruleset: Landlock ruleset to put
> */
> __bpf_kfunc void
> bpf_landlock_put_ruleset(const struct bpf_landlock_ruleset *ruleset)
> {
> landlock_put_ruleset((struct landlock_ruleset *)ruleset);
> }
>
> __bpf_kfunc void bpf_landlock_put_ruleset_dtor(void *ruleset)
> {
> bpf_landlock_put_ruleset(ruleset);
> }
>
> static int __init bpf_landlock_kfunc_init(void)
> {
> const struct btf_id_dtor_kfunc bpf_landlock_dtors[] = {
> {
> .btf_id = bpf_landlock_dtor_ids[0],
> .kfunc_btf_id = bpf_landlock_dtor_ids[1],
> },
> };
> int ret;
>
> ret = register_btf_kfunc_id_set(BPF_PROG_TYPE_LSM,
> &bpf_landlock_kfunc_set);
> if (ret)
> return ret;
>
> return register_btf_id_dtor_kfuncs(bpf_landlock_dtors,
> ARRAY_SIZE(bpf_landlock_dtors),
> THIS_MODULE);
> }
>
> Good reminder I need to include a test making sure the ruleset
> remains valid after the FD and/or task is closed. :)
>
> > Why not using proper typing with a dedicated map?
> >
>
> I may be misunderstanding, but from what I see, a __kptr DOES give
> proper typing, __kptr is an annotation not a type.
Ok, good.
>
> This is what it would look like in an BPF_MAP_TYPE_ARRAY.
>
> struct ruleset_kptr_value {
> struct bpf_landlock_ruleset __kptr * ruleset;
> };
>
> struct {
> __uint(type, BPF_MAP_TYPE_ARRAY);
> __uint(max_entries, 1);
> __type(key, __u32);
> __type(value, struct ruleset_kptr_value);
> } ruleset_kptr_map SEC(".maps");
>
> So we get proper typing from what I see. (It's not like a __kptr is a
> special void*, it has a type)
Looks good.
>
> > >
> > > And tagging it with KF_ACQUIRE + KF_RET_NULL.
> > >
> > > Then keep the existing kfunc for putting the ruleset and enforcing it on
> > > a struct linux_binprm.
> > >
> > > The BPF program would need to get a reference to a task struct
> > > of the program creating the rulesets with bpf_task_from_pid for
> > > instance. Then they could use the task_struct with another plain integer
> > > map to store FD numbers and then use the rulesets or store them in a map
> > > of __kptr objects for later usage.
> > >
> > > Would this be more acceptable?
> > > > > Basically the pattern I need is userspace must create the file
> > > > > descriptor, BPF converts that FD into a refcounted kernel object, and
> > > > > even if userspace closes the FD BPF needs to hold a reference on the
> > > > > underlying ruleset structure.
> > > > >
> > > > > (In this patch this was accomplished through the map_ops)
> > > > >
> > > > > Let me know what you think Song. I do understand the benefit of having a
> > > > > __kptr instead, the refcounting is all there, and it would allow storing
> > > > > rulesets in multiple map types. (and one less map type to maintain).
> > > >
> > > > A new type of map for each FD referenced kernel type is non-starter.
> > > > It is impossible to add UAPI for a specific use case.
> >
> > This new map type is only about one file descriptor type, similarly to
> > socket FDs. From a UAPI point of view, it looks clean and safe,
> > especially to deal with underlying object lifetime (e.g. reference
> > tracking).
> >
> > > >
> > > You've convinced me. I could see a lot of problems if everyone wanting
> > > to add their specialized maps, it would be difficult to maintain.
> >
> > Is there another way to properly handle kernel object lifetime (not tied
>
> The answer the the lifetime part is yes.
>
> The kptr destructors and the landlock ruleset refcounting give us that
> abstraction. (along with the KF_ACQUIRE/KF_RELEASE annotations and
> destructor implementation)
Good.
>
> > to the caller) and pass them as file descriptor?
> This "pass them as a file descriptor" is the tricky part. It would be
> very convenient if we could send the fd to bpf from userspace and have
> it be implicitly converted (like in the BPF_MAP_TYPE_LANDLOCK_RULESET
> implementation) in one step, but I just don't see a way to do that with
> the bpf_landlock_get_ruleset_from_fd kfunc approach.
Song's idea to have a generic FD map looks promising.
> >
> > >
> > > It's probably best to keep the specialized map types to core kernel
> > > interfaces only that are unlikely to change.
> >
> > File descriptors are a stable interface.
> >
> No that's correct. I cede that point :)
> > >
> > > > Thanks,
> > > > Song
> > > >
> > > > > Mickaël, do you have any thoughts on this? I have v2 basically ready,
> > > > > although it uses the BPF_MAP_TYPE_LANDLOCK_RULESET it changes a lot on
> > > > > the Landlock side.
> > >
>
next prev parent reply other threads:[~2026-04-17 18:10 UTC|newest]
Thread overview: 38+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-07 20:01 [RFC PATCH 00/20] BPF interface for applying Landlock rulesets Justin Suess
2026-04-07 20:01 ` [RFC PATCH 01/20] landlock: Move operations from syscall into ruleset code Justin Suess
2026-04-07 20:01 ` [RFC PATCH 02/20] execve: Add set_nnp_on_point_of_no_return Justin Suess
2026-04-07 20:01 ` [RFC PATCH 03/20] landlock: Implement LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS Justin Suess
2026-04-07 20:01 ` [RFC PATCH 04/20] selftests/landlock: Cover LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS Justin Suess
2026-04-07 20:01 ` [RFC PATCH 05/20] landlock: Make ruleset deferred free RCU safe Justin Suess
2026-04-07 20:01 ` [RFC PATCH 06/20] bpf: lsm: Add Landlock kfuncs Justin Suess
2026-04-07 20:01 ` [RFC PATCH 07/20] bpf: arraymap: Implement Landlock ruleset map Justin Suess
2026-04-07 20:01 ` [RFC PATCH 08/20] bpf: Add Landlock ruleset map type Justin Suess
2026-04-16 21:12 ` Song Liu
2026-04-16 21:53 ` Justin Suess
2026-04-16 23:47 ` Song Liu
2026-04-17 14:09 ` Justin Suess
2026-04-17 15:18 ` Mickaël Salaün
2026-04-17 16:10 ` Song Liu
2026-04-17 18:01 ` Mickaël Salaün
2026-04-17 16:51 ` Justin Suess
2026-04-17 18:03 ` Mickaël Salaün [this message]
2026-04-17 16:01 ` Song Liu
2026-04-07 20:01 ` [RFC PATCH 09/20] bpf: syscall: Handle Landlock ruleset maps Justin Suess
2026-04-07 20:01 ` [RFC PATCH 10/20] bpf: verifier: Add Landlock ruleset map support Justin Suess
2026-04-07 20:01 ` [RFC PATCH 11/20] selftests/bpf: Add Landlock kfunc declarations Justin Suess
2026-04-07 20:01 ` [RFC PATCH 12/20] selftests/landlock: Rename gettid wrapper for BPF reuse Justin Suess
2026-04-07 20:01 ` [RFC PATCH 13/20] selftests/bpf: Enable Landlock in selftests kernel Justin Suess
2026-04-07 20:01 ` [RFC PATCH 14/20] selftests/bpf: Add Landlock kfunc test program Justin Suess
2026-04-07 20:01 ` [RFC PATCH 15/20] selftests/bpf: Add Landlock kfunc test runner Justin Suess
2026-04-07 20:01 ` [RFC PATCH 16/20] landlock: Bump ABI version Justin Suess
2026-04-07 20:01 ` [RFC PATCH 17/20] tools: bpftool: Add documentation for landlock_ruleset Justin Suess
2026-04-07 20:01 ` [RFC PATCH 18/20] landlock: Document LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS Justin Suess
2026-04-07 20:01 ` [RFC PATCH 19/20] bpf: Document BPF_MAP_TYPE_LANDLOCK_RULESET Justin Suess
2026-04-07 20:01 ` [RFC PATCH 20/20] MAINTAINERS: update entry for the Landlock subsystem Justin Suess
2026-04-08 4:40 ` [RFC PATCH 00/20] BPF interface for applying Landlock rulesets Ihor Solodrai
2026-04-08 11:41 ` Justin Suess
2026-04-08 14:00 ` Mickaël Salaün
2026-04-08 17:10 ` Justin Suess
2026-04-08 19:21 ` Mickaël Salaün
2026-04-10 12:43 ` Justin Suess
2026-04-13 15:06 ` 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=20260417.aPh1ooQu8esh@digikod.net \
--to=mic@digikod.net \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=brauner@kernel.org \
--cc=daniel@iogearbox.net \
--cc=eddyz87@gmail.com \
--cc=gnoack@google.com \
--cc=jack@suse.cz \
--cc=jmorris@namei.org \
--cc=john.fastabend@gmail.com \
--cc=kees@kernel.org \
--cc=kpsingh@kernel.org \
--cc=linux-fsdevel@vger.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=paul@paul-moore.com \
--cc=sdf@fomichev.me \
--cc=serge@hallyn.com \
--cc=skhan@linuxfoundation.org \
--cc=song@kernel.org \
--cc=utilityemal77@gmail.com \
--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