From: roblabla <linux@roblab.la>
To: "Daan De Meyer" <daan@amutable.com>, "Paul Moore" <paul@paul-moore.com>
Cc: bpf@vger.kernel.org, linux-security-module@vger.kernel.org,
paul.mabileau@harfanglab.fr, linux-kernel@vger.kernel.org,
"Andrii Nakryiko" <andrii@kernel.org>
Subject: [BUG] bpf, lsm: new first argument in 7.4 inode hooks silently breaks BPF LSMs
Date: Fri, 06 Nov 2026 14:38:49 +0100 [thread overview]
Message-ID: <356db94e-f5d6-4fb2-839a-b97aef72256b@app.fastmail.com> (raw)
In-Reply-To: <d85ece6e-27f9-4d9f-83af-4101bc76fef6@app.fastmail.com>
Resubmitting as plain text. Sorry for the noise.
Hello,
First of all, I'm sorry if I'm sending this email to the wrong mailing lists, it's my first time reporting a linux issue ^^'.
In commit 16959c469f232f5c76cfb628297cafbf6dbdba79 (lsm: expose mount idmaps to inode hooks), merged in 7.4-rc1, a new argument was added in position 0 of various inode-related `security_` functions. Specifically, it added this argument to inode_create, inode_link, inode_symlink, inode_mkdir, inode_mknod and inode_permission.
This has the immediate effect of breaking eBPF LSM programs relying on these hooks that were compiled with BPF CO-RE and using BPF_CORE_READ. Those programs don't simply stop loading (which would be fine enough) - instead, they will misinterpret the argument from one type to another, which can cause them to behave erratically. This has already bitten me in the past, when inode_setattr got a similar argument change in Linux 6.9. This caused our eBPF LSM to misbehave and deny actions that should have been ordinarily accepted, leading to huge production outages on our customers' machines.
Here's a simple reproducer that shows the problem (full repro with the loader, makefile and run.sh is at https://github.com/roblabla/kernel-7.4-bpf-bug-reproducer):
```
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_core_read.h>
char LICENSE[] SEC("license") = "GPL";
#define EPERM 1
#define NAME_LEN 32
static const char forbidden[] = "forbidden";
SEC("lsm/inode_create")
int BPF_PROG(deny_forbidden, struct inode *dir, struct dentry *dentry)
{
char name[NAME_LEN] = {};
const unsigned char *name_ptr;
unsigned long dir_ino;
dir_ino = BPF_CORE_READ(dir, i_ino);
name_ptr = BPF_CORE_READ(dentry, d_name.name);
bpf_probe_read_kernel_str(name, sizeof(name), name_ptr);
bpf_printk("inode_create: dir ino=%lu name='%s'", dir_ino, name);
for (int i = 0; i < sizeof(forbidden); i++)
if (name[i] != forbidden[i])
return 0;
bpf_printk("inode_create: denied '%s'", name);
return -EPERM;
}
```
Compile it under a kernel before 7.4 release, then run it on mainline. Here's the output:
- run on 7.1-rc7: touch forbidden: DENIED (dir ino=59 name='forbidden')
- run on 7.4-rc1: touch forbidden: created (dir ino=0 name='')
Before Linux 7.4, this program will properly deny the creation of any file named "forbidden". But in 7.4, the name_ptr BPF_CORE_READ will read garbage, and the check will fail. This is a bit of a contrived example, of course, but should show that there's a real problem in the way we handle eBPF loading in the face of changing signatures, that is prone to causing big compatibility issues.
Now, I'm not sure how the Linux Kernel treats eBPF LSM hooks - if they're considered part of the userspace that shouldn't be broken. My understanding is that kprobes are not part of the Linux Kernel stability guarantees, for rather obvious reasons (they allow watching the internals of the kernel) - but I'm not sure if this extends to the LSM Hooks. I assume not. Still, this kind of breakage is really painful for us, and I hope we can find a solution.
Could we fix this type of breakage by making sure new arguments are only added at the _end_ of the LSM hooks signatures, such that eBPF written for an older version of the kernel do not start misinterpreting arguments? eBPFs don't care about having "too few" arguments in the hook, so this would solve the situation.
Separately, I think the current lack of error handling in case of argument mismatch should really be improved. Could we perhaps have a mechanism such that the kernel (or maybe libbpf?) could check the arguments of the eBPF program, and refuse loading if it mismatches what the kernel expects?
Thanks,
roblabla
next parent reply other threads:[~2026-11-06 13:39 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <d85ece6e-27f9-4d9f-83af-4101bc76fef6@app.fastmail.com>
2026-11-06 13:38 ` roblabla [this message]
2026-11-06 15:41 ` Paul Moore
2026-11-06 19:33 ` Andrii Nakryiko
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=356db94e-f5d6-4fb2-839a-b97aef72256b@app.fastmail.com \
--to=linux@roblab.la \
--cc=andrii@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daan@amutable.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-security-module@vger.kernel.org \
--cc=paul.mabileau@harfanglab.fr \
--cc=paul@paul-moore.com \
/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
all inboxes | Powered by JetHome®