All of lore.kernel.org
 help / color / mirror / Atom feed
From: Dipanjan Das <mail.dipanjan.das@gmail.com>
To: dhowells@redhat.com, Greg KH <gregkh@linuxfoundation.org>,
	sashal@kernel.org, fmdefrancesco@gmail.com, edumazet@google.com,
	linux-kernel@vger.kernel.org
Cc: syzkaller@googlegroups.com, fleischermarius@googlemail.com,
	its.priyanka.bose@gmail.com
Subject: KASAN: use-after-free Read in post_one_notification
Date: Wed, 27 Jul 2022 14:28:45 -0700	[thread overview]
Message-ID: <CANX2M5bHye2ZEEhEV6PUj1kYL2KdWYeJtgXw8KZRzwrNpLYz+A@mail.gmail.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 5798 bytes --]

Hi,

We would like to report the following bug which has been found by our
modified version of syzkaller.

======================================================
description: KASAN: use-after-free Read in post_one_notification
affected file: kernel/watch_queue.c
kernel version: 5.10.131
kernel commit: 8f95261a006489c828f1d909355669875649668b
git tree: upstream
kernel config: https://syzkaller.appspot.com/x/.config?x=e49433cfed49b7d9
crash reproducer: attached
patch: This bug was previously reported by syzkaller for kernel
version 5.17. The same patch works for kernel version 5.10 as well,
i.e., we tested that the repro can no longer triggers the reported
crash with this patch:
https://syzkaller.appspot.com/text?tag=Patch&x=13b8c83c080000
======================================================
Crash log:
======================================================
BUG: KASAN: use-after-free in __lock_acquire+0x3867/0x5840
kernel/locking/lockdep.c:4824
Read of size 8 at addr ffff8880aa5f8ca8 by task syz-executor.5/1878

CPU: 0 PID: 1878 Comm: syz-executor.5 Tainted: G           OE     5.10.131+ #3
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS
1.13.0-1ubuntu1.1 04/01/2014
Call Trace:
 __dump_stack lib/dump_stack.c:77 [inline]
 dump_stack+0x107/0x163 lib/dump_stack.c:118
 print_address_description.constprop.0.cold+0xd3/0x4f7 mm/kasan/report.c:385
 __kasan_report mm/kasan/report.c:545 [inline]
 kasan_report.cold+0x1f/0x37 mm/kasan/report.c:562
 __lock_acquire+0x3867/0x5840 kernel/locking/lockdep.c:4824
 lock_acquire kernel/locking/lockdep.c:5564 [inline]
 lock_acquire+0x1a8/0x4b0 kernel/locking/lockdep.c:5529
 __raw_spin_lock_irq include/linux/spinlock_api_smp.h:128 [inline]
 _raw_spin_lock_irq+0x32/0x50 kernel/locking/spinlock.c:167
 spin_lock_irq include/linux/spinlock.h:379 [inline]
 post_one_notification+0x59/0x860 kernel/watch_queue.c:86
 __post_watch_notification kernel/watch_queue.c:206 [inline]
 __post_watch_notification+0x562/0x840 kernel/watch_queue.c:176
 post_watch_notification include/linux/watch_queue.h:109 [inline]
 notify_key security/keys/internal.h:199 [inline]
 __key_update security/keys/key.c:774 [inline]
 key_create_or_update+0xbff/0xd00 security/keys/key.c:977
 __do_sys_add_key security/keys/keyctl.c:134 [inline]
 __se_sys_add_key security/keys/keyctl.c:74 [inline]
 __x64_sys_add_key+0x2ab/0x4b0 security/keys/keyctl.c:74
 do_syscall_64+0x2d/0x70 arch/x86/entry/common.c:46
 entry_SYSCALL_64_after_hwframe+0x44/0xa9
