Re: [PATCH bpf-next 4/8] bpf, lsm: Let BPF LSM provide xattrs at inode creation
From: Daniel Borkmann
Date: Wed Sep 23 2026 - 15:46:58 EST
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]. In that file there are a number of
other kfuncs as well already related to xattr in context of dentry, files,
etc. I don't see a point at all on endless bike shedding on this, its
perfectly reasonably where this is located. In case you have some technical
comment or found a bug, let me know, happy to address.
[0] https://lore.kernel.org/bpf/20260625-schnabel-rennmaschine-parieren-bcb352c3cf59@brauner/
@David, simply for my own understanding, did you ask Daniel to do
this, or was Daniel operating on his own with this patchset?
[1] https://lore.kernel.org/linux-security-module/CAHC9VhTS7rSnBqg00ZxNkcZyh_=EeJmn_4z3CTCCxreEEDtTtg@xxxxxxxxxxxxxx/