WSL2-Linux-Kernel/block
Omar Sandoval 8ba8682107 block: fix use-after-free in sys_ioprio_get()
get_task_ioprio() accesses the task->io_context without holding the task
lock and thus can race with exit_io_context(), leading to a
use-after-free. The reproducer below hits this within a few seconds on
my 4-core QEMU VM:

#define _GNU_SOURCE
#include <assert.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/wait.h>

int main(int argc, char **argv)
{
	pid_t pid, child;
	long nproc, i;

	/* ioprio_set(IOPRIO_WHO_PROCESS, 0, IOPRIO_PRIO_VALUE(IOPRIO_CLASS_IDLE, 0)); */
	syscall(SYS_ioprio_set, 1, 0, 0x6000);

	nproc = sysconf(_SC_NPROCESSORS_ONLN);

	for (i = 0; i < nproc; i++) {
		pid = fork();
		assert(pid != -1);
		if (pid == 0) {
			for (;;) {
				pid = fork();
				assert(pid != -1);
				if (pid == 0) {
					_exit(0);
				} else {
					child = wait(NULL);
					assert(child == pid);
				}
			}
		}

		pid = fork();
		assert(pid != -1);
		if (pid == 0) {
			for (;;) {
				/* ioprio_get(IOPRIO_WHO_PGRP, 0); */
				syscall(SYS_ioprio_get, 2, 0);
			}
		}
	}

	for (;;) {
		/* ioprio_get(IOPRIO_WHO_PGRP, 0); */
		syscall(SYS_ioprio_get, 2, 0);
	}

	return 0;
}

This gets us KASAN dumps like this:

[   35.526914] ==================================================================
[   35.530009] BUG: KASAN: out-of-bounds in get_task_ioprio+0x7b/0x90 at addr ffff880066f34e6c
[   35.530009] Read of size 2 by task ioprio-gpf/363
[   35.530009] =============================================================================
[   35.530009] BUG blkdev_ioc (Not tainted): kasan: bad access detected
[   35.530009] -----------------------------------------------------------------------------

[   35.530009] Disabling lock debugging due to kernel taint
[   35.530009] INFO: Allocated in create_task_io_context+0x2b/0x370 age=0 cpu=0 pid=360
[   35.530009] 	___slab_alloc+0x55d/0x5a0
[   35.530009] 	__slab_alloc.isra.20+0x2b/0x40
[   35.530009] 	kmem_cache_alloc_node+0x84/0x200
[   35.530009] 	create_task_io_context+0x2b/0x370
[   35.530009] 	get_task_io_context+0x92/0xb0
[   35.530009] 	copy_process.part.8+0x5029/0x5660
[   35.530009] 	_do_fork+0x155/0x7e0
[   35.530009] 	SyS_clone+0x19/0x20
[   35.530009] 	do_syscall_64+0x195/0x3a0
[   35.530009] 	return_from_SYSCALL_64+0x0/0x6a
[   35.530009] INFO: Freed in put_io_context+0xe7/0x120 age=0 cpu=0 pid=1060
[   35.530009] 	__slab_free+0x27b/0x3d0
[   35.530009] 	kmem_cache_free+0x1fb/0x220
[   35.530009] 	put_io_context+0xe7/0x120
[   35.530009] 	put_io_context_active+0x238/0x380
[   35.530009] 	exit_io_context+0x66/0x80
[   35.530009] 	do_exit+0x158e/0x2b90
[   35.530009] 	do_group_exit+0xe5/0x2b0
[   35.530009] 	SyS_exit_group+0x1d/0x20
[   35.530009] 	entry_SYSCALL_64_fastpath+0x1a/0xa4
[   35.530009] INFO: Slab 0xffffea00019bcd00 objects=20 used=4 fp=0xffff880066f34ff0 flags=0x1fffe0000004080
[   35.530009] INFO: Object 0xffff880066f34e58 @offset=3672 fp=0x0000000000000001
[   35.530009] ==================================================================

Fix it by grabbing the task lock while we poke at the io_context.

Cc: stable@vger.kernel.org
Reported-by: Dmitry Vyukov <dvyukov@google.com>
Signed-off-by: Omar Sandoval <osandov@fb.com>
Signed-off-by: Jens Axboe <axboe@fb.com>
2016-07-01 08:39:24 -06:00
..
partitions block/partitions/ldm.c: use generic UUID library 2016-05-20 17:58:30 -07:00
Kconfig
Kconfig.iosched
Makefile
badblocks.c
bio-integrity.c
bio.c block: make bio_inc_remaining() interface accessible again 2016-05-05 13:03:29 -06:00
blk-cgroup.c
blk-core.c block: kill off q->flush_flags 2016-04-13 13:33:19 -06:00
blk-exec.c
blk-flush.c block: kill off q->flush_flags 2016-04-13 13:33:19 -06:00
blk-integrity.c
blk-ioc.c
blk-lib.c block: missing bio_put following submit_bio_wait 2016-06-07 10:47:48 -06:00
blk-map.c fix the copy vs. map logics in blk_rq_map_user_iov() 2016-04-08 19:46:28 -04:00
blk-merge.c
blk-mq-cpu.c
blk-mq-cpumap.c
blk-mq-sysfs.c blk-mq: Use proper cpumask iterator 2016-03-20 09:34:02 -06:00
blk-mq-tag.c blk-mq: Make blk_mq_all_tag_busy_iter static 2016-04-12 15:07:36 -06:00
blk-mq-tag.h
blk-mq.c blk-mq: really fix plug list flushing for nomerge queues 2016-06-02 11:47:32 -06:00
blk-mq.h
blk-settings.c block: kill off q->flush_flags 2016-04-13 13:33:19 -06:00
blk-softirq.c
blk-sysfs.c block: add ability to flag write back caching on a device 2016-04-12 15:46:27 -06:00
blk-tag.c
blk-throttle.c blk-throttle: don't parse cgroup path if trace isn't enabled 2016-05-10 08:41:37 -06:00
blk-timeout.c
blk.h
bounce.c
bsg-lib.c
bsg.c
cfq-iosched.c mm, fs: get rid of PAGE_CACHE_* and page_cache_{get,release} macros 2016-04-04 10:41:08 -07:00
cmdline-parser.c
compat_ioctl.c mm, fs: get rid of PAGE_CACHE_* and page_cache_{get,release} macros 2016-04-04 10:41:08 -07:00
deadline-iosched.c
elevator.c
genhd.c
ioctl.c DAX error handling for 4.7 2016-05-26 19:34:26 -07:00
ioprio.c block: fix use-after-free in sys_ioprio_get() 2016-07-01 08:39:24 -06:00
noop-iosched.c
partition-generic.c Merge branch 'for-linus' of git://git.kernel.dk/linux-block 2016-04-15 15:44:10 -07:00
scsi_ioctl.c
t10-pi.c