RIP: 0033:0x7fc85a2514ed
Code: 02 b8 ff ff ff ff c3 66 0f 1f 44 00 00 f3 0f 1e fa 48 89 f8 48
89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d
01 f0 ff ff 73 01 c3 48 c7 c1 b8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007fc858201be8 EFLAGS: 00000246 ORIG_RAX: 00000000000000f8
RAX: ffffffffffffffda RBX: 00007fc85a36ff60 RCX: 00007fc85a2514ed
RDX: 0000000020000080 RSI: 0000000020000040 RDI: 0000000020000000
RBP: 00007fc85a2bd2e1 R08: fffffffffffffffc R09: 0000000000000000
R10: 0000000000000001 R11: 0000000000000246 R12: 0000000000000000
R13: 00007ffde3e9524f R14: 00007fc85a36ff60 R15: 00007fc858201d80

Allocated by task 1368:
 kasan_save_stack+0x1b/0x40 mm/kasan/common.c:49
 kasan_set_track mm/kasan/common.c:57 [inline]
 __kasan_kmalloc.constprop.0+0xcf/0xe0 mm/kasan/common.c:471
 kmalloc include/linux/slab.h:552 [inline]
 kzalloc include/linux/slab.h:664 [inline]
 alloc_pipe_info+0x10c/0x500 fs/pipe.c:789
 get_pipe_inode fs/pipe.c:880 [inline]
 create_pipe_files+0x8f/0x7d0 fs/pipe.c:912
 __do_pipe_flags+0x41/0x240 fs/pipe.c:961
 do_pipe2+0x77/0x160 fs/pipe.c:1009
 __do_sys_pipe2 fs/pipe.c:1027 [inline]
 __se_sys_pipe2 fs/pipe.c:1025 [inline]
 __x64_sys_pipe2+0x50/0x70 fs/pipe.c:1025
 do_syscall_64+0x2d/0x70 arch/x86/entry/common.c:46
 entry_SYSCALL_64_after_hwframe+0x44/0xa9

Freed by task 1402:
 kasan_save_stack+0x1b/0x40 mm/kasan/common.c:49
 kasan_set_track+0x1c/0x30 mm/kasan/common.c:57
 kasan_set_free_info+0x1b/0x30 mm/kasan/generic.c:363
 __kasan_slab_free+0x111/0x150 mm/kasan/common.c:427
 slab_free_hook mm/slub.c:1542 [inline]
 slab_free_freelist_hook mm/slub.c:1576 [inline]
 slab_free mm/slub.c:3149 [inline]
 kfree+0xfa/0x460 mm/slub.c:4125
 put_pipe_info+0xb9/0xe0 fs/pipe.c:710
 pipe_release+0x1d2/0x260 fs/pipe.c:733
 __fput+0x285/0x920 fs/file_table.c:281
 task_work_run+0xe0/0x1a0 kernel/task_work.c:151
 tracehook_notify_resume include/linux/tracehook.h:188 [inline]
 exit_to_user_mode_loop kernel/entry/common.c:164 [inline]
 exit_to_user_mode_prepare+0x195/0x1b0 kernel/entry/common.c:191
 syscall_exit_to_user_mode+0x38/0x260 kernel/entry/common.c:266
 entry_SYSCALL_64_after_hwframe+0x44/0xa9

The buggy address belongs to the object at ffff8880aa5f8c00
 which belongs to the cache kmalloc-512 of size 512
The buggy address is located 168 bytes inside of
 512-byte region [ffff8880aa5f8c00, ffff8880aa5f8e00)
The buggy address belongs to the page:
page:000000000cd222be refcount:1 mapcount:0 mapping:0000000000000000
index:0x0 pfn:0xaa5f8
head:000000000cd222be order:2 compound_mapcount:0 compound_pincount:0
flags: 0xfff00000010200(slab|head)
raw: 00fff00000010200 dead000000000100 dead000000000122 ffff888100041280
raw: 0000000000000000 0000000000100010 00000001ffffffff 0000000000000000
page dumped because: kasan: bad access detected

Memory state around the buggy address:
 ffff8880aa5f8b80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
 ffff8880aa5f8c00: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
>ffff8880aa5f8c80: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
                                  ^
 ffff8880aa5f8d00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
 ffff8880aa5f8d80: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
==================================================================


-- 
Thanks and Regards,

Dipanjan

