lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Thu, 5 Apr 2018 19:31:34 +0900
From:   Tetsuo Handa <penguin-kernel@...ove.SAKURA.ne.jp>
To:     gregkh@...uxfoundation.org, jslaby@...e.com
Cc:     syzbot <syzbot+3aa9784721dfb90e984d@...kaller.appspotmail.com>,
        linux-kernel@...r.kernel.org, syzkaller-bugs@...glegroups.com
Subject: Re: KASAN: user-memory-access Write in n_tty_set_termios

Hello.

I manually simplified the reproducer. Since the bug is timing dependent,
this reproducer might fail to reproducer the bug. Anyway, I guess that
there is a race condition between

	vfree(ldata);
	tty->disc_data = NULL;

at n_tty_close() by something (ioctl(TIOCVHANGUP) ?) and

	struct n_tty_data *ldata = tty->disc_data;

	if (!old || (old->c_lflag ^ tty->termios.c_lflag) & (ICANON | EXTPROC)) {
		bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE);

at n_tty_set_termios() by ioctl(TCSETS), for the report says that ldata == NULL
("Write of size 512 at addr 0000000000001060").

----------------------------------------
#include <fcntl.h>
#include <linux/futex.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <termios.h>
#define TIOCGPTPEER     _IO('T', 0x41) 

static const int zero = 0;
static int master_fd = EOF;
static int slave_fd = EOF;
static void execute_call(int call)
{
	struct termios term;
	char buf[128];
	int ptyno = 0;
	switch (call) {
	case 0:
		master_fd = open("/dev/ptmx", O_RDONLY);
		ioctl(master_fd, TIOCSPTLCK, &zero);
		if (ioctl(master_fd, TIOCGPTN, &ptyno))
			break;
		sprintf(buf, "/dev/pts/%d", ptyno);
		slave_fd = open(buf, O_RDONLY, 0);
		usleep(5 * 1000);
		ioctl(slave_fd, TIOCVHANGUP, 0);
		break;
	case 5:
		memset(&term, 0, sizeof(term));
		ioctl(master_fd, TCSETS, &term);
		break;
	case 6:
		ioctl(master_fd, TIOCGPTPEER, 0);
		break;
	}
}

struct thread_t {
	int created, running, call;
	pthread_t th;
};

static struct thread_t threads[16];
static int running;
static int collide;

static void* thr(void* arg)
{
	struct thread_t* th = (struct thread_t*)arg;
	for (;;) {
		while (!__atomic_load_n(&th->running, __ATOMIC_ACQUIRE))
			syscall(SYS_futex, &th->running, FUTEX_WAIT, 0, 0);
		execute_call(th->call);
		__atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
		__atomic_store_n(&th->running, 0, __ATOMIC_RELEASE);
		syscall(SYS_futex, &th->running, FUTEX_WAKE);
	}
	return 0;
}

static void execute(int num_calls)
{
	int call, thread;
	running = 0;
	for (call = 0; call < num_calls; call++) {
		for (thread = 0; thread < sizeof(threads) / sizeof(threads[0]); thread++) {
			struct thread_t* th = &threads[thread];
			if (!th->created) {
				th->created = 1;
				pthread_attr_t attr;
				pthread_attr_init(&attr);
				pthread_attr_setstacksize(&attr, 128 << 10);
				pthread_create(&th->th, &attr, thr, th);
			}
			if (!__atomic_load_n(&th->running, __ATOMIC_ACQUIRE)) {
				th->call = call;
				__atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
				__atomic_store_n(&th->running, 1, __ATOMIC_RELEASE);
				syscall(SYS_futex, &th->running, FUTEX_WAKE);
				if (collide && call % 2)
					break;
				struct timespec ts;
				ts.tv_sec = 0;
				ts.tv_nsec = 20 * 1000 * 1000;
				syscall(SYS_futex, &th->running, FUTEX_WAIT, 1, &ts);
				if (running)
					usleep((call == num_calls - 1) ? 10000 : 1000);
				break;
			}
		}
	}
}

int main(int argc, char *argv[])
{
	while (1) {
		execute(7);
		collide = 1;
		execute(7);
	}
	return 0;
}
----------------------------------------

Powered by blists - more mailing lists