public inbox for io-uring@vger.kernel.org
 help / color / mirror / Atom feed
From: Jarkko Sakkinen <jarkko@kernel.org>
To: Jann Horn <jannh@google.com>
Cc: David Howells <dhowells@redhat.com>,
	keyrings@vger.kernel.org,
	Roberto Sassu <roberto.sassu@huawei.com>,
	Kumar Kartikeya Dwivedi <memxor@gmail.com>,
	Song Liu <song@kernel.org>, Alexei Starovoitov <ast@kernel.org>,
	Herbert Xu <herbert@gondor.apana.org.au>,
	"David S. Miller" <davem@davemloft.net>,
	linux-crypto@vger.kernel.org, Jens Axboe <axboe@kernel.dk>,
	io-uring <io-uring@vger.kernel.org>,
	Daniel Borkmann <daniel@iogearbox.net>,
	Andrii Nakryiko <andrii@kernel.org>,
	Eduard Zingerman <eddyz87@gmail.com>,
	Martin KaFai Lau <martin.lau@linux.dev>,
	Yonghong Song <yonghong.song@linux.dev>,
	Jiri Olsa <jolsa@kernel.org>,
	Emil Tsalapatis <emil@etsalapatis.com>,
	Ihor Solodrai <ihor.solodrai@linux.dev>,
	bpf <bpf@vger.kernel.org>
Subject: Re: [BUG] lookup_user_key() calls commit_creds() (hitting BUG_ON() when called from io_uring through AF_ALG setsockopt; BPF probably also affected)
Date: Fri, 18 Sep 2026 04:39:44 +0300	[thread overview]
Message-ID: <aqyWYIoh-JONhsjN@kernel.org> (raw)
In-Reply-To: <CAG48ez0XjVSR=M--UBauTm8sJuc+ZbhKzaPa3a6wrSVHyoKevw@mail.gmail.com>

