Messages in this thread |  | | Subject | Re: KASAN: user-memory-access Write in n_tty_set_termios | From | Tetsuo Handa <> | Date | Thu, 5 Apr 2018 19:31:34 +0900 |
| |
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; } ----------------------------------------
|  |