Raporlar, Analiz, Konsept - Syzkaller

Merhabalar, son dönemlerde syzkaller ile fuzzing muhabbetlerinden mütevellit şuraya bir küçük fuzz çıktısı atma ihtiyacı duydum. Hem bu rapor üzere konuşmak, hem beyin fırtınasıyla exploit yöntemleri aramanın farklı çalışmalara vesile olacağı kanaatindeyim.

Syzkaller hit 'KASAN: use-after-free Read in mpi_free' bug.

RDX: 0000000020a53ffb RSI: 0000000020000100 RDI: 0000000000000017
RBP: 0000000000000082 R08: 0000000020c61fc8 R09: 00007ffcbe003231
R10: 0000000000000005 R11: 0000000000000246 R12: 0000000000402070
R13: 0000000000402100 R14: 0000000000000000 R15: 0000000000000000
==================================================================
BUG: KASAN: use-after-free in mpi_free+0x117/0x150 lib/mpi/mpiutil.c:114
Read of size 4 at addr ffff88003e59b410 by task syzkaller123263/4094

CPU: 0 PID: 4094 Comm: syzkaller123263 Not tainted 4.13.0 #2
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.11.1-0-g0551a4be2c-prebuilt.qemu-project.org 04/01/2014
Call Trace:
 __dump_stack lib/dump_stack.c:16 [inline]
 dump_stack+0x194/0x24d lib/dump_stack.c:52
 print_address_description+0x73/0x250 mm/kasan/report.c:252
 kasan_report_error mm/kasan/report.c:351 [inline]
 kasan_report+0x24e/0x340 mm/kasan/report.c:409
 __asan_report_load4_noabort+0x14/0x20 mm/kasan/report.c:429
 mpi_free+0x117/0x150 lib/mpi/mpiutil.c:114
 dh_clear_params crypto/dh.c:26 [inline]
 dh_free_ctx crypto/dh.c:34 [inline]
 dh_exit_tfm+0x3d/0x140 crypto/dh.c:161
 crypto_kpp_exit_tfm+0x52/0x70 crypto/kpp.c:63
 crypto_exit_ops crypto/api.c:314 [inline]
 crypto_destroy_tfm+0xb9/0x2e0 crypto/api.c:578
 crypto_free_kpp include/crypto/kpp.h:155 [inline]
 __keyctl_dh_compute+0x1015/0x1990 security/keys/dh.c:412
 keyctl_dh_compute+0xac/0xf3 security/keys/dh.c:434
 SYSC_keyctl security/keys/keyctl.c:1743 [inline]
 SyS_keyctl+0x72/0x2c0 security/keys/keyctl.c:1639
 entry_SYSCALL_64_fastpath+0x23/0xc2
RIP: 0033:0x440789
RSP: 002b:00007ffcbe6fea58 EFLAGS: 00000246 ORIG_RAX: 00000000000000fa
RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 0000000000440789
RDX: 0000000020a53ffb RSI: 0000000020000100 RDI: 0000000000000017
RBP: 0000000000000082 R08: 0000000020c61fc8 R09: 00007ffcbe003231
R10: 0000000000000005 R11: 0000000000000246 R12: 0000000000402070
R13: 0000000000402100 R14: 0000000000000000 R15: 0000000000000000

Allocated by task 4094:
 save_stack_trace+0x16/0x20 arch/x86/kernel/stacktrace.c:59
 save_stack+0x43/0xd0 mm/kasan/kasan.c:447
 set_track mm/kasan/kasan.c:459 [inline]
 kasan_kmalloc+0xad/0xe0 mm/kasan/kasan.c:551
 kmem_cache_alloc_trace+0x12f/0x740 mm/slab.c:3627
 kmalloc include/linux/slab.h:493 [inline]
 mpi_alloc+0x4b/0x230 lib/mpi/mpiutil.c:34
 mpi_read_raw_data+0x1e5/0x440 lib/mpi/mpicoder.c:57
 dh_set_params crypto/dh.c:69 [inline]
 dh_set_secret+0x257/0x600 crypto/dh.c:94
 crypto_kpp_set_secret include/crypto/kpp.h:281 [inline]
 __keyctl_dh_compute+0x9b6/0x1990 security/keys/dh.c:333
 keyctl_dh_compute+0xac/0xf3 security/keys/dh.c:434
 SYSC_keyctl security/keys/keyctl.c:1743 [inline]
 SyS_keyctl+0x72/0x2c0 security/keys/keyctl.c:1639
 entry_SYSCALL_64_fastpath+0x23/0xc2

