All of lore.kernel.org
 help / color / mirror / Atom feed
* A null-ptr-deref bug was triggered when continuously remont jfs image to write a log to record
@ 2022-03-07  8:01 butt3rflyh4ck
  0 siblings, 0 replies; only message in thread
From: butt3rflyh4ck @ 2022-03-07  8:01 UTC (permalink / raw)
  To: shaggy; +Cc: jfs-discussion, LKML

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

Hi, there is a null-ptr-deref bug by kernel fuzz. It was triggered
when continuously remont jfs image to write a log to record
I can reproduce it on the latest kernel.

### Crash log
[   30.752504][ T7617] BUG: kernel NULL pointer dereference, address:
00000000000005a8
[   30.753179][ T7617] #PF: supervisor read access in kernel mode
[   30.753670][ T7617] #PF: error_code(0x0000) - not-present page
[   30.754160][ T7617] PGD 106cb067 P4D 106cb067 PUD f7e7067 PMD 0
[   30.754681][ T7617] Oops: 0000 [#1] PREEMPT SMP
[   30.755073][ T7617] CPU: 1 PID: 7617 Comm: bio_associate_b Tainted:
G        W         5.17.0-rc6+ #47
[   30.755880][ T7617] Hardware name: QEMU Standard PC (i440FX + PIIX,
1996), BIOS 1.13.0-1ubuntu1 04/01/2014
[   30.756688][ T7617] RIP: 0010:bio_associate_blkg_from_css+0x1f1/0x730
[   30.757238][ T7617] Code: c6 50 59 e4 81 48 c7 c7 c0 cc 22 85 e8 d8
8d 41 ff 49 89 5c 24 48 48 83 c4 18 5b 5d 41 5c 41 5d 41 5e 41 5f c3
49 8b 44 24 08 <48> 8b 80 a5
[   30.758904][ T7617] RSP: 0018:ffffc900022f3b70 EFLAGS: 00010246
[   30.759429][ T7617] RAX: 0000000000000000 RBX: 0000000000000000
RCX: 0000000000000001
[   30.760127][ T7617] RDX: 0000000000000000 RSI: ffffffff882f6080
RDI: ffff888046ee3e00
[   30.760739][ T7617] RBP: ffffffff882f6080 R08: 0000000000000000
R09: 0000000000020027
[   30.761297][ T7617] R10: 0000000000000001 R11: 0000000000000000
R12: ffff888046ee3e00
[   30.761854][ T7617] R13: ffff8880482f8400 R14: ffff8880482f85d0
R15: ffff8880482f85d0
[   30.762412][ T7617] FS:  0000000000e05880(0000)
GS:ffff88807ec00000(0000) knlGS:0000000000000000
[   30.763118][ T7617] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   30.763680][ T7617] CR2: 00007fcd480390e8 CR3: 000000000fdf7000
CR4: 00000000000006e0
[   30.764390][ T7617] Call Trace:
[   30.764673][ T7617]  <TASK>
[   30.764929][ T7617]  bio_associate_blkg+0x58/0x190
[   30.765331][ T7617]  lbmStartIO+0x7c/0xf0
[   30.765684][ T7617]  ? lockdep_hardirqs_on+0x79/0x100
[   30.766138][ T7617]  lbmWrite+0xed/0x150
[   30.766492][ T7617]  lmNextPage+0x87/0x150
[   30.766861][ T7617]  lmWriteRecord+0x35d/0x460
[   30.767270][ T7617]  lmLog+0xc2/0x290
[   30.767597][ T7617]  ? __sync_dirty_buffer+0x85/0x160
[   30.768082][ T7617]  jfs_mount_rw+0x15e/0x190
[   30.768465][ T7617]  jfs_fill_super+0x2d3/0x350
[   30.768857][ T7617]  mount_bdev+0x18b/0x1c0
[   30.769217][ T7617]  ? jfs_remount+0x1d0/0x1d0
[   30.769605][ T7617]  legacy_get_tree+0x28/0x50
[   30.769991][ T7617]  vfs_get_tree+0x1d/0xb0
[   30.770362][ T7617]  path_mount+0x42b/0xb10
[   30.770731][ T7617]  do_mount+0x70/0x90
[   30.771056][ T7617]  __x64_sys_mount+0x89/0xc0
[   30.771450][ T7617]  do_syscall_64+0x35/0xb0
[   30.771836][ T7617]  entry_SYSCALL_64_after_hwframe+0x44/0xae
[   30.772327][ T7617] RIP: 0033:0x4521de
[   30.772662][ T7617] Code: 83 c4 08 5b 5d c3 66 0f 1f 44 00 00 c3 66
2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 f3 0f 1e fa 49 89 ca b8 a5
00 00 00 0f 05 <48> 3d 01 f8
[   30.774275][ T7617] RSP: 002b:00007ffeae064a48 EFLAGS: 00000282
ORIG_RAX: 00000000000000a5
[   30.774988][ T7617] RAX: ffffffffffffffda RBX: 0000000000400530
RCX: 00000000004521de
[   30.775692][ T7617] RDX: 0000000020000000 RSI: 0000000020000100
RDI: 00007ffeae064ac0
[   30.776382][ T7617] RBP: 00007ffeae064c10 R08: 00007ffeae064b00
R09: 00007ffeae064a84
[   30.777054][ T7617] R10: 0000000000000000 R11: 0000000000000282
R12: 0000000000404050
[   30.777617][ T7617] R13: 0000000000000000 R14: 00000000004c8018
R15: 0000000000000000

