1 /**
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #define _GNU_SOURCE
17 #include <sys/types.h>
18 #include <sys/wait.h>
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <stdlib.h>
22 #include <sys/mman.h>
23 #include <sys/ptrace.h>
24 #include <sys/stat.h>
25 #include <unistd.h>
26 #include <../includes/common.h>
27
28 volatile char *mem = 0;
29
30 // child
check_zero_page()31 int check_zero_page() {
32 char *temp =
33 (char *)mmap(0, 4096, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
34 int zeropage = *(int *)temp;
35 munmap(temp, 4096);
36 return zeropage;
37 }
38
39 // child
do_child(int val)40 int do_child(int val) {
41 // enable tracing and wait until parent is finished unlocking zero page
42 ptrace(PTRACE_TRACEME, 0, 0, 0);
43 sleep(2);
44
45 mprotect((void *)mem, 4096, PROT_READ | PROT_WRITE);
46
47 // try to corrupt zero page
48 mem[0] = val;
49
50 int zeropage = check_zero_page();
51 return zeropage ? EXIT_VULNERABLE : 0;
52 }
53
54 // parent
do_trace(pid_t child)55 int do_trace(pid_t child) {
56 int status = 0;
57 sleep(1); // wait until child is set up
58 kill(child, SIGSTOP); // pause child
59 waitpid(child, &status, 0);
60
61 // unlock zero page
62 status = ptrace(PTRACE_PEEKDATA, child, mem, 0);
63
64 // stop tracing so child can continue
65 ptrace(PTRACE_DETACH, child, 0, 0);
66 kill(child, SIGCONT);
67 return status;
68 }
69
main(void)70 int main(void) {
71
72 char value = 0xAA;
73
74 mem = (volatile char *)mmap(0, 4096, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
75 mprotect((void *)mem, 4096, PROT_NONE);
76
77 pid_t child = fork();
78
79 if (child == 0) {
80 return do_child(value);
81 } else {
82 do_trace(child);
83 }
84
85 int status = 0;
86 waitpid(child, &status, 0); // wait for child to exit naturally
87 int exit = WEXITSTATUS(status); // get child exit status
88
89 munmap((void *)mem, 4096);
90
91 return exit;
92 }
93