From: "Emil Tsalapatis" <emil@etsalapatis.com>
To: "Matt Bobrowski" <mattbobrowski@google.com>, <bpf@vger.kernel.org>
Cc: "Alexei Starovoitov" <ast@kernel.org>,
"Daniel Borkmann" <daniel@iogearbox.net>,
"Paul Moore" <paul@paul-moore.com>,
"Andrii Nakryiko" <andrii@kernel.org>,
"Martin KaFai Lau" <martin.lau@linux.dev>,
"Eduard Zingerman" <eddyz87@gmail.com>,
"Song Liu" <song@kernel.org>,
"Yonghong Song" <yonghong.song@linux.dev>,
"Jiri Olsa" <jolsa@kernel.org>, "oxsignal" <awo@kakao.com>
Subject: Re: [PATCH bpf-next] bpf: reject BPF_MAP_TYPE_INODE_STORAGE creation if BPF LSM is uninitialized
Date: Mon, 29 Jun 2026 01:25:03 -0400 [thread overview]
Message-ID: <DJLA7B56ET76.M6YCMTTMHXCZ@etsalapatis.com> (raw)
In-Reply-To: <20260628201103.3624525-1-mattbobrowski@google.com>
On Sun Jun 28, 2026 at 4:11 PM EDT, Matt Bobrowski wrote:
> When CONFIG_BPF_LSM=y is set, BPF inode storage maps
> (BPF_MAP_TYPE_INODE_STORAGE) are compiled into the kernel. However,
> if the BPF LSM is not explicitly enabled at boot time (e.g. omitted
> from the "lsm=" boot parameter), lsm_prepare() is never executed for
> the BPF LSM.
>
> Consequently, the BPF inode security blob offset
> (bpf_lsm_blob_sizes.lbs_inode) is never initialized and remains at its
> default compiled size of 8 bytes instead of being updated to a valid
> offset past the reserved struct rcu_head (typically 16 bytes or more).
>
> When a privileged user creates and updates a
> BPF_MAP_TYPE_INODE_STORAGE map, bpf_inode() evaluates
> inode->i_security + 8. This erroneously aliases the struct
> rcu_head.func callback pointer at the beginning of the
> inode->i_security blob. During subsequent map element cleanup or inode
> destruction, writing NULL to owner_storage clears the queued RCU
> callback pointer. When rcu_do_batch() later executes the queued
> callback, it attempts an instruction fetch at address 0x0, triggering
> an immediate kernel panic.
>
> Fix this by introducing a global bpf_lsm_initialized boolean flag
> marked with __ro_after_init. Set this flag to true inside
> bpf_lsm_init() when the LSM framework successfully registers the BPF
> LSM. Gate map allocation in inode_storage_map_alloc() on this flag,
> returning -EOPNOTSUPP if the BPF LSM is in turn uninitialized.
>
> This fail-fast approach prevents userspace from allocating inode
> storage maps when the supporting BPF LSM infrastructure is absent,
> avoiding zombie map states.
>
> Fixes: 8ea636848aca ("bpf: Implement bpf_local_storage for inodes")
> Reported-by: oxsignal <awo@kakao.com>
> Signed-off-by: Matt Bobrowski <mattbobrowski@google.com>
Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com>
It makes sense for since the only users of inode-local storage are
related to LSM (case in point, this whole bug is due to storing the
storage map in the inode's ->security in the first place).
> ---
> include/linux/bpf_lsm.h | 4 ++++
> kernel/bpf/bpf_inode_storage.c | 9 +++++++++
> security/bpf/hooks.c | 3 +++
> 3 files changed, 16 insertions(+)
>
> diff --git a/include/linux/bpf_lsm.h b/include/linux/bpf_lsm.h
> index 143775a27a2a..dda272d78f01 100644
> --- a/include/linux/bpf_lsm.h
> +++ b/include/linux/bpf_lsm.h
> @@ -14,6 +14,8 @@
>
> #ifdef CONFIG_BPF_LSM
>
> +extern bool bpf_lsm_initialized __ro_after_init;
> +
> #define LSM_HOOK(RET, DEFAULT, NAME, ...) \
> RET bpf_lsm_##NAME(__VA_ARGS__);
> #include <linux/lsm_hook_defs.h>
> @@ -56,6 +58,8 @@ bool bpf_lsm_hook_returns_errno(u32 btf_id);
>
> #else /* !CONFIG_BPF_LSM */
>
> +#define bpf_lsm_initialized false
> +
> static inline bool bpf_lsm_is_sleepable_hook(u32 btf_id)
> {
> return false;
> diff --git a/kernel/bpf/bpf_inode_storage.c b/kernel/bpf/bpf_inode_storage.c
> index 0da8d923e39d..f9e81060c1f4 100644
> --- a/kernel/bpf/bpf_inode_storage.c
> +++ b/kernel/bpf/bpf_inode_storage.c
> @@ -178,6 +178,15 @@ static int notsupp_get_next_key(struct bpf_map *map, void *key,
>
> static struct bpf_map *inode_storage_map_alloc(union bpf_attr *attr)
> {
> + /*
> + * Do not allow allocation of BPF_MAP_TYPE_INODE_STORAGE if the BPF LSM
> + * was not initialized by the LSM framework at boot. Without proper
> + * initialization, the BPF inode security blob offset remains unprepared,
> + * causing bpf_inode() to calculate an invalid memory offset and corrupt
> + * inode->i_security.
> + */
> + if (!bpf_lsm_initialized)
> + return ERR_PTR(-EOPNOTSUPP);
> return bpf_local_storage_map_alloc(attr, &inode_cache);
> }
>
> diff --git a/security/bpf/hooks.c b/security/bpf/hooks.c
> index 40efde233f3a..7b98f5d1e2be 100644
> --- a/security/bpf/hooks.c
> +++ b/security/bpf/hooks.c
> @@ -7,6 +7,8 @@
> #include <linux/bpf_lsm.h>
> #include <uapi/linux/lsm.h>
>
> +bool bpf_lsm_initialized __ro_after_init;
> +
> static struct security_hook_list bpf_lsm_hooks[] __ro_after_init = {
> #define LSM_HOOK(RET, DEFAULT, NAME, ...) \
> LSM_HOOK_INIT(NAME, bpf_lsm_##NAME),
> @@ -24,6 +26,7 @@ static int __init bpf_lsm_init(void)
> {
> security_add_hooks(bpf_lsm_hooks, ARRAY_SIZE(bpf_lsm_hooks),
> &bpf_lsmid);
> + bpf_lsm_initialized = true;
> pr_info("LSM support for eBPF active\n");
> return 0;
> }
next prev parent reply other threads:[~2026-06-29 5:25 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-28 20:11 [PATCH bpf-next] bpf: reject BPF_MAP_TYPE_INODE_STORAGE creation if BPF LSM is uninitialized Matt Bobrowski
2026-06-29 5:25 ` Emil Tsalapatis [this message]
2026-06-29 6:30 ` Amery Hung
2026-06-30 15:31 ` Daniel Borkmann
2026-07-02 20:55 ` Matt Bobrowski
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=DJLA7B56ET76.M6YCMTTMHXCZ@etsalapatis.com \
--to=emil@etsalapatis.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=awo@kakao.com \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=eddyz87@gmail.com \
--cc=jolsa@kernel.org \
--cc=martin.lau@linux.dev \
--cc=mattbobrowski@google.com \
--cc=paul@paul-moore.com \
--cc=song@kernel.org \
--cc=yonghong.song@linux.dev \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.