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