On Fri, Sep 11, 2026 at 07:42:50PM +0200, Jann Horn wrote:
> When lookup_user_key() is called on a special keyring ID
> (KEY_SPEC_*_KEYRING), it can end up calling commit_creds() on several
> codepaths:
> 
> lookup_user_key
>   install_thread_keyring [KEY_SPEC_THREAD_KEYRING + KEY_LOOKUP_CREATE]
>     commit_creds
>   install_process_keyring [KEY_SPEC_PROCESS_KEYRING + KEY_LOOKUP_CREATE]
>     commit_creds
>   join_session_keyring [KEY_SPEC_SESSION_KEYRING + KEY_LOOKUP_CREATE]
>     commit_creds
>   install_session_keyring [KEY_SPEC_SESSION_KEYRING]
>     commit_creds
> 
> commit_creds() is only allowed when the process does not have
> overridden credentials. commit_creds() also requires that no
> non-refcounted pointers obtained from current_cred() are live in any
> callers.
> 
> lookup_user_key() is used by lots of keyctl operations, where it can
> make sense to refer to special keyring IDs; but it is also used by
> other subsystems (such as AF_ALG, nvdimm, fscrypt, BPF, ...) to look
> up user-specified key IDs. In that case, special keyring IDs don't
> make sense (because they refer to keyrings, not individual
> cryptographic keys), and calling commit_creds() is unsafe.
> 
> It would be nice if we could ensure that commit_creds() can only be
> called when KEY_LOOKUP_CREATE is set (which is only used for special
> key IDs); maybe we could replace the
> install_session_keyring(user_session) call with something that just
> grabs a reference to the session keyring and returns it?
> 
> I made a reproducer for the lookup_user_key() call in AF_ALG, but I
> think several other callers of lookup_user_key() are probably also
> affected, like bpf_lookup_user_key() and nvdimm_lookup_user_key().
> 
> bpf_lookup_user_key() will probably require separate fixing; it seems
> to be intentionally designed to be able to look up and create special
> key IDs, but is part of the generic_kfunc_set kfunc set, which can
> probably run in some contexts with overridden creds, like in arbitrary
> LSM hooks. That seems inherently broken.
> 
> Reproducer
> ==========
> As an example, when I use io_uring with ->personality to indirectly
> call setsockopt(af_alg_sock, SOL_ALG, ALG_SET_KEY_BY_KEY_SERIAL,
> &KEY_SPEC_SESSION_KEYRING, sizeof(int)), the kernel will go down the
> following call graph.
> 
> sys_io_uring_enter
>   io_submit_sqes
>     io_submit_sqe
>       io_init_req
>         [set REQ_F_CREDS if sqe->personality is set]
>       io_queue_sqe
>         io_issue_sqe
>           __io_issue_sqe
>             override_creds [if REQ_F_CREDS is set and creds differ]
>             io_uring_cmd
>               io_uring_cmd_sock
>                 io_uring_cmd_setsockopt
>                   do_sock_setsockopt
>                     alg_setsockopt
>                       alg_setkey_by_key_serial
>                         lookup_key
>                           lookup_user_key
>                             install_session_keyring
>                               commit_creds
>                                 BUG_ON(task->cred != old)
>             revert_creds
> 
> Running this reproducer:
> 
> #define _GNU_SOURCE
> #include <err.h>
> #include <stdio.h>
> #include <unistd.h>
> #include <sys/mman.h>
> #include <sys/socket.h>
> #include <sys/syscall.h>
> #include <linux/if_alg.h>
> #include <linux/io_uring.h>
> #include <linux/keyctl.h>
> 
> #define SYSCHK(x) ({          \
>   typeof(x) __res = (x);      \
>   if (__res == (typeof(x))-1) \
>     err(1, "SYSCHK(" #x ")"); \
>   __res;                      \
> })
> 
> int main(void) {
>   int alg_sock = SYSCHK(socket(AF_ALG, SOCK_SEQPACKET, 0));
>   struct sockaddr_alg addr = {
>     .salg_family = AF_ALG,
>     .salg_type = "hash",
>     .salg_name = "sha1"
>   };
>   SYSCHK(bind(alg_sock, (struct sockaddr *)&addr, sizeof(addr)));
> 
>   struct io_uring_params params = { .flags = IORING_SETUP_NO_SQARRAY };
>   int uring_fd = SYSCHK(syscall(__NR_io_uring_setup, /*entries=*/4, &params));
> 
>   // let io_uring grab a reference to the current creds
>   int personality = SYSCHK(syscall(__NR_io_uring_register, uring_fd,
> IORING_REGISTER_PERSONALITY, NULL, 0));
>   // change our creds so that the io_uring personality is different
> from current creds
>   SYSCHK(syscall(__NR_keyctl, KEYCTL_GET_KEYRING_ID,
> KEY_SPEC_SESSION_KEYRING, 0, 0, 0));
> 
>   char *ring_region = SYSCHK(mmap(NULL, 0x1000, PROT_READ|PROT_WRITE,
> MAP_SHARED, uring_fd, IORING_OFF_CQ_RING));
>   struct io_uring_sqe *sqes = SYSCHK(mmap(NULL, 0x1000,
> PROT_READ|PROT_WRITE, MAP_SHARED, uring_fd, IORING_OFF_SQES));
> 
>   int key_serial = KEY_SPEC_SESSION_KEYRING;
>   sqes[0] = (struct io_uring_sqe) {
>     .opcode = IORING_OP_URING_CMD,
>     .fd = alg_sock,
>     .personality = personality,
> 
>     /* specific to uring_cmd */
>     .cmd_op = SOCKET_URING_OP_SETSOCKOPT,
>     .optname = ALG_SET_KEY_BY_KEY_SERIAL,
>     .optval = (unsigned long)&key_serial,
>     .optlen = sizeof(key_serial),
>     .level = SOL_ALG,
>   };
>   (*(unsigned int *)(ring_region + params.sq_off.tail))++;
> 
>   int submitted = SYSCHK(syscall(__NR_io_uring_enter, uring_fd,
>                                    /*to_submit=*/1, /*min_complete=*/1,
>                                    /*flags=*/0, /*sig=*/NULL, /*sigsz=*/0));
>   printf("submitted %d and completed\n", submitted);
> }
> 
> 
> I get this splat:
> 
> [  543.190354][  T111] kernel BUG at kernel/cred.c:376!
> [...]
> [  543.196705][  T111] Call Trace:
> [...]
> [  543.197319][  T111]  lookup_user_key+0x261/0xbe0
> [...]
> [  543.197869][  T111]  alg_setkey_by_key_serial+0xbc/0x300
> [  543.198153][  T111]  alg_setsockopt+0x1a2/0x2a0
> [...]
> [  543.198610][  T111]  do_sock_setsockopt+0x103/0x130
> [  543.198863][  T111]  io_uring_cmd_sock+0x257/0x8b0
> [...]
> [  543.199608][  T111]  io_uring_cmd+0x1f3/0x2a0
> [...]
> [  543.200103][  T111]  __io_issue_sqe+0xd8/0x2a0
> [  543.200335][  T111]  io_issue_sqe+0xde/0x8c0
> [...]
> [  543.201100][  T111]  io_submit_sqes+0x7a6/0x1060
> [  543.201380][  T111]  __se_sys_io_uring_enter+0x218/0xf40
> [...]
> [  543.202158][  T111]  __x64_sys_io_uring_enter+0x82/0xa0
> [...]
> [  543.202780][  T111]  x64_sys_call+0x175f/0x2600
> [  543.203086][  T111]  do_syscall_64+0xbe/0x360
> [  543.203348][  T111]  entry_SYSCALL_64_after_hwframe+0x76/0x7e

Just got this while going through inbox.

I'll run the reproducer with a test environment and respond properly
later.

BR, Jarkko

      reply	other threads:[~2026-09-18  1:39 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-11 17:42 [BUG] lookup_user_key() calls commit_creds() (hitting BUG_ON() when called from io_uring through AF_ALG setsockopt; BPF probably also affected) Jann Horn
2026-09-18  1:39 ` Jarkko Sakkinen [this message]

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=aqyWYIoh-JONhsjN@kernel.org \
    --to=jarkko@kernel.org \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=axboe@kernel.dk \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=davem@davemloft.net \
    --cc=dhowells@redhat.com \
    --cc=eddyz87@gmail.com \
    --cc=emil@etsalapatis.com \
    --cc=herbert@gondor.apana.org.au \
    --cc=ihor.solodrai@linux.dev \
    --cc=io-uring@vger.kernel.org \
    --cc=jannh@google.com \
    --cc=jolsa@kernel.org \
    --cc=keyrings@vger.kernel.org \
    --cc=linux-crypto@vger.kernel.org \
    --cc=martin.lau@linux.dev \
    --cc=memxor@gmail.com \
    --cc=roberto.sassu@huawei.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox