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