Re: [PATCH v5 bpf-next 1/3] security: rework inode_init_security xattr handling

David Windsor <[email protected]>
Newsgroups org.kernel.vger.selinux,dev.linux.lists.sashiko-reviews,org.kernel.vger.bpf
Message-ID <CAEXv5_hyXHEKTfFCb9sSi=Z6B3W-PEue=x07sh_-Y56M7V=esA@mail.gmail.com>
On Tue, Jul 7, 2026 at 8:20 PM <[email protected]> wrote:
>
> Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
> - [High] Heap buffer overflow in `security_lsmxattr_add()` due to xattr quota bypass by BPF programs.
> - [Medium] `security_lsmxattr_add()` incorrectly returns `-EINVAL` instead of `-EOPNOTSUPP` when the xattr array is not allocated.
> --
>
> --- Patch [1]: [PATCH v5 bpf-next 1/3] security: rework inode_init_security xattr handling ---
> commit 871b3020e8c69372708886992716ee08d2e36bc2
> Author: David Windsor <[email protected]>
>
> security: rework inode_init_security xattr handling
>
> In preparation for bpf_init_inode_xattr(), a kfunc that lets bpf LSM
> programs atomically label new inodes, rework how inode_init_security
> xattrs are managed.
>
> > diff --git a/security/security.c b/security/security.c
> > --- a/security/security.c
> > +++ b/security/security.c
>
> [ ... ]
>
> > +/**
> > + * security_lsmxattr_add() - Add an xattr during inode_init_security
> > + * @xattrs: xattr state shared by inode_init_security hooks
> > + * @lsm_id: LSM_ID_* value identifying the calling LSM
> > + * @name: xattr name suffix
> > + * @value: xattr value
> > + * @value_len: length of @value
> > + *
> > + * Claim an xattr slot in @xattrs on behalf of the LSM identified by
> > + * @lsm_id and fill it with a copy of @name and @value. Callers can invoke
> > + * this function from non-sleepable context.
> > + *
> > + * Return: Returns 0 on success, -ENOSPC if the calling LSM's slot budget
> > + *         is exhausted, negative values on other errors.
> > + */
> > +int security_lsmxattr_add(struct lsm_xattrs *xattrs, u64 lsm_id,
> > +                       const char *name, const void *value,
> > +                       size_t value_len)
> > +{
> > +     struct xattr *xattr;
> > +     void *xattr_value;
> > +     size_t name_len;
> > +
> > +     if (!xattrs || !xattrs->xattrs || !name || !value)
> > +             return -EINVAL;
>
> [Severity: Medium]
> Should this return -EOPNOTSUPP instead of -EINVAL when the xattrs array
> is not allocated?
>
> During file creation on filesystems without xattr support,
> security_inode_init_security() is called with initxattrs == NULL,
> deliberately leaving xattrs.xattrs unallocated.
>
> If a BPF program then calls security_lsmxattr_add(), it will receive
> -EINVAL. If the BPF program propagates this error, it will abort the
> inode creation entirely because security_inode_init_security() only
> treats -EOPNOTSUPP as a graceful fallback.
>
> > +
> > +     name_len = strlen(name);
> > +     if (name_len == 0 || name_len > XATTR_NAME_MAX)
> > +             return -EINVAL;
> > +     if (value_len == 0 || value_len > XATTR_SIZE_MAX)
> > +             return -EINVAL;
> > +
> > +     switch (lsm_id) {
> > +#ifdef CONFIG_BPF_LSM
> > +     case LSM_ID_BPF:
> > +             if (lsm_xattrs_used(xattrs, XATTR_BPF_LSM_SUFFIX) >=
> > +                 BPF_LSM_INODE_INIT_XATTRS)
> > +                     return -ENOSPC;
>
> [Severity: High]
> Can this limit check be bypassed, leading to a heap buffer overflow?
>
> If a BPF program repeatedly calls security_lsmxattr_add() with a name
> that does not begin with XATTR_BPF_LSM_SUFFIX, lsm_xattrs_used() will
> not count them.
>

Sorry, all paths to calling this function are guaranteed to have
XATTR_BPF_LSM_SUFFIX.

> This allows bypassing the BPF_LSM_INODE_INIT_XATTRS limit. Since
> lsm_get_xattr_slot() does not check against the actual allocated heap
> size, it will increment ctx->xattr_count and return out-of-bounds
> pointers:
>
> include/linux/lsm_hooks.h:lsm_get_xattr_slot() {
>     ...
>     return &ctx->xattrs[ctx->xattr_count++];
> }
>
> Could this cause out-of-bounds writes when assigning xattr->value and
> xattr->name further down in this function?
>
> > +             break;
> > +#endif /* CONFIG_BPF_LSM */
> > +     default:
> > +             return -EINVAL;
> > +     }
> > +
> > +     /* Combine xattr value + name into one allocation. */
> > +     xattr_value = kmalloc(value_len + name_len + 1, GFP_NOWAIT);
> > +     if (!xattr_value)
> > +             return -ENOMEM;
>
> --
> Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.