[-- Attachment #2: repro.c --]
[-- Type: text/x-csrc, Size: 6232 bytes --]

// autogenerated by syzkaller (https://github.com/google/syzkaller)

#define _GNU_SOURCE 

#include <dirent.h>
#include <endian.h>
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <signal.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/prctl.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>

#include <linux/futex.h>

#ifndef __NR_close_range
#define __NR_close_range 436
#endif

static void sleep_ms(uint64_t ms)
{
	usleep(ms * 1000);
}

static uint64_t current_time_ms(void)
{
	struct timespec ts;
	if (clock_gettime(CLOCK_MONOTONIC, &ts))
	exit(1);
	return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
}

static void thread_start(void* (*fn)(void*), void* arg)
{
	pthread_t th;
	pthread_attr_t attr;
	pthread_attr_init(&attr);
	pthread_attr_setstacksize(&attr, 128 << 10);
	int i = 0;
	for (; i < 100; i++) {
		if (pthread_create(&th, &attr, fn, arg) == 0) {
			pthread_attr_destroy(&attr);
			return;
		}
		if (errno == EAGAIN) {
			usleep(50);
			continue;
		}
		break;
	}
	exit(1);
}

typedef struct {
	int state;
} event_t;

static void event_init(event_t* ev)
{
	ev->state = 0;
}

static void event_reset(event_t* ev)
{
	ev->state = 0;
}

static void event_set(event_t* ev)
{
	if (ev->state)
	exit(1);
	__atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
	syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000);
}

static void event_wait(event_t* ev)
{
	while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
		syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
}

static int event_isset(event_t* ev)
{
	return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
}

static int event_timedwait(event_t* ev, uint64_t timeout)
{
	uint64_t start = current_time_ms();
	uint64_t now = start;
	for (;;) {
		uint64_t remain = timeout - (now - start);
		struct timespec ts;
		ts.tv_sec = remain / 1000;
		ts.tv_nsec = (remain % 1000) * 1000 * 1000;
		syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
		if (__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
			return 1;
		now = current_time_ms();
		if (now - start > timeout)
			return 0;
	}
}

static bool write_file(const char* file, const char* what, ...)
{
	char buf[1024];
	va_list args;
	va_start(args, what);
	vsnprintf(buf, sizeof(buf), what, args);
	va_end(args);
	buf[sizeof(buf) - 1] = 0;
	int len = strlen(buf);
	int fd = open(file, O_WRONLY | O_CLOEXEC);
	if (fd == -1)
		return false;
	if (write(fd, buf, len) != len) {
		int err = errno;
		close(fd);
		errno = err;
		return false;
	}
	close(fd);
	return true;
}

static void kill_and_wait(int pid, int* status)
{
	kill(-pid, SIGKILL);
	kill(pid, SIGKILL);
	for (int i = 0; i < 100; i++) {
		if (waitpid(-1, status, WNOHANG | __WALL) == pid)
			return;
		usleep(1000);
	}
	DIR* dir = opendir("/sys/fs/fuse/connections");
	if (dir) {
		for (;;) {
			struct dirent* ent = readdir(dir);
			if (!ent)
				break;
			if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
				continue;
			char abort[300];
			snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort", ent->d_name);
			int fd = open(abort, O_WRONLY);
			if (fd == -1) {
				continue;
			}
			if (write(fd, abort, 1) < 0) {
			}
			close(fd);
		}
		closedir(dir);
	} else {
	}
	while (waitpid(-1, status, __WALL) != pid) {
	}
}

static void setup_test()
{
	prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
	setpgrp();
	write_file("/proc/self/oom_score_adj", "1000");
}

struct thread_t {
	int created, call;
	event_t ready, done;
};

static struct thread_t threads[16];
static void execute_call(int call);
static int running;

static void* thr(void* arg)
{
	struct thread_t* th = (struct thread_t*)arg;
	for (;;) {
		event_wait(&th->ready);
		event_reset(&th->ready);
		execute_call(th->call);
		__atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
		event_set(&th->done);
	}
	return 0;
}

static void execute_one(void)
{
	int i, call, thread;
	for (call = 0; call < 5; call++) {
		for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0])); thread++) {
			struct thread_t* th = &threads[thread];
			if (!th->created) {
				th->created = 1;
				event_init(&th->ready);
				event_init(&th->done);
				event_set(&th->done);
				thread_start(thr, th);
			}
			if (!event_isset(&th->done))
				continue;
			event_reset(&th->done);
			th->call = call;
			__atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
			event_set(&th->ready);
			if (call == 3)
				break;
			event_timedwait(&th->done, 50);
			break;
		}
	}
	for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
		sleep_ms(1);
}

