BPF List
 help / color / mirror / Atom feed
From: Yuqi Xu <xuyuqiabc@gmail.com>
To: bpf@vger.kernel.org
Cc: Vadim Fedorenko <vadim.fedorenko@linux.dev>,
	Alexei Starovoitov <ast@kernel.org>,
	Daniel Borkmann <daniel@iogearbox.net>,
	Andrii Nakryiko <andrii@kernel.org>,
	Eduard Zingerman <eddyz87@gmail.com>,
	Kumar Kartikeya Dwivedi <memxor@gmail.com>,
	Martin KaFai Lau <martin.lau@linux.dev>,
	Song Liu <song@kernel.org>,
	Yonghong Song <yonghong.song@linux.dev>,
	Jiri Olsa <jolsa@kernel.org>,
	Emil Tsalapatis <emil@etsalapatis.com>,
	Ihor Solodrai <ihor.solodrai@linux.dev>,
	stable@vger.kernel.org, Vega <vega@nebusec.ai>,
	Ren Wei <weir@nebusec.ai>,
	xuyq21@lenovo.com
Subject: Re: [PATCH bpf 1/1] bpf: crypto: check params size before reading reserved fields
Date: Sun, 20 Sep 2026 15:24:41 +0800	[thread overview]
Message-ID: <20260920072441.60435-1-xuyuqiabc@gmail.com> (raw)
In-Reply-To: <4f3ab4b03e79017e215521743996555439bf0bb3.1789802413.git.xuyuqiabc@gmail.com>

Hi all,

This note is about a Sashiko finding on the already-applied patch
(a11212910cf0); that review was not posted to the list.  The note
below is analysis only; I am not asking to change the merged patch.

> The `algo` string in `struct bpf_crypto_params` is not checked for
> null-termination before being passed to the crypto API. A BPF program
> can fill this array and subsequent fields with non-null bytes, causing
> `vsnprintf` in `request_module` to read out-of-bounds, potentially
> resulting in a kernel panic or leaking kernel memory to user-space.
> locations: kernel/bpf/crypto.c:165 `bpf_crypto_ctx_create`;
> kernel/bpf/crypto.c:185

This is a valid finding.  It is also pre-existing and independent of the
params__sz out-of-bounds read that this patch fixes.

The kfunc's __sz annotation only bounds-checks the buffer: the verifier
calls check_mem_size_reg() on the params / params__sz pair and checks
that params__sz bytes of the pointer are readable.  It neither zeroes
nor NUL-terminates the buffer.  After the size check in
bpf_crypto_ctx_create(), params__sz == sizeof(struct bpf_crypto_params)
== 408, so algo[] (offset 16, 128 bytes, kernel/bpf/crypto.c:33) lies
inside the validated region, but nothing guarantees a NUL anywhere in
it.  A program can pass reserved[0] = reserved[1] = 0 (which the
function requires) and fill algo[] and the trailing fields with non-NUL
bytes.

type->has_algo(params->algo) (kernel/bpf/crypto.c:165) then reaches an
unbounded read:

  bpf_crypto_lskcipher_has_algo()
    crypto_has_skcipher()          crypto/skcipher.c:666
      crypto_type_has_alg()        crypto/algapi.c:1039
        crypto_find_alg()          crypto/api.c:535
          crypto_alg_mod_lookup()  crypto/api.c:338
            crypto_larval_lookup()  crypto/api.c:290
              request_module("crypto-%s", name)   crypto/api.c:303
                vsnprintf(module_name, MODULE_NAME_LEN, fmt, args)
                                                  kernel/module/kmod.c:150

The "%s" conversion has no precision, so vsnprintf() does a plain
strlen() on name; it keeps reading through key[], key_len and authsize
and past the 408-byte region that the verifier validated, until it finds
a zero byte.  KASAN reports a slab-out-of-bounds read if the object ends
before the next zero.  That is the extent of the bug: the OOB is only
that strlen()/string_nocheck walk past the 408-byte region.  An
unterminated algo makes vsnprintf()'s "%s" read unbounded, but when the
return value is >= MODULE_NAME_LEN, kmod.c returns -ENAMETOOLONG and
does not reach call_modprobe() or the usermode helper.

The finding also cites kernel/bpf/crypto.c:185.  That line is a blank
line, not a second use of algo; if (!ctx) after kzalloc is at 181.
The nearby second use of params->algo is type->alloc_tfm() at 187;
185 is a near miss for that line.  A 128-byte all-non-NUL algo cannot
match any already-loaded cra_name, so has_algo() returns false,
bpf_crypto_ctx_create() sets -EOPNOTSUPP, and type->alloc_tfm() is
not reached.

This is only reachable from BPF_PROG_TYPE_SYSCALL (the
crypt_init_kfunc_set registration at kernel/bpf/crypto.c:393), which
requires CAP_BPF, so it is not an unprivileged attack.  Still, the
verifier-validated buffer is the trust boundary, and reading past it is
a bug regardless.

Relationship to this patch: the patch only moves the params__sz
comparison ahead of the reserved[] reads.  The algo[] termination
problem exists identically before and after it, so it is a separate root
cause and is neither fixed nor worsened here.

A follow-up would validate that the strings are terminated before
handing them to the crypto API, for example:

  if (strnlen(params->algo, sizeof(params->algo)) == sizeof(params->algo) ||
      strnlen(params->type, sizeof(params->type)) == sizeof(params->type)) {
          *err = -EINVAL;
          return NULL;
  }

(memchr(params->algo, '\0', sizeof(params->algo)) is equivalent.)
params is const, so writing
params->algo[sizeof(params->algo) - 1] = '\0' would modify the
caller's buffer; explicitly rejecting an unterminated name is cleaner
than silently truncating it.  params->type[] is only compared with
strcmp() against the short, NUL-terminated registered type names, so
it cannot drive the unbounded read, but validating both keeps them
consistent.

That would be a separate patch (Fixes: 3e1c6f35409f), not a change to
the already-merged commit.  Happy to send it if you want it.

Thanks,
Yuqi Xu

  parent reply	other threads:[~2026-09-20  7:25 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-19  8:45 [PATCH bpf 0/1] bpf: crypto: check params size before reading reserved fields Yuqi Xu
2026-09-19  8:45 ` [PATCH bpf 1/1] " Yuqi Xu
2026-09-19 18:17   ` Alexei Starovoitov
2026-09-20  7:24   ` Yuqi Xu [this message]
2026-09-19 23:30 ` [PATCH bpf 0/1] " patchwork-bot+netdevbpf

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=20260920072441.60435-1-xuyuqiabc@gmail.com \
    --to=xuyuqiabc@gmail.com \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=eddyz87@gmail.com \
    --cc=emil@etsalapatis.com \
    --cc=ihor.solodrai@linux.dev \
    --cc=jolsa@kernel.org \
    --cc=martin.lau@linux.dev \
    --cc=memxor@gmail.com \
    --cc=song@kernel.org \
    --cc=stable@vger.kernel.org \
    --cc=vadim.fedorenko@linux.dev \
    --cc=vega@nebusec.ai \
    --cc=weir@nebusec.ai \
    --cc=xuyq21@lenovo.com \
    --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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox