1/* 2 * File: ptrace_tests_10767133.c 3 * Test Description: Testing different functions of the ptrace call. 4 * Radar: <rdar://problem/10767133> 5 * compile command: cc -o ../BUILD/ptrace_tests_10767133 ptrace_tests_10767133.c 6 */ 7#include <stdio.h> 8#include <unistd.h> 9#include <errno.h> 10#include <string.h> 11#include <assert.h> 12#include <stdlib.h> 13#include <sys/types.h> 14#include <sys/ptrace.h> 15#include <signal.h> 16#include <sys/wait.h> 17 18#define assert_condition(condition, exit_status, cause) \ 19 if (!(condition)) { \ 20 printf("[FAILED] %s:%s at %d error: %s \n", "test_10767133", __func__ , __LINE__, cause ); \ 21 if (errno) \ 22 perror(cause); \ 23 exit(exit_status); \ 24 } \ 25 26#define log_message(msg) \ 27 printf("%s:%d -> %s \n", __func__, __LINE__, msg); 28 29 30typedef int * pipe_t; 31 32ssize_t pipe_read_data(pipe_t p, void *dest_buf, int size) 33{ 34 int fd = p[0]; 35 int retval = read(fd, dest_buf, size); 36 if (retval == -1) { 37 printf("Error reading from buffer. "); 38 perror("pipe_read"); 39 } 40 return retval; 41} 42 43ssize_t pipe_write_data(pipe_t p, void *src_buf, int size) 44{ 45 int fd = p[1]; 46 int retval = write(fd, src_buf, size); 47 if (retval == -1) { 48 printf("Error writing to buffer. "); 49 perror("pipe_write"); 50 } 51 return retval; 52} 53 54 55 56void test_ptrace_deny_tace_sigexc(); 57void test_ptrace_attach_detach(); 58void test_ptrace_step_kill(); 59 60int main(){ 61 int retval =0; 62 log_message(" Testing for PT_FORCEQUOTA. it should return EPERM for non root program. "); 63 errno=0; 64 retval = ptrace(PT_FORCEQUOTA, getpid(), NULL, 0); 65 assert_condition( (retval == -1 && errno == EPERM), -1, "PT_FORCEQUOTA"); 66 67 log_message(" Testing to PT_DENY_ATTACH. should return successfully as nobody is tracing me.") 68 retval = ptrace(PT_DENY_ATTACH, getpid(), NULL, 0); 69 assert_condition (retval == 0 , -2, "PR_DENY_ATTACH"); 70 test_ptrace_deny_tace_sigexc(); 71 test_ptrace_attach_detach(); 72 test_ptrace_step_kill(); 73 success: 74 printf("[PASSED] Test test_10767133 passed. \n"); 75 return 0; 76 fail: 77 printf("[FAILED] Test test_10767133 failed. \n"); 78 return -1; 79} 80 81void test_ptrace_step_kill(){ 82 int retval = 0, status=1; 83 int parentpipe[2], childpipe[2], data; 84 enum data_state { begin, finished_child_loop, finished_parent_detach }; 85 retval = pipe(childpipe); 86 assert_condition(retval == 0, -1, "Pipe create"); 87 retval = pipe(parentpipe); 88 assert_condition(retval == 0, -1, "Pipe create"); 89 int childpid = fork(); 90 assert_condition(childpid >=0, -1, "fork failed"); 91 92 if (childpid == 0){ /* child */ 93 pipe_read_data(parentpipe, &data, sizeof(data)); 94 assert_condition(data == begin, -1, "child: parent not setting begin"); 95 pipe_write_data(childpipe, &data, sizeof(data)); 96 log_message("child: running the sleep loop"); 97 int i = 5; 98 log_message("child: sleep loop"); 99 while (i-- > 0){ 100 sleep(1); 101 printf(".z.\n"); 102 } 103 data = finished_child_loop; 104 log_message("child: finished sleep loop"); 105 pipe_write_data(childpipe, &data, sizeof(data)); 106 pipe_read_data(parentpipe, &data, sizeof(data)); 107 assert_condition(data == finished_parent_detach, -1, "child: parent not done with detach"); 108 i = 5; 109 log_message("child: sleep loop 2"); 110 while (i-- > 0){ 111 sleep(1); 112 printf(".Z.\n"); 113 } 114 exit(57); 115 }else{ /* parent */ 116 data = begin; 117 pipe_write_data(parentpipe, &data, sizeof(data)); 118 data = getpid(); 119 pipe_read_data(childpipe, &data, sizeof(data)); 120 assert_condition(data == begin, -1, "child is not ready with TRACE_ME setup"); 121 printf("parent: attaching to child with pid %d \n", childpid); 122 retval = ptrace(PT_ATTACH, childpid, NULL, 0); 123 assert_condition(retval == 0, -1, "parent: failed to attach to child"); 124 sleep(2); 125 log_message("parent: attached to child. Now PT_STEP through it"); 126 retval = ptrace(PT_STEP, childpid, (caddr_t)1, 0); 127 assert_condition(retval == 0, -1, "parent: failed to continue the child"); 128 sleep(2); 129 retval = ptrace(PT_STEP, childpid, (caddr_t)1, 0); 130 assert_condition(retval == 0, -1, "parent: failed to continue the child"); 131 log_message("parent: issuing PT_KILL to child "); 132 sleep(2); 133 retval = ptrace(PT_KILL, childpid, NULL, 0); 134 assert_condition(retval == 0, -1, "parent: failed to PT_KILL the child"); 135 data = finished_parent_detach; 136 pipe_write_data(parentpipe, &data, sizeof(data)); 137 waitpid(childpid,&status,0); 138 assert_condition(status != 57, -1, "child has exited successfully. It should have died with signal 9"); 139 assert_condition(status == 9, -1, "child has exited unexpectedly. Should have died with signal 9"); 140 } 141 142} 143 144void test_ptrace_attach_detach(){ 145 int retval = 0, status=1; 146 int parentpipe[2], childpipe[2], data; 147 enum data_state { begin, finished_child_loop, finished_parent_detach }; 148 retval = pipe(childpipe); 149 assert_condition(retval == 0, -1, "Pipe create"); 150 retval = pipe(parentpipe); 151 assert_condition(retval == 0, -1, "Pipe create"); 152 int childpid = fork(); 153 assert_condition(childpid >=0, -1, "fork failed"); 154 155 if (childpid == 0){ /* child */ 156 //retval = ptrace(PT_TRACE_ME, getpid(), NULL, 0); 157 //assert_condition(retval == 0, -1, "PT_TRACE_ME failed"); 158 pipe_read_data(parentpipe, &data, sizeof(data)); 159 assert_condition(data == begin, -1, "child: parent not setting begin"); 160 pipe_write_data(childpipe, &data, sizeof(data)); 161 log_message("child: running the sleep loop"); 162 int i = 5; 163 log_message("child: sleep looping"); 164 while (i-- > 0){ 165 sleep(1); 166 printf(".z.\n"); 167 } 168 data = finished_child_loop; 169 log_message("child: finished sleep loop"); 170 pipe_write_data(childpipe, &data, sizeof(data)); 171 pipe_read_data(parentpipe, &data, sizeof(data)); 172 assert_condition(data == finished_parent_detach, -1, "child: parent not done with detach"); 173 i = 5; 174 log_message("child sleep looping too"); 175 while (i-- > 0){ 176 sleep(1); 177 printf(".Z.\n"); 178 } 179 exit(0); 180 }else{ /* parent */ 181 data = begin; 182 pipe_write_data(parentpipe, &data, sizeof(data)); 183 data = getpid(); 184 pipe_read_data(childpipe, &data, sizeof(data)); 185 assert_condition(data == begin, -1, "child is not ready with TRACE_ME setup"); 186 printf("parent: attaching to child with pid %d \n", childpid); 187 retval = ptrace(PT_ATTACH, childpid, NULL, 0); 188 assert_condition(retval == 0, -1, "parent: failed to attach to child"); 189 sleep(2); 190 log_message("parent: attached to child. Now continuing it"); 191 retval = ptrace(PT_CONTINUE, childpid, (caddr_t)1, 0); 192 assert_condition(retval == 0, -1, "parent: failed to continue the child"); 193 194 pipe_read_data(childpipe, &data, sizeof(data)); 195 assert_condition(data == finished_child_loop, -1, "parent: child has not finished while loop"); 196 197 retval = kill(childpid, SIGSTOP); 198 assert_condition(retval == 0, -1, "parent: failed to SIGSTOP child"); 199 sleep(2); 200 201 log_message("parent: child has finished loop. Now detaching the child"); 202 retval = ptrace(PT_DETACH, childpid, NULL, 0); 203 assert_condition(retval == 0, -1, "parent: failed to detach"); 204 205 data = finished_parent_detach; 206 pipe_write_data(parentpipe, &data, sizeof(data)); 207 waitpid(childpid,&status,0); 208 assert_condition(status == 0, -1, "child has exited unexpectedly"); 209 } 210} 211 212 213void test_ptrace_deny_tace_sigexc(){ 214 enum ptrace_state { begin,denied_attach, sigexc_tested,trace_me_set, attached, stepped, continued, killed }; 215 int retval =0; 216 int childpipe[2],parentpipe[2], data[2]; 217 retval = pipe(childpipe); 218 assert_condition( retval == 0, -3, "Pipe create"); 219 retval = pipe(parentpipe); 220 assert_condition( retval == 0, -3, "Pipe create"); 221 222 data[0] = begin; // parent 223 data[1] = begin; //child 224 225 int childpid = fork(); 226 int status = 0; 227 assert_condition(childpid >=0, -4, "fork failed"); 228 229 if (childpid == 0){ 230 /* child */ 231 retval = ptrace(PT_DENY_ATTACH, getpid(), NULL,0); 232 data[1] = denied_attach; 233 pipe_write_data(childpipe, &data[1], sizeof(int)); 234 log_message("child: waiting for parent to write something"); 235 pipe_read_data(parentpipe, &data[0], sizeof(int)); 236 assert_condition(data[0] == begin , -5, "child: parent didnt begin with right state"); 237 238 /* waiting for parent to verify that PT_SIGEXC fails since child is not yet traced. */ 239 240 pipe_read_data(parentpipe, &data[0], sizeof(int)); 241 assert_condition(data[0] == sigexc_tested, -5, " child: parent didnt test for sigexc failure"); 242 log_message("child: setting myself to be traced"); 243 retval = ptrace(PT_TRACE_ME, getpid(), NULL ,0); 244 assert_condition(retval == 0, -6, "child: failed to setmyself for tracing"); 245 data[1]=trace_me_set; 246 pipe_write_data(childpipe, &data[1], sizeof(int)); 247 log_message("child: setting signals to be exceptions. PT_SIGEXC"); 248 retval = ptrace(PT_SIGEXC, getpid(), NULL, 0); 249 assert_condition(retval == 0, -7, "child: failed to set PT_SIGEXC"); 250 251 exit(0); 252 253 }else { 254 /* parent */ 255 // get status of child 256 pipe_read_data(childpipe, &data[1], sizeof(int)); 257 assert_condition(data[1] == denied_attach, -5, "parent: deny_attach_check"); 258 pipe_write_data(parentpipe, &data[0], sizeof(int)); 259 260 log_message("parent: testing for failure fo PT_SIGEXC "); 261 retval = ptrace(PT_SIGEXC, childpid, NULL, 0); 262 assert_condition(retval < 0 , -5, "PT_SIGEXC did not fail for untraced child"); 263 data[0] = sigexc_tested; 264 pipe_write_data(parentpipe, &data[0], sizeof(int)); 265 266 pipe_read_data(childpipe, &data[1], sizeof(int)); 267 assert_condition(data[1] == trace_me_set , -7, "parent: child has not set PT_TRACE_ME"); 268 269 waitpid(childpid, &status, 0); 270 if ( status != 0){ 271 log_message("Child exited with non zero status"); 272 } 273 } 274 275 close(childpipe[0]); 276 close(childpipe[1]); 277 278 close(parentpipe[0]); 279 close(parentpipe[1]); 280 281} 282