static void execute_one(void);

#define WAIT_FLAGS __WALL

static void loop(void)
{
	int iter = 0;
	for (;; iter++) {
		int pid = fork();
		if (pid < 0)
	exit(1);
		if (pid == 0) {
			setup_test();
			execute_one();
			exit(0);
		}
		int status = 0;
		uint64_t start = current_time_ms();
		for (;;) {
			if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
				break;
			sleep_ms(1);
			if (current_time_ms() - start < 5000)
				continue;
			kill_and_wait(pid, &status);
			break;
		}
	}
}

uint64_t r[2] = {0xffffffffffffffff, 0x0};

void execute_call(int call)
{
		intptr_t res = 0;
	switch (call) {
	case 0:
		res = syscall(__NR_pipe2, 0x20000140ul, 0x80ul);
		if (res != -1)
r[0] = *(uint32_t*)0x20000140;
		break;
	case 1:
memcpy((void*)0x20000000, "big_key\000", 8);
memcpy((void*)0x20000040, "syz", 3);
*(uint8_t*)0x20000043 = 0x21;
*(uint8_t*)0x20000044 = 0;
memset((void*)0x20000080, 64, 1);
		res = syscall(__NR_add_key, 0x20000000ul, 0x20000040ul, 0x20000080ul, 1ul, 0xfffffffc);
		if (res != -1)
				r[1] = res;
		break;
	case 2:
		syscall(__NR_pipe2, 0ul, 0x80ul);
		break;
	case 3:
		syscall(__NR_keyctl, 0x20ul, r[1], r[0], 0ul, 0);
		break;
	case 4:
		syscall(__NR_close_range, r[0], -1, 0ul);
		break;
	}

}
int main(void)
{
		syscall(__NR_mmap, 0x1ffff000ul, 0x1000ul, 0ul, 0x32ul, -1, 0ul);
	syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 7ul, 0x32ul, -1, 0ul);
	syscall(__NR_mmap, 0x21000000ul, 0x1000ul, 0ul, 0x32ul, -1, 0ul);
			loop();
	return 0;
}

[-- Attachment #3: repro.syz --]
[-- Type: application/octet-stream, Size: 316 bytes --]

pipe2$watch_queue(&(0x7f0000000140)={<r0=>0xffffffffffffffff}, 0x80)
r1 = add_key(&(0x7f0000000000)='big_key\x00', &(0x7f0000000040)={'syz', 0x1}, &(0x7f0000000080)='@', 0x1, 0xfffffffffffffffc)
pipe2$watch_queue(0x0, 0x80)
keyctl$KEYCTL_WATCH_KEY(0x20, r1, r0, 0x0) (async)
close_range(r0, 0xffffffffffffffff, 0x0)

             reply	other threads:[~2022-07-27 21:29 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-07-27 21:28 Dipanjan Das [this message]
2022-07-28  6:52 ` KASAN: use-after-free Read in post_one_notification Greg KH
2022-07-28 14:10   ` Lukas Bulwahn
2022-07-28 14:35     ` Greg KH

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=CANX2M5bHye2ZEEhEV6PUj1kYL2KdWYeJtgXw8KZRzwrNpLYz+A@mail.gmail.com \
    --to=mail.dipanjan.das@gmail.com \
    --cc=dhowells@redhat.com \
    --cc=edumazet@google.com \
    --cc=fleischermarius@googlemail.com \
    --cc=fmdefrancesco@gmail.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=its.priyanka.bose@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=sashal@kernel.org \
    --cc=syzkaller@googlegroups.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.