You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
167 lines
3.2 KiB
167 lines
3.2 KiB
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
* Copyright (c) 2018 Michael Moese <mmoese@suse.com>
|
|
*/
|
|
/* Regression test for CVE-2017-17053, original reproducer can be found
|
|
* here:
|
|
* https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=ccd5b3235180eef3cfec337df1c8554ab151b5cc
|
|
*
|
|
* Be careful! This test may crash your kernel!
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include "tst_test.h"
|
|
|
|
#ifdef HAVE_ASM_LDT_H
|
|
#include <asm/ldt.h>
|
|
#include <pthread.h>
|
|
#include <signal.h>
|
|
#include <stdlib.h>
|
|
#include <sys/syscall.h>
|
|
#include <sys/wait.h>
|
|
#include <unistd.h>
|
|
#include <stdio.h>
|
|
|
|
#include "tst_taint.h"
|
|
#include "lapi/syscalls.h"
|
|
|
|
#define EXEC_USEC 5000000
|
|
|
|
/* this is basically identical to SAFE_PTHREAD_CREATE(), but is tolerating the
|
|
* call to fail whenn the error is EAGAIN or EWOULDBLOCK */
|
|
static void try_pthread_create(pthread_t *thread_id, const pthread_attr_t *attr,
|
|
void *(*thread_fn)(void *), void *arg)
|
|
{
|
|
int rval;
|
|
|
|
rval = pthread_create(thread_id, attr, thread_fn, arg);
|
|
|
|
if (rval && rval != EAGAIN && rval != EWOULDBLOCK)
|
|
tst_brk(TBROK, "pthread_create(%p,%p,%p,%p) failed: %s",
|
|
thread_id, attr, thread_fn, arg, tst_strerrno(rval));
|
|
}
|
|
|
|
/* this is basically identical to SAFE_FORK(), but is tolerating the
|
|
* call to fail whenn the error is EAGAIN or EWOULDBLOCK */
|
|
static int try_fork(void)
|
|
{
|
|
pid_t pid;
|
|
|
|
tst_flush();
|
|
|
|
pid = fork();
|
|
if (pid < 0 && errno != EAGAIN && errno == EWOULDBLOCK)
|
|
tst_brk(TBROK | TERRNO, "fork() failed");
|
|
|
|
return pid;
|
|
}
|
|
|
|
|
|
|
|
struct shm_data {
|
|
volatile sig_atomic_t do_exit;
|
|
volatile sig_atomic_t segfaulted;
|
|
};
|
|
static struct shm_data *shm;
|
|
|
|
static void handler(int sig)
|
|
{
|
|
(void)sig;
|
|
|
|
shm->segfaulted = 1;
|
|
shm->do_exit = 1;
|
|
}
|
|
|
|
static void install_sighandler(void)
|
|
{
|
|
struct sigaction sa;
|
|
|
|
sa.sa_flags = SA_SIGINFO;
|
|
sigemptyset(&sa.sa_mask);
|
|
sa.sa_handler = handler;
|
|
|
|
SAFE_SIGACTION(SIGSEGV, &sa, NULL);
|
|
}
|
|
|
|
static void setup(void)
|
|
{
|
|
tst_taint_init(TST_TAINT_W | TST_TAINT_D);
|
|
|
|
shm = SAFE_MMAP(NULL, sizeof(struct shm_data),
|
|
PROT_READ | PROT_WRITE,
|
|
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
|
|
}
|
|
|
|
static void cleanup(void)
|
|
{
|
|
SAFE_MUNMAP(shm, sizeof(struct shm_data));
|
|
}
|
|
|
|
static void *fork_thread(void *arg)
|
|
{
|
|
try_fork();
|
|
return arg;
|
|
}
|
|
|
|
void run_test(void)
|
|
{
|
|
struct user_desc desc = { .entry_number = 8191 };
|
|
|
|
install_sighandler();
|
|
syscall(__NR_modify_ldt, 1, &desc, sizeof(desc));
|
|
|
|
for (;;) {
|
|
if (shm->do_exit)
|
|
exit(0);
|
|
|
|
if (try_fork() == 0) {
|
|
pthread_t t;
|
|
|
|
srand(getpid());
|
|
try_pthread_create(&t, NULL, fork_thread, NULL);
|
|
usleep(rand() % 10000);
|
|
syscall(__NR_exit_group, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
void run(void)
|
|
{
|
|
int status;
|
|
pid_t pid;
|
|
|
|
shm->do_exit = 0;
|
|
shm->segfaulted = 0;
|
|
|
|
pid = SAFE_FORK();
|
|
if (pid == 0) {
|
|
run_test();
|
|
} else {
|
|
usleep(EXEC_USEC);
|
|
shm->do_exit = 1;
|
|
}
|
|
|
|
SAFE_WAIT(&status);
|
|
|
|
if (WIFEXITED(status) && shm->segfaulted == 0 && tst_taint_check() == 0)
|
|
tst_res(TPASS, "kernel survived");
|
|
else
|
|
tst_res(TFAIL, "kernel is vulnerable");
|
|
}
|
|
|
|
static struct tst_test test = {
|
|
.forks_child = 1,
|
|
.setup = setup,
|
|
.cleanup = cleanup,
|
|
.test_all = run,
|
|
.tags = (const struct tst_tag[]) {
|
|
{"linux-git", "ccd5b3235180"},
|
|
{"CVE", "2017-17053"},
|
|
{}
|
|
}
|
|
};
|
|
|
|
#else
|
|
TST_TEST_TCONF("no asm/ldt.h header (only for i386 or x86_64)");
|
|
#endif
|