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 30static void handler(int s) 31{ 32} 33 34static 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 81static 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 94int 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