the attachment is reproduce.

Regards,
 butt3rflyh4ck.








--
Active Defense Lab of Venustech

[-- Attachment #2: repro.cprog --]
[-- Type: application/octet-stream, Size: 11619 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 <signal.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mount.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/loop.h>

#ifndef __NR_memfd_create
#define __NR_memfd_create 319
#endif

static unsigned long long procid;

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 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;
}

struct fs_image_segment {
	void* data;
	uintptr_t size;
	uintptr_t offset;
};

#define IMAGE_MAX_SEGMENTS 4096
#define IMAGE_MAX_SIZE (129 << 20)

static unsigned long fs_image_segment_check(unsigned long size, unsigned long nsegs, struct fs_image_segment* segs)
{
	if (nsegs > IMAGE_MAX_SEGMENTS)
		nsegs = IMAGE_MAX_SEGMENTS;
	for (size_t i = 0; i < nsegs; i++) {
		if (segs[i].size > IMAGE_MAX_SIZE)
			segs[i].size = IMAGE_MAX_SIZE;
		segs[i].offset %= IMAGE_MAX_SIZE;
		if (segs[i].offset > IMAGE_MAX_SIZE - segs[i].size)
			segs[i].offset = IMAGE_MAX_SIZE - segs[i].size;
		if (size < segs[i].offset + segs[i].offset)
			size = segs[i].offset + segs[i].offset;
	}
	if (size > IMAGE_MAX_SIZE)
		size = IMAGE_MAX_SIZE;
	return size;
}
static int setup_loop_device(long unsigned size, long unsigned nsegs, struct fs_image_segment* segs, const char* loopname, int* memfd_p, int* loopfd_p)
{
	int err = 0, loopfd = -1;
	size = fs_image_segment_check(size, nsegs, segs);
	int memfd = syscall(__NR_memfd_create, "syzkaller", 0);
	if (memfd == -1) {
		err = errno;
		goto error;
	}
	if (ftruncate(memfd, size)) {
		err = errno;
		goto error_close_memfd;
	}
	for (size_t i = 0; i < nsegs; i++) {
		if (pwrite(memfd, segs[i].data, segs[i].size, segs[i].offset) < 0) {
		}
	}
	loopfd = open(loopname, O_RDWR);
	if (loopfd == -1) {
		err = errno;
		goto error_close_memfd;
	}
	if (ioctl(loopfd, LOOP_SET_FD, memfd)) {
		if (errno != EBUSY) {
			err = errno;
			goto error_close_loop;
		}
		ioctl(loopfd, LOOP_CLR_FD, 0);
		usleep(1000);
		if (ioctl(loopfd, LOOP_SET_FD, memfd)) {
			err = errno;
			goto error_close_loop;
		}
	}
	*memfd_p = memfd;
	*loopfd_p = loopfd;
	return 0;

error_close_loop:
	close(loopfd);
error_close_memfd:
	close(memfd);
error:
	errno = err;
	return -1;
}

static long syz_mount_image(volatile long fsarg, volatile long dir, volatile unsigned long size, volatile unsigned long nsegs, volatile long segments, volatile long flags, volatile long optsarg)
{
	struct fs_image_segment* segs = (struct fs_image_segment*)segments;
	int res = -1, err = 0, loopfd = -1, memfd = -1, need_loop_device = !!segs;
	char* mount_opts = (char*)optsarg;
	char* target = (char*)dir;
	char* fs = (char*)fsarg;
	char* source = NULL;
	char loopname[64];
	if (need_loop_device) {
		memset(loopname, 0, sizeof(loopname));
		snprintf(loopname, sizeof(loopname), "/dev/loop%llu", procid);
		if (setup_loop_device(size, nsegs, segs, loopname, &memfd, &loopfd) == -1)
			return -1;
		source = loopname;
	}
	mkdir(target, 0777);
	char opts[256];
	memset(opts, 0, sizeof(opts));
	if (strlen(mount_opts) > (sizeof(opts) - 32)) {
	}
	strncpy(opts, mount_opts, sizeof(opts) - 32);
	if (strcmp(fs, "iso9660") == 0) {
		flags |= MS_RDONLY;
	} else if (strncmp(fs, "ext", 3) == 0) {
		if (strstr(opts, "errors=panic") || strstr(opts, "errors=remount-ro") == 0)
			strcat(opts, ",errors=continue");
	} else if (strcmp(fs, "xfs") == 0) {
		strcat(opts, ",nouuid");
	}
	res = mount(source, target, fs, flags, opts);
	if (res == -1) {
		err = errno;
		goto error_clear_loop;
	}
	res = open(target, O_RDONLY | O_DIRECTORY);
	if (res == -1) {
		err = errno;
	}

error_clear_loop:
	if (need_loop_device) {
		ioctl(loopfd, LOOP_CLR_FD, 0);
		close(loopfd);
		close(memfd);
	}
	errno = err;
	return res;
}

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 reset_loop()
{
	char buf[64];
	snprintf(buf, sizeof(buf), "/dev/loop%llu", procid);
	int loopfd = open(buf, O_RDWR);
	if (loopfd != -1) {
		ioctl(loopfd, LOOP_CLR_FD, 0);
		close(loopfd);
	}
}

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

static void execute_one(void);

#define WAIT_FLAGS __WALL

static void loop(void)
{
	int iter = 0;
	for (;; iter++) {
		reset_loop();
		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;
		}
	}
}

