| /* |
| * Copyright (c) 2018 Michael Moese <mmoese@suse.com> |
| * |
| * This program is free software: you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation, either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| */ |
| /* |
| * Test for CVE-2017-17052, original reproducer taken from kernel commit: |
| * 2b7e8665b4ff51c034c55df3cff76518d1a9ee3a |
| * |
| * CAUTION!! |
| * This test will crash unpatched kernels! |
| * Use at your own risk! |
| * |
| */ |
| |
| #include <unistd.h> |
| #include <pthread.h> |
| #include <sys/wait.h> |
| #include <sys/syscall.h> |
| #include <sys/types.h> |
| #include <stdlib.h> |
| |
| #include "tst_test.h" |
| #include "tst_safe_pthread.h" |
| #include "lapi/syscalls.h" |
| |
| #define RUNS 4 |
| #define EXEC_USEC 400000 |
| |
| static int *do_exit; |
| |
| static void setup(void) |
| { |
| do_exit = SAFE_MMAP(NULL, sizeof(*do_exit), PROT_READ|PROT_WRITE, |
| MAP_SHARED | MAP_ANONYMOUS, -1, 0); |
| |
| *do_exit = 0; |
| } |
| |
| static void cleanup(void) |
| { |
| SAFE_MUNMAP(do_exit, sizeof(*do_exit)); |
| } |
| |
| static void *mmap_thread(void *arg) |
| { |
| for (;;) { |
| SAFE_MMAP(NULL, 0x1000000, PROT_READ, |
| MAP_POPULATE|MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); |
| if (*do_exit) |
| exit(0); |
| } |
| |
| return arg; |
| } |
| |
| static void *fork_thread(void *arg) |
| { |
| if (*do_exit) |
| exit(0); |
| |
| usleep(rand() % 10000); |
| SAFE_FORK(); |
| |
| return arg; |
| } |
| |
| static void do_test_fork(void) |
| { |
| int status; |
| |
| SAFE_FORK(); |
| SAFE_FORK(); |
| SAFE_FORK(); |
| |
| for(;;) { |
| if (SAFE_FORK() == 0) { |
| pthread_t t; |
| |
| SAFE_PTHREAD_CREATE(&t, NULL, mmap_thread, NULL); |
| SAFE_PTHREAD_CREATE(&t, NULL, fork_thread, NULL); |
| usleep(rand() % 10000); |
| syscall(__NR_exit_group, 0); |
| } |
| SAFE_WAIT(&status); |
| if (*do_exit) |
| exit(0); |
| } |
| } |
| |
| static void run(void) |
| { |
| pid_t pid; |
| volatile int run = 0; |
| |
| while (run < RUNS) { |
| pid = SAFE_FORK(); |
| |
| if (pid == 0) { |
| do_test_fork(); |
| } else { |
| usleep(EXEC_USEC); |
| *do_exit = 1; |
| } |
| tst_res(TINFO, "run %d passed", run); |
| run++; |
| } |
| |
| if (run == RUNS) |
| tst_res(TPASS, "kernel survived %d runs", run); |
| else |
| tst_res(TBROK, "something strange happened"); |
| } |
| |
| static struct tst_test test = { |
| .forks_child = 1, |
| .cleanup = cleanup, |
| .setup = setup, |
| .test_all = run, |
| }; |