From: Kuniyuki Iwashima <kuniyu@google.com>
To: 2022090917019@std.uestc.edu.cn
Cc: M202472210@hust.edu.cn, bpf@vger.kernel.org,
daniel@iogearbox.net, dddddd@hust.edu.cn, dzm91@hust.edu.cn,
edumazet@google.com, hust-os-kernel-patches@googlegroups.com,
jiayuan.chen@linux.dev, kuniyu@google.com
Subject: Uninitialized Stack Variable / NULL Pointer Dereference in __sys_socket_create via BPF LSM hooks
Date: Tue, 21 Apr 2026 08:47:31 +0000 [thread overview]
Message-ID: <20260421084806.1785541-1-kuniyu@google.com> (raw)
In-Reply-To: <567d3206-74a5-44e5-99c6-779c425f399e@std.uestc.edu.cn>
From: Quan Sun <2022090917019@std.uestc.edu.cn>
Date: Tue, 21 Apr 2026 14:32:35 +0800
> Our fuzzing found an Uninitialized Stack Variable vulnerability in the
> Linux Socket Subsystem. The issue is triggered when a
> `BPF_PROG_TYPE_LSM` attached to the `bpf_lsm_socket_create` cgroup hook
> uses the `bpf_set_retval()` helper to return a value greater than 0
> (e.g., `1`). This bypasses the actual `socket_create` execution but
> returns a success status back to `__sys_socket_create`, which then
> accesses the uninitialized stack variable `sock` leading to a NULL
> pointer dereference or potential privilege escalation.
>
> Reported-by: Quan Sun <2022090917019@std.uestc.edu.cn>
> Reported-by: Yinhao Hu <dddddd@hust.edu.cn>
> Reported-by: Kaiyan Mei <M202472210@hust.edu.cn>
> Reviewed-by: Dongliang Mu <dzm91@hust.edu.cn>
>
> ## Root Cause
>
> This vulnerability is caused by treating a manipulated return value from
> an LSM hook as complete success in `__sys_socket_create` without
> ensuring that the underlying object has been fully initialized.
>
> 1. `__sys_socket_create()` in `net/socket.c` reserves a pointer variable
> `struct socket *sock;` on the kernel stack without zero-initializing it.
> 2. It calls `sock_create(family, type, protocol, &sock);` to allocate
> and initialize the socket object.
> 3. `sock_create` proceeds to allocate the socket internally and invokes
> the `security_socket_create` LSM hook (which triggers
> `bpf_lsm_socket_create`).
> 4. If a BPF program is attached to the cgroup LSM hook for
> `bpf_lsm_socket_create`, it can call `bpf_set_retval(1)` and return `1`.
> 5. Because the BPF hook completes without an error code (< 0),
> `sock_create` interprets this bypass as success and promptly returns `1`
> (or a positive bypass value) back to `__sys_socket_create()`. However,
> the critical variable `sock` is never populated.
> 6. The caller `__sys_socket_create()` checks if `sock_create()`'s return
> value is `< 0`. Since `1` is not less than `0`, it assumes the `sock`
> pointer is valid.
> 7. Subsequent socket operations inside `__sys_socket_create()`, such as
> `sock_map_fd(sock, ...)`, attempt to dereference the uninitialized
> `sock` stack pointer.
>
> #### Execution Flow Visualization
>
> ```text
> Vulnerability Execution Flow
> |
> |--- 1. `__sys_socket_create(...)`
> | |\
> | | `-- struct socket *sock; (Uninitialized pointer on stack)
> | |
> |--- 2. `sock_create(...)` -> `security_socket_create(...)`
> | |\
> | | `-- BPF LSM CGROUP hook for `bpf_lsm_socket_create` triggered.
> | | |
> | | `-- bpf_set_retval(1); return 1;
> | |
> |--- 3. Context switches back to `sock_create`
> | |\
> | | `-- LSM hook returns `1`. `sock_create` skips allocation and
> returns `1`.
> | |
> |--- 4. Context switches back to `__sys_socket_create`
> | |\
> | | `-- Check return value (1 < 0 is False). Treated as SUCCESS.
> | | |
> | | `-- `sock_map_fd(sock, ...)`
> | | |
> | | `-- Dereferences `sock` leading to KERNEL PANIC or Hijack.
> ```
>
> ## Reproduction Steps
>
> 1. Load a `BPF_PROG_TYPE_LSM` BPF program that:
> - Sets the target BTF ID to `bpf_lsm_socket_create`.
> - Calls the `bpf_set_retval(1)` helper inside the hook.
> 2. Attach the loaded program to a chosen cgroup directory using
> `BPF_LSM_CGROUP`.
> 3. Add the current process to the targeted cgroup.
> 4. Trigger the creation of a socket by invoking the `socket(AF_INET,
> SOCK_STREAM, 0)` system call from within the cgroup.
> 5. The `sock_create` function skips allocation, returns 1, and
> `__sys_socket_create` dereferences the uninitialized stack pointer.
Thanks for the report.
Maybe we could fix like below.
I guess all (most?) places suppose LSM to return 0 or
a negative value, and the btf_id_set_contains() check
would be unnecessary ?
---8<---
diff --git a/kernel/bpf/bpf_lsm.c b/kernel/bpf/bpf_lsm.c
index c5c925f00202..c4b9e9d4de92 100644
--- a/kernel/bpf/bpf_lsm.c
+++ b/kernel/bpf/bpf_lsm.c
@@ -87,6 +87,13 @@ BTF_ID(func, bpf_lsm_socket_socketpair)
#endif
BTF_SET_END(bpf_lsm_unlocked_sockopt_hooks)
+BTF_SET_START(bpf_lsm_negative_set_retval_hooks)
+#ifdef CONFIG_SECURITY_NETWORK
+BTF_ID(func, bpf_lsm_socket_create)
+#endif
+BTF_SET_END(bpf_lsm_negative_set_retval_hooks)
+
+
#ifdef CONFIG_CGROUP_BPF
void bpf_lsm_find_cgroup_shim(const struct bpf_prog *prog,
bpf_func_t *bpf_func)
@@ -221,12 +228,37 @@ static const struct bpf_func_proto bpf_get_attach_cookie_proto = {
.arg1_type = ARG_PTR_TO_CTX,
};
+BPF_CALL_1(bpf_lsm_set_retval, int, retval)
+{
+ struct bpf_cg_run_ctx *ctx;
+
+ if (retval > 0)
+ return -EINVAL;
+
+ ctx = container_of(current->bpf_ctx, struct bpf_cg_run_ctx, run_ctx);
+ ctx->retval = retval;
+
+ return 0;
+}
+
+const struct bpf_func_proto bpf_lsm_set_retval_proto = {
+ .func = bpf_lsm_set_retval,
+ .gpl_only = false,
+ .ret_type = RET_INTEGER,
+ .arg1_type = ARG_ANYTHING,
+};
+
static const struct bpf_func_proto *
bpf_lsm_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
{
const struct bpf_func_proto *func_proto;
if (prog->expected_attach_type == BPF_LSM_CGROUP) {
+ if (func_id == BPF_FUNC_set_retval &&
+ btf_id_set_contains(&bpf_lsm_negative_set_retval_hooks,
+ prog->aux->attach_btf_id))
+ return &bpf_lsm_set_retval_proto;
+
func_proto = cgroup_common_func_proto(func_id, prog);
if (func_proto)
return func_proto;
---8<---
next prev parent reply other threads:[~2026-04-21 8:48 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-21 6:32 Uninitialized Stack Variable / NULL Pointer Dereference in __sys_socket_create via BPF LSM hooks Quan Sun
2026-04-21 8:47 ` Kuniyuki Iwashima [this message]
2026-04-21 9:17 ` Matt Bobrowski
2026-04-21 9:59 ` Kuniyuki Iwashima
2026-04-21 13:05 ` Xu Kuohai
2026-04-21 20:20 ` Matt Bobrowski
2026-04-21 8:50 ` Matt Bobrowski
2026-04-21 9:11 ` Jiayuan Chen
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=20260421084806.1785541-1-kuniyu@google.com \
--to=kuniyu@google.com \
--cc=2022090917019@std.uestc.edu.cn \
--cc=M202472210@hust.edu.cn \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=dddddd@hust.edu.cn \
--cc=dzm91@hust.edu.cn \
--cc=edumazet@google.com \
--cc=hust-os-kernel-patches@googlegroups.com \
--cc=jiayuan.chen@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox