-
Notifications
You must be signed in to change notification settings - Fork 0
/
ptrace.c
146 lines (122 loc) · 3.5 KB
/
ptrace.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <string.h>
#define PTRACE_SYSEMU 0x1d
#define PTRACE_SYSEMU_SINGLESTEP 0x1e
#define __NR_getpid 0x14
//#define DBG 1
static siginfo_t wait_trap(pid_t chld)
{
siginfo_t si;
if (waitid(P_PID, chld, &si, WEXITED|WSTOPPED) != 0)
perror("waitid");
if (si.si_pid != chld)
perror("got unexpected pid in event\n");
if (si.si_code != CLD_TRAPPED)
perror("got unexpected event type");
return si;
}
void dump_regs(struct pt_regs *regs) {
printf("r0 = %016lx and r1= %016lx\n", regs->gpr[0], regs->gpr[1]);
printf("r2 = %016lx and r3= %016lx\n", regs->gpr[2], regs->gpr[3]);
printf("r4 = %016lx and r5= %016lx\n", regs->gpr[4], regs->gpr[5]);
}
int trace_syscall()
{
pid_t chld = fork();
if (chld < 0) {
perror("Fork");
exit(-1);
}
/* CHILD */
if (chld == 0) {
int sysemu_result, syscall_result = 0;
/*
* This syscall will be trapped by PTRACE_SYSCALL, thus, it
* will execute
*/
syscall_result = syscall(__NR_getpid, 0, 0, 0, 0);
/*
* This syscall will be trapped by PTRACE_SYSEMU, thus, it
* will *not* execute and return the syscall number
*/
sysemu_result = syscall(__NR_getpid, 0, 0, 0, 0);
#ifdef DBG
printf("sysemu_result = %lx and syscall_result = %lx\n", sysemu_result, syscall_result);
#endif
/* The output should be the current PID */
if (syscall_result != getpid()) {
printf("Failure: PTRACE_SYSCALL output is not correct. (%x != %x)\n", syscall_result, getpid());
return -1;
}
/* The output should be the very first argument */
if (sysemu_result != 0) {
printf("Failure: PTRACE_SYSEMU output is not correct. (%x)\n", sysemu_result);
return -1;
}
return 0;
}
/* Parent */
if (chld > 0) {
int ret;
struct pt_regs regs;
ret = ptrace(PTRACE_ATTACH, chld, NULL, NULL);
if (ret < 0) {
perror("ptrace attach error");
exit(-1);
}
printf("Tracing process PID = %lx\n", chld);
/* Start with PTRACE_SYSCALL */
ret = ptrace(PTRACE_SYSCALL, chld, 0, 0);
if (ret < 0) {
perror("ptrace sysemu error");
exit(-1);
}
wait_trap(chld);
ptrace(PTRACE_GETREGS, chld, 0, ®s);
#ifdef DBG
printf("PTRACE_SYSCALL regs\n");
dump_regs(®s);
#endif
/* Checks if the registers are properly set as expected in
* in the syscall entrance
*/
if (regs.gpr[0] != __NR_getpid || regs.gpr[3] != 0 ||
regs.gpr[4] != 0 || regs.gpr[5] != 0 || regs.gpr[6] != 0) {
printf("Failure: SYSCALL does not seem to have r[0] = __NR_getpid or the regs are corrupted\n");
dump_regs(®s);
}
/* Now trace with PTRACE_SYSEMU */
ret = ptrace(PTRACE_SYSEMU, chld, 0, 0);
if (ret < 0) {
perror("ptrace sysemu error");
exit(-1);
}
wait_trap(chld);
ptrace(PTRACE_GETREGS, chld, 0, ®s);
#ifdef DBG
printf("PTRACE_SYSEMU regs\n");
dump_regs(®s);
#endif
if (regs.gpr[0] != __NR_getpid || regs.gpr[3] != 0 ||
regs.gpr[4] != 0 || regs.gpr[5] != 0 || regs.gpr[6] != 0) {
printf("Failure: SYSCALL does not seem to have r[0] = __NR_getpid, or the regs are corrupted\n");
dump_regs(®s);
return -1;
}
ret = ptrace(PTRACE_CONT, chld, NULL, NULL);
waitpid(chld, NULL, 0);
}
printf("Test passed\n");
return 0;
}
int main()
{
return trace_syscall();
}