Freed by task 4094:
 save_stack_trace+0x16/0x20 arch/x86/kernel/stacktrace.c:59
 save_stack+0x43/0xd0 mm/kasan/kasan.c:447
 set_track mm/kasan/kasan.c:459 [inline]
 kasan_slab_free+0x71/0xc0 mm/kasan/kasan.c:524
 __cache_free mm/slab.c:3503 [inline]
 kfree+0xd6/0x260 mm/slab.c:3820
 mpi_free+0xcb/0x150 lib/mpi/mpiutil.c:121
 dh_set_params crypto/dh.c:75 [inline]
 dh_set_secret+0x3e5/0x600 crypto/dh.c:94
 crypto_kpp_set_secret include/crypto/kpp.h:281 [inline]
 __keyctl_dh_compute+0x9b6/0x1990 security/keys/dh.c:333
 keyctl_dh_compute+0xac/0xf3 security/keys/dh.c:434
 SYSC_keyctl security/keys/keyctl.c:1743 [inline]
 SyS_keyctl+0x72/0x2c0 security/keys/keyctl.c:1639
 entry_SYSCALL_64_fastpath+0x23/0xc2

The buggy address belongs to the object at ffff88003e59b400
 which belongs to the cache kmalloc-32 of size 32
The buggy address is located 16 bytes inside of
 32-byte region [ffff88003e59b400, ffff88003e59b420)
The buggy address belongs to the page:
page:ffffea0000f966c0 count:1 mapcount:0 mapping:ffff88003e59b000 index:0xffff88003e59bfc1
flags: 0x1fffc0000000100(slab)
raw: 01fffc0000000100 ffff88003e59b000 ffff88003e59bfc1 000000010000003c
raw: ffffea0000f314a0 ffffea0000f47160 ffff88003e4001c0 0000000000000000
page dumped because: kasan: bad access detected

Memory state around the buggy address:
 ffff88003e59b300: fb fb fb fb fc fc fc fc fb fb fb fb fc fc fc fc
 ffff88003e59b380: fb fb fb fb fc fc fc fc fb fb fb fb fc fc fc fc
>ffff88003e59b400: fb fb fb fb fc fc fc fc fb fb fb fb fc fc fc fc
                         ^
 ffff88003e59b480: 00 02 fc fc fc fc fc fc fb fb fb fb fc fc fc fc
 ffff88003e59b500: fb fb fb fb fc fc fc fc fb fb fb fb fc fc fc fc

//////////////

C reproducer:
// autogenerated by syzkaller (http://github.com/google/syzkaller)

#define _GNU_SOURCE 
#include <endian.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <sys/stat.h>

__attribute__((noreturn)) static void doexit(int status)
{
	volatile unsigned i;
	syscall(__NR_exit_group, status);
	for (i = 0;; i++) {
	}
}
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>

const int kFailStatus = 67;
const int kRetryStatus = 69;

  static void exitf(const char* msg, ...)
{
	int e = errno;
	va_list args;
	va_start(args, msg);
	vfprintf(stderr, msg, args);
	va_end(args);
	fprintf(stderr, " (errno %d)\n", e);
	doexit(kRetryStatus);
}

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 int inject_fault(int nth)
{
	int fd;
	char buf[16];

	fd = open("/proc/thread-self/fail-nth", O_RDWR);
	if (fd == -1)
		exitf("failed to open /proc/thread-self/fail-nth");
	sprintf(buf, "%d", nth + 1);
	if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
		exitf("failed to write /proc/thread-self/fail-nth");
	return fd;
}

