[PATCH bpf-next 1/2] bpf: add bpf_init_inode_xattr kfunc for atomic inode labeling

Kumar Kartikeya Dwivedi memxor at gmail.com
Tue Apr 28 16:33:18 UTC 2026


On Tue, 28 Apr 2026 at 13:03, Matt Bobrowski <mattbobrowski at google.com> wrote:
>
> On Mon, Apr 27, 2026 at 04:33:18PM +0200, Kumar Kartikeya Dwivedi wrote:
> > On Mon, 27 Apr 2026 at 16:21, Song Liu <song at kernel.org> wrote:
> > >
> > > On Mon, Apr 27, 2026 at 11:11 AM Matt Bobrowski
> > > <mattbobrowski at google.com> wrote:
> n> > >
> > > > On Mon, Apr 27, 2026 at 05:32:47AM +0200, Kumar Kartikeya Dwivedi wrote:
> > > > > On Mon, 27 Apr 2026 at 05:24, David Windsor <dwindsor at gmail.com> wrote:
> > > > > >
> > > > > > On Sun, Apr 26, 2026 at 10:57 PM Kumar Kartikeya Dwivedi
> > > > > > <memxor at gmail.com> wrote:
> > > > > > >
> > > > > > > On Mon, 27 Apr 2026 at 02:16, David Windsor <dwindsor at gmail.com> wrote:
> > > > > > > >
> > > > > > > > Add bpf_init_inode_xattr() kfunc for BPF LSM programs to atomically set
> > > > > > > > xattrs via inode_init_security hook using lsm_get_xattr_slot().
> > > > > > > >
> > > > > > > > lsm_get_xattr_slot() claims a slot by writing to xattr_count, which BPF
> > > > > > > > programs cannot do: hook arguments are not directly writable from BPF.
> > > > > > > > To hide this, the BPF-facing API is just bpf_init_inode_xattr(name,
> > > > > > > > value), and the verifier transparently rewrites each call into
> > > > > > > > bpf_init_inode_xattr_impl(xattrs, xattr_count, name, value). xattrs and
> > > > > > > > xattr_count are extracted from the hook context, which the verifier
> > > > > > > > spills to the stack at program entry since R1 is clobbered during normal
> > > > > > > > execution.
> > > > > > > >
> > > > > > > > A previous attempt [1] required a kmalloc string output protocol for
> > > > > > > > the xattr name. Since commit 6bcdfd2cac55 ("security: Allow all LSMs to
> > > > > > > > provide xattrs for inode_init_security hook") [2], the xattr name is no
> > > > > > > > longer allocated; it is a static constant. We take advantage of this by
> > > > > > > > passing the name directly. Because we rely on the hook-specific ctx
> > > > > > > > layout, the kfunc is restricted to lsm/inode_init_security.
> > > > > > > >
> > > > > > > > Link: https://kernsec.org/pipermail/linux-security-module-archive/2022-October/034878.html [1]
> > > > > > > > Link: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=6bcdfd2cac55 [2]
> > > > > > > > Suggested-by: Song Liu <song at kernel.org>
> > > > > > > > Signed-off-by: David Windsor <dwindsor at gmail.com>
> > > > > > > > ---
> > > > > > >
> > > > > > > The explanation and code make no sense to me. Why not pass xattrs and
> > > > > > > xattr_count directly as arguments, even if you choose to restrict the
> > > > > > > kfunc to a specific hook? Why does the verifier core need the hack to
> > > > > > > spill the context and extract the two arguments?
> > > > > > >
> > > > > >
> > > > > > xattr_count is an output parameter; we cannot currently write to it in
> > > > > > bpf as there is no verifier support for writing to int *.  xattrs and
> > > > > > xattr_count can be fixed up by the verifier, so we only require the
> > > > > > user to pass the name and value.
> > > > >
> > > > > Sure, but the kfunc can. Did you try passing them in directly?
> > > > > If that doesn't work for some reason, we should fix it instead.
> > > >
> > > > Hm, perhaps this fixup approach might be the simplest in order to
> > > > assure the needed safety?
> > >
> > > +1. I think this is the best approach I can think of.
> >
> > We're not going to add more and more special cases to the verifier.
> > The whole approach is unscalable.
>
> Totally fair of you to push back here. I'm also agreement with you on
> the fact that extending the BPF verifier with such special casing
> doesn't scale all that well.
>
> > If the concern is that int xattr_count passed for xattrs can be
> > unrelated int pointer obtained from elsewhere, can we pack the xattrs
> > and xattr_count into a struct and pass it as an argument to the LSM?
> > Then the pair struct can be passed in directly, ensuring both
> > originate from the arguments passed to the LSM. That should eliminate
> > concerns about either being out of sync if obtained from different
> > sources.
>
> This could work, but we'd also need to modify all the other
> pre-existing hook implementations along with the core
> security_inode_init_security() LSM hook itself. I don't think that'd
> be an issue. The biggest hurdle here I think would be convincing the
> LSM maintainers themselves.

Yeah, when these parameters were introduced, we changed all LSMs, so I
don't see why we cannot adjust things again to benefit this use case.

>
> > Even if we wanted to ensure argument provenance was stuff loaded from
> > context, the right solution would be some kfunc flag that constraints
> > the argument to be derived by following the ctx pointer, not whatever
> > is done in this patch.
>
> OK, so it is provenance-like tracking which you were initially kinda
> alluding to here. Currently, I don't believe that PTR_TO_CTX is
> preserved upon any subsequent R1 (ctx) dereferences, so we'd need to
> think about how this type could be preserved such that we can enforce
> this kinda constraint (__ctx) at the time which the new BPF kfunc is
> called. Do you have any ideas on how to do this?

I think we'll have to track in the register whether the PTR_TO_BTF_ID
came from a PTR_TO_CTX load. That said, I still prefer changing the
prototype to pack the array and its output size parameter together. It
is even clearer to have a well named type than int *xattr_count in the
prototype.



More information about the Linux-security-module-archive mailing list