1 /*
2 * Copyright (C) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <stdlib.h>
17 #include <unistd.h>
18 #include <sys/wait.h>
19 #include <signal.h>
20 #include <errno.h>
21 #include <string.h>
22 #include "test.h"
23
24 #define ALIGNED_SIZE (8 * sizeof(size_t))
25 #define POINTER_USAGE (2 * sizeof(void *))
26 #define UAF_VAL 0xab
27 #define LOOP_SIZE 512
28 #define MALLOC_TIME 67
29
handler(int s)30 static void handler(int s)
31 {
32 }
33
child(void)34 static int child(void)
35 {
36 char *ptr[MALLOC_TIME];
37 char *ptr1[MALLOC_TIME];
38 char *divide[MALLOC_TIME];
39 for (int i = 0; i < LOOP_SIZE; ++i) {
40 for (int j = 0; j < MALLOC_TIME; ++j) {
41 ptr[j] = (char *)malloc(ALIGNED_SIZE - 1);
42 if (!ptr[j]) {
43 t_error("Malloc failed:%s\n", strerror(errno));
44 return -1;
45 }
46 divide[j] = (char *)malloc(ALIGNED_SIZE - 1);
47 if (!divide[j]) {
48 t_error("Malloc divide failed:%s\n", strerror(errno));
49 return -1;
50 }
51 }
52
53 for (int j = 0; j < MALLOC_TIME; ++j) {
54 free(ptr[j]);
55 /* Use after free, we should avoid changing the bin/quarantine deque pointer */
56 ptr[j][POINTER_USAGE] = (char)(UAF_VAL - j);
57 }
58
59 for (int j = 0; j < MALLOC_TIME; ++j) {
60 ptr1[j] = (char *)malloc(ALIGNED_SIZE - 1);
61 if (!ptr1[j]) {
62 t_error("Malloc failed:%s\n", strerror(errno));
63 return -1;
64 }
65 }
66
67 for (int j = 0; j < MALLOC_TIME; ++j) {
68 free(divide[j]);
69 divide[j][POINTER_USAGE] = (char)(UAF_VAL - j);
70 }
71
72 for (int j = 0; j < MALLOC_TIME; ++j) {
73 free(ptr1[j]);
74 ptr1[j][POINTER_USAGE] = (char)(UAF_VAL - j);
75 }
76 }
77
78 return 0;
79 }
80
start_child(void)81 static pid_t start_child(void)
82 {
83 pid_t pid = 0;
84 int ret = 0;
85 pid = fork();
86 if (pid == 0) {
87 ret = child();
88 t_error("child process normally out with %d\n", ret);
89 return ret;
90 }
91 return pid;
92 }
93
main(int argc,char * argv[])94 int main(int argc, char *argv[])
95 {
96 sigset_t set;
97 int status = 0;
98 pid_t pid = 0;
99 int flag = 0;
100 char *pname = (argc > 0) ? argv[0] : "malloc-uaf-check";
101
102 sigemptyset(&set);
103 sigaddset(&set, SIGCHLD);
104 sigprocmask(SIG_BLOCK, &set, 0);
105 signal(SIGCHLD, handler);
106
107 pid = start_child();
108 if (pid == -1) {
109 t_error("%s fork failed: %s\n", pname, strerror(errno));
110 return -1;
111 }
112 if (sigtimedwait(&set, 0, &(struct timespec){5, 0}) == -1) { /* Wait for 5 seconds */
113 if (errno == EAGAIN)
114 flag = 1;
115 else
116 t_error("%s sigtimedwait failed: %s\n", pname, strerror(errno));
117 if (kill(pid, SIGKILL) == -1)
118 t_error("%s kill failed: %s\n", pname, strerror(errno));
119 }
120
121 if (waitpid(pid, &status, 0) != pid) {
122 t_error("%s waitpid failed: %s\n", pname, strerror(errno));
123 return -1;
124 }
125
126 if (flag) {
127 t_error("Child process time out\n");
128 }
129
130 if (WIFSIGNALED(status)) {
131 if (WTERMSIG(status) != SIGSEGV && WTERMSIG(status) != SIGILL) {
132 t_error("%s child process out with %s\n", pname, strsignal(WTERMSIG(status)));
133 return -1;
134 }
135 } else {
136 t_error("%s child process finished normally\n", pname);
137 }
138 return t_status;
139 }
140