void execute_one(void)
{
memcpy((void*)0x20000000, "jfs\000", 4);
memcpy((void*)0x20000100, "./file0\000", 8);
*(uint64_t*)0x20000200 = 0x20010000;
memcpy((void*)0x20010000, "\x4a\x46\x53\x31\x01\x00\x00\x00\x60\x76\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x0c\x00\x03\x00\x00\x02\x00\x00\x09\x00\x00\x00\x00\x20\x00\x00\x00\x09\x20\x10\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x18\x00\x00\x00\x02\x00\x00\x00\x16\x00\x00\x00\x32\x07\x00\x00\x01\x00\x00\x00\x00\x01\x00\x00\x00\x0f\x00\x00\x34\x00\x00\x00\xcc\x0e\x00\x00\x10\xc4\x64\x5f\x00\x00\x00\x00\x32\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\xa1\xbb\x9c\xe3\x52\xe0\x4a\xdf\xb9\xb5\x9a\xff\x47\xa5\x59\xea\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x50\xf4\x42\x56\xfd\x7f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 192);
*(uint64_t*)0x20000208 = 0xc0;
*(uint64_t*)0x20000210 = 0x8000;
*(uint64_t*)0x20000218 = 0;
*(uint64_t*)0x20000220 = 0;
*(uint64_t*)0x20000228 = 0x9000;
*(uint64_t*)0x20000230 = 0;
*(uint64_t*)0x20000238 = 0;
*(uint64_t*)0x20000240 = 0x9800;
*(uint64_t*)0x20000248 = 0;
*(uint64_t*)0x20000250 = 0;
*(uint64_t*)0x20000258 = 0xa800;
*(uint64_t*)0x20000260 = 0;
*(uint64_t*)0x20000268 = 0;
*(uint64_t*)0x20000270 = 0xaa00;
*(uint64_t*)0x20000278 = 0;
*(uint64_t*)0x20000280 = 0;
*(uint64_t*)0x20000288 = 0xac00;
*(uint64_t*)0x20000290 = 0;
*(uint64_t*)0x20000298 = 0;
*(uint64_t*)0x200002a0 = 0xb020;
*(uint64_t*)0x200002a8 = 0x20010f00;
memcpy((void*)0x20010f00, "\x10\xc4\x64\x5f\x01\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x0b\x00\x00\x00\x00\x20\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x01\x00\x10\xc4\x64\x5f\x00\x00\x00\x00\x10\xc4\x64\x5f\x00\x00\x00\x00\x10\xc4\x64\x5f\x00\x00\x00\x00\x10\xc4\x64\x5f\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\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 160);
*(uint64_t*)0x200002b0 = 0xa0;
*(uint64_t*)0x200002b8 = 0xb200;
*(uint64_t*)0x200002c0 = 0x20011000;
memcpy((void*)0x20011000, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x83\x00\x03\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 60);
*(uint64_t*)0x200002c8 = 0x3c;
*(uint64_t*)0x200002d0 = 0xb2e0;
*(uint64_t*)0x200002d8 = 0x20011100;
memcpy((void*)0x20011100, "\x10\xc4\x64\x5f\x01\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x0b\x00\x00\x00\x00\x60\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x01\x00\x10\xc4\x64\x5f\x00\x00\x00\x00\x10\xc4\x64\x5f\x00\x00\x00\x00\x10\xc4\x64\x5f\x00\x00\x00\x00\x10\xc4\x64\x5f\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\x02\x00\x00\x00\x00\x00\x00\x00", 128);
*(uint64_t*)0x200002e0 = 0x80;
*(uint64_t*)0x200002e8 = 0xb400;
*(uint64_t*)0x200002f0 = 0x20011200;
memcpy((void*)0x20011200, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x83\x00\x03\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x10", 45);
*(uint64_t*)0x200002f8 = 0x2d;
*(uint64_t*)0x20000300 = 0xb4e0;
*(uint64_t*)0x20000308 = 0;
*(uint64_t*)0x20000310 = 0;
*(uint64_t*)0x20000318 = 0;
*(uint64_t*)0x20000320 = 0x20011700;
memcpy((void*)0x20011700, "\x10\xc4\x64\x5f\x01\x00\x00\x00\x10\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x0b\x00\x00\x00\x00\x20", 26);
*(uint64_t*)0x20000328 = 0x1a;
*(uint64_t*)0x20000330 = 0xd000;
*(uint64_t*)0x20000338 = 0x20013900;
memcpy((void*)0x20013900, "\x10\xc4\x64\x5f\x01\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x18\x00\x00\x00\x00\x20", 26);
*(uint64_t*)0x20000340 = 0x1a;
*(uint64_t*)0x20000348 = 0x18200;
memcpy((void*)0x20000900, "nointegrity", 11);
*(uint8_t*)0x2000090b = 0x2c;
memcpy((void*)0x2000090c, "gid", 3);
*(uint8_t*)0x2000090f = 0x3d;
sprintf((char*)0x20000910, "0x%016llx", (long long)0);
*(uint8_t*)0x20000922 = 0x2c;
memcpy((void*)0x20000923, "noquota", 7);
*(uint8_t*)0x2000092a = 0x2c;
memcpy((void*)0x2000092b, "uid", 3);
*(uint8_t*)0x2000092e = 0x3d;
sprintf((char*)0x2000092f, "0x%016llx", (long long)0);
*(uint8_t*)0x20000941 = 0x2c;
memcpy((void*)0x20000942, "quota", 5);
*(uint8_t*)0x20000947 = 0x2c;
memcpy((void*)0x20000948, "errors=continue", 15);
*(uint8_t*)0x20000957 = 0x2c;
memcpy((void*)0x20000958, "iocharset", 9);
*(uint8_t*)0x20000961 = 0x3d;
memcpy((void*)0x20000962, "none", 4);
*(uint8_t*)0x20000966 = 0x2c;
memcpy((void*)0x20000967, "errors=remount-ro", 17);
*(uint8_t*)0x20000978 = 0x2c;
*(uint8_t*)0x20000979 = 0;
syz_mount_image(0x20000000, 0x20000100, 0, 0xe, 0x20000200, 0, 0x20000900);

}
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;
}

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-03-07  8:01 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-03-07  8:01 A null-ptr-deref bug was triggered when continuously remont jfs image to write a log to record butt3rflyh4ck

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.