From: Matt Bobrowski <mattbobrowski@google.com>
To: Kuniyuki Iwashima <kuniyu@google.com>
Cc: 2022090917019@std.uestc.edu.cn, 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
Subject: Re: Uninitialized Stack Variable / NULL Pointer Dereference in __sys_socket_create via BPF LSM hooks
Date: Tue, 21 Apr 2026 09:17:29 +0000 [thread overview]
Message-ID: <aedAqdeuVqLq4hDQ@google.com> (raw)
In-Reply-To: <20260421084806.1785541-1-kuniyu@google.com>
On Tue, Apr 21, 2026 at 08:47:31AM +0000, Kuniyuki Iwashima wrote:
> 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;
Sorry, I missed this response. I was probably typing out my response
(https://lore.kernel.org/bpf/aec6Q1g2K8vP_jck@google.com/) whilst this
had already come through.
I guess this is kinda on the right path and how I'd probably go about
fixing part of the underlying issue. My slight concern/reservation is
that it's highly BPF LSM specific as it's focused only on preventing
the BPF LSM from violating the expected semantics of the LSM hook.
The other immediate issue here which I think also needs to be
addressed is that __sys_socket_create() operates on an uninitialized
pointer and assumes that any non-negative return value from
sock_create() means that the pointer is valid. I'd probably also
propose making __sys_socket_create() a little more fail-safe by
initializing sock to NULL and explicitly checking both the return code
and the poitner validity post calling into sock_create(). This makes
the caller robust against any failure of sock_create() to fulfill its
implied contract (initializing the sock pointer on success),
regardless of whether that failure was caused by BPF, some other LSM,
or a bug in a protocols family's ->create() function.
What do you think?
next prev parent reply other threads:[~2026-04-21 9:17 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
2026-04-21 9:17 ` Matt Bobrowski [this message]
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=aedAqdeuVqLq4hDQ@google.com \
--to=mattbobrowski@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 \
--cc=kuniyu@google.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