uint64_t r[6] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
void loop()
{
	long res = 0;
memcpy((void*)0x20000340, "keyring", 8);
*(uint8_t*)0x20000380 = 0x73;
*(uint8_t*)0x20000381 = 0x79;
*(uint8_t*)0x20000382 = 0x7a;
*(uint8_t*)0x20000383 = 0;
*(uint8_t*)0x20000384 = 0;
	res = syscall(__NR_add_key, 0x20000340, 0x20000380, 0, 0, 0xfffffffb);
	if (res != -1)
		r[0] = res;
memcpy((void*)0x200002c0, "keyring", 8);
*(uint8_t*)0x20000300 = 0x73;
*(uint8_t*)0x20000301 = 0x79;
*(uint8_t*)0x20000302 = 0x7a;
*(uint8_t*)0x20000303 = 0;
*(uint8_t*)0x20000304 = 0;
	res = syscall(__NR_add_key, 0x200002c0, 0x20000300, 0, 0, r[0]);
	if (res != -1)
		r[1] = res;
memcpy((void*)0x20000400, "keyring", 8);
*(uint8_t*)0x20000000 = 0x73;
*(uint8_t*)0x20000001 = 0x79;
*(uint8_t*)0x20000002 = 0x7a;
*(uint8_t*)0x20000003 = 0;
*(uint8_t*)0x20000004 = 0;
	res = syscall(__NR_add_key, 0x20000400, 0x20000000, 0, 0, r[1]);
	if (res != -1)
		r[2] = res;
memcpy((void*)0x200000c0, "keyring", 8);
*(uint8_t*)0x20000180 = 0x73;
*(uint8_t*)0x20000181 = 0x79;
*(uint8_t*)0x20000182 = 0x7a;
*(uint8_t*)0x20000183 = 0;
*(uint8_t*)0x20000184 = 0;
	res = syscall(__NR_add_key, 0x200000c0, 0x20000180, 0, 0, r[2]);
	if (res != -1)
		r[3] = res;
memcpy((void*)0x200001c0, "user", 5);
*(uint8_t*)0x20000200 = 0x73;
*(uint8_t*)0x20000201 = 0x79;
*(uint8_t*)0x20000202 = 0x7a;
*(uint8_t*)0x20000203 = 0;
*(uint8_t*)0x20000204 = 0;
memcpy((void*)0x20000440, "\x01", 1);
	res = syscall(__NR_add_key, 0x200001c0, 0x20000200, 0x20000440, 1, r[3]);
	if (res != -1)
		r[4] = res;
memcpy((void*)0x20002cc0, "user", 5);
*(uint8_t*)0x20000040 = 0x73;
*(uint8_t*)0x20000041 = 0x79;
*(uint8_t*)0x20000042 = 0x7a;
*(uint8_t*)0x20000043 = 0;
*(uint8_t*)0x20000044 = 0;
	res = syscall(__NR_add_key, 0x20002cc0, 0x20000040, 0x20000280, 0x182, r[1]);
	if (res != -1)
		r[5] = res;
*(uint32_t*)0x20000100 = r[4];
*(uint32_t*)0x20000104 = r[5];
*(uint32_t*)0x20000108 = r[5];
*(uint64_t*)0x20c61fc8 = 0x20a3dffa;
memcpy((void*)0x20a3dffa, "\x70\x6f\x6c\x79\x31\x33\x30\x35\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 64);
*(uint64_t*)0x20c61fd0 = 0;
*(uint32_t*)0x20c61fd8 = 0;
*(uint32_t*)0x20c61fdc = 0;
*(uint32_t*)0x20c61fe0 = 0;
*(uint32_t*)0x20c61fe4 = 0;
*(uint32_t*)0x20c61fe8 = 0;
*(uint32_t*)0x20c61fec = 0;
*(uint32_t*)0x20c61ff0 = 0;
*(uint32_t*)0x20c61ff4 = 0;
*(uint32_t*)0x20c61ff8 = 0;
	write_file("/sys/kernel/debug/failslab/ignore-gfp-wait", "N");
	write_file("/sys/kernel/debug/fail_futex/ignore-private", "N");
	inject_fault(11);
	syscall(__NR_keyctl, 0x17, 0x20000100, 0x20a53ffb, 5, 0x20c61fc8);
}

int main()
{
	syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
	loop();
	return 0;
}
6 Likes