[PATCH v2] relay: handle alloc_percpu returning NULL in relay_open

From: Daniel Axtens
Date: Thu Dec 19 2019 - 07:13:03 EST


alloc_percpu() may return NULL, which means chan->buf may be set to
NULL. In that case, when we do *per_cpu_ptr(chan->buf, ...), we
dereference an invalid pointer:

BUG: Unable to handle kernel data access at 0x7dae0000
Faulting instruction address: 0xc0000000003f3fec
...
NIP [c0000000003f3fec] relay_open+0x29c/0x600
LR [c0000000003f3fc0] relay_open+0x270/0x600
Call Trace:
[c000000054353a70] [c0000000003f3fb4] relay_open+0x264/0x600 (unreliable)
[c000000054353b00] [c000000000451764] __blk_trace_setup+0x254/0x600
[c000000054353bb0] [c000000000451b78] blk_trace_setup+0x68/0xa0
[c000000054353c10] [c0000000010da77c] sg_ioctl+0x7bc/0x2e80
[c000000054353cd0] [c000000000758cbc] do_vfs_ioctl+0x13c/0x1300
[c000000054353d90] [c000000000759f14] ksys_ioctl+0x94/0x130
[c000000054353de0] [c000000000759ff8] sys_ioctl+0x48/0xb0
[c000000054353e20] [c00000000000bcd0] system_call+0x5c/0x68

Check if alloc_percpu returns NULL.

This was found by syzkaller both on x86 and powerpc, and the reproducer
it found on powerpc is capable of hitting the issue as an unprivileged
user.

Fixes: 017c59c042d0 ("relay: Use per CPU constructs for the relay channel buffer pointers")
Reported-by: syzbot+1e925b4b836afe85a1c6@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Reported-by: syzbot+587b2421926808309d21@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Reported-by: syzbot+58320b7171734bf79d26@xxxxxxxxxxxxxxxxxxxxxxxxx
Reported-by: syzbot+d6074fb08bdb2e010520@xxxxxxxxxxxxxxxxxxxxxxxxx
Cc: Akash Goel <akash.goel@xxxxxxxxx>
Cc: Andrew Donnellan <ajd@xxxxxxxxxxxxx> # syzkaller-ppc64
Reviewed-by: Michael Ellerman <mpe@xxxxxxxxxxxxxx>
Reviewed-by: Andrew Donnellan <ajd@xxxxxxxxxxxxx>
Cc: stable@xxxxxxxxxxxxxxx # v4.10+
Signed-off-by: Daniel Axtens <dja@xxxxxxxxxx>

--

v2: drop the NOWARN.

There's a syz reproducer on the powerpc syzbot that eventually hits
the bug, but it can take up to an hour or so before it keels over on a
kernel with all the syzkaller debugging on, and even longer on a
production kernel. I have been able to reproduce it once on a stock
Ubuntu 5.0 ppc64le kernel.

CVE-2019-19462 has been assigned. While only the process doing the syscall
gets killed, it gets killed while holding the relay_channels_mutex,
so it blocks all future relay activity.
---
kernel/relay.c | 5 +++++
1 file changed, 5 insertions(+)

diff --git a/kernel/relay.c b/kernel/relay.c
index ade14fb7ce2e..4b760ec16342 100644
--- a/kernel/relay.c
+++ b/kernel/relay.c
@@ -581,6 +581,11 @@ struct rchan *relay_open(const char *base_filename,
return NULL;

chan->buf = alloc_percpu(struct rchan_buf *);
+ if (!chan->buf) {
+ kfree(chan);
+ return NULL;
+ }
+
chan->version = RELAYFS_CHANNEL_VERSION;
chan->n_subbufs = n_subbufs;
chan->subbuf_size = subbuf_size;
--
2.20.1