Re: [PATCH bpf-next 4/8] bpf, lsm: Let BPF LSM provide xattrs at inode creation
From: Paul Moore
Date: Wed Sep 23 2026 - 16:58:21 EST
On Wed, Sep 23, 2026 at 3:11 PM Daniel Borkmann <daniel@xxxxxxxxxxxxx> wrote:
> On 9/23/26 6:57 PM, Paul Moore wrote:
> > On Tue, Sep 15, 2026 at 11:07 AM Daniel Borkmann <daniel@xxxxxxxxxxxxx> wrote:
> >> From: David Windsor <dwindsor@xxxxxxxxx>
> >>
> >> Many in-kernel LSMs (SELinux, Smack, IMA) store security labels in extended
> >> attributes. For these LSMs, atomic labeling during inode creation is
> >> critical: if the inode becomes accessible before its xattr is set, it is
> >> briefly unlabeled, which can disrupt LSMs making policy decisions based
> >> on file labels. Existing LSMs solve this by setting xattrs in the
> >> inode_init_security hook, which runs before the inode becomes accessible.
> >> BPF LSM programs currently lack this capability because the hook uses an
> >> output parameter (xattr_count) that BPF programs cannot write to, and
> >> existing kfuncs like bpf_set_dentry_xattr() require a dentry that isn't
> >> available until after the inode is accessible.
> >>
> >> Add a bpf_inode_init_xattr() kfunc that takes the hook's own xattrs and
> >> xattr_count arguments, passed through from the program's context, and
> >> claims a slot via lsm_get_xattr_slot() on the program's behalf. The
> >> xattr_count output argument is exposed to inode_init_security programs
> >> as trusted read-only memory, so programs can pass it to the kfunc but
> >> cannot modify the count themselves.
> >>
> >> Reserve BPF_LSM_INODE_INIT_XATTRS slots in bpf_lsm_blob_sizes the way
> >> every other xattr-providing LSM does, for the life of the kernel. The
> >> framework keys the collection off the reserved slot count, so a kernel
> >> built with CONFIG_BPF_LSM=y now allocates the xattr array on every inode
> >> creation, whether or not a program sits on the hook.
> >>
> >> Give the hook a strong prototype in bpf_lsm_proto.c so that its qstr and
> >> xattrs arguments are marked __nullable. Both can be NULL for some callers.
> >> Without the annotation the verifier otherwise hands the program a trusted
> >> non-NULL pointer which it dereferences. Also, keep the hook out of the
> >> sleepable set. inode_init_security runs inside the transaction creating
> >> the inode, with a journal handle held on ext4 and btrfs and the parent's
> >> i_rwsem down, which is why everything on the path allocates GFP_NOFS.
> >>
> >> Signed-off-by: David Windsor <dwindsor@xxxxxxxxx>
> >> Co-developed-by: Daniel Borkmann <daniel@xxxxxxxxxxxxx>
> >> Signed-off-by: Daniel Borkmann <daniel@xxxxxxxxxxxxx>
> >> ---
> >> fs/bpf_fs_kfuncs.c | 99 ++++++++++++++++++++++++++++++++++++++
> >> include/linux/bpf_lsm.h | 11 ++++-
> >> kernel/bpf/bpf_lsm.c | 22 ++++++++-
> >> kernel/bpf/bpf_lsm_proto.c | 15 ++++++
> >> security/bpf/hooks.c | 1 +
> >> 5 files changed, 145 insertions(+), 3 deletions(-)
> >
> > @Daniel, you were CC'd on David's previous patches, so I'm guessing
> > you saw my objection[1], but just in case you hadn't please look at my
> > comments where I requested that David's proposed LSM kfunc be located
> > in security/bpf_lsm_kfuncs.c as opposed to fs/bpf_fs_kfuncs.c. It
> > would be really nice if we could sort this out now and avoid having
> > this drag out or escalate.
>
> Paul, I reached out to David recently asking whether I could offer some
> help with the BPF bits, added some bug fixes and a lot more BPF selftests
> as I think the inode xattr init is valuable work and something we need as
> well. I just reread this whole thread below given its quite a while back
> and didn't follow in too much detail back then.. the location as it is is
> perfectly fine, I see no reason to change it, and I guess that makes three
> of us then including the VFS folks [0].
I didn't think there were any doubts that the BPF and VFS folks wanted
the kfunc in fs/bpf_fs_kfuncs.c, but I thought I made my objections
clear in the previous revisions. While you've changed things slightly
from David's last patchset, essentially folding the proposed
security_lsmxattr_add() helper into the bpf_inode_init_xattr(), it
does appear that the basic purpose and context around the kfunc
remains the same: the proposed kfunc is called from a LSM
inode_init_security callback, it populates a LSM framework managed
buffer, and then when the LSM callback returns the LSM framework code
in security_inode_init_security() does the xattr init based on the
buffers populated by all of the configured LSMs (the BPF LSM as well
as others). As there are no direct calls to the VFS layer in the
kfunc, but there are direct calls into LSM internal APIs (e.g.
lsm_get_xattr_slot(), as well as the LSM state and calling context
mentioned above, from my perspective this really does need to be
located in a LSM framework BPF kfunc file (e.g.
security/bpf_lsm_kfuncs.c). I've mentioned several times in David's
previous postings that I'm happy to work with you and the BPF devs to
set that up. If you are open to that let's sort it out now so we can
get everything in place before the merge window. If that isn't
something you are able to do, that would also be good to know.
--
paul-moore.com