0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #define _GNU_SOURCE
0012
0013 #include <sys/ptrace.h>
0014 #include <sys/types.h>
0015 #include <sys/wait.h>
0016 #include <sys/syscall.h>
0017 #include <sys/user.h>
0018 #include <unistd.h>
0019 #include <errno.h>
0020 #include <stddef.h>
0021 #include <stdio.h>
0022 #include <err.h>
0023 #include <string.h>
0024 #include <sys/auxv.h>
0025 #include "utils.h"
0026
0027
0028 #define user_syscall_nr gpr[0]
0029 #define user_arg0 gpr[3]
0030 #define user_arg1 gpr[4]
0031 #define user_arg2 gpr[5]
0032 #define user_arg3 gpr[6]
0033 #define user_arg4 gpr[7]
0034 #define user_arg5 gpr[8]
0035 #define user_ip nip
0036
0037 #define PTRACE_SYSEMU 0x1d
0038
0039 static int nerrs;
0040
0041 static void wait_trap(pid_t chld)
0042 {
0043 siginfo_t si;
0044
0045 if (waitid(P_PID, chld, &si, WEXITED|WSTOPPED) != 0)
0046 err(1, "waitid");
0047 if (si.si_pid != chld)
0048 errx(1, "got unexpected pid in event\n");
0049 if (si.si_code != CLD_TRAPPED)
0050 errx(1, "got unexpected event type %d\n", si.si_code);
0051 }
0052
0053 static void test_ptrace_syscall_restart(void)
0054 {
0055 int status;
0056 struct pt_regs regs;
0057 pid_t chld;
0058
0059 printf("[RUN]\tptrace-induced syscall restart\n");
0060
0061 chld = fork();
0062 if (chld < 0)
0063 err(1, "fork");
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073 if (chld == 0) {
0074 if (ptrace(PTRACE_TRACEME, 0, 0, 0) != 0)
0075 err(1, "PTRACE_TRACEME");
0076
0077 pid_t pid = getpid(), tid = syscall(SYS_gettid);
0078
0079 printf("\tChild will make one syscall\n");
0080 syscall(SYS_tgkill, pid, tid, SIGSTOP);
0081
0082 syscall(SYS_gettid, 10, 11, 12, 13, 14, 15);
0083 _exit(0);
0084 }
0085
0086
0087
0088 if (waitpid(chld, &status, 0) != chld || !WIFSTOPPED(status))
0089 err(1, "waitpid");
0090
0091 printf("[RUN]\tSYSEMU\n");
0092 if (ptrace(PTRACE_SYSEMU, chld, 0, 0) != 0)
0093 err(1, "PTRACE_SYSEMU");
0094 wait_trap(chld);
0095
0096 if (ptrace(PTRACE_GETREGS, chld, 0, ®s) != 0)
0097 err(1, "PTRACE_GETREGS");
0098
0099
0100
0101
0102
0103 if (regs.user_syscall_nr != SYS_gettid ||
0104 regs.user_arg0 != 10 || regs.user_arg1 != 11 ||
0105 regs.user_arg2 != 12 || regs.user_arg3 != 13 ||
0106 regs.user_arg4 != 14 || regs.user_arg5 != 15) {
0107 printf("[FAIL]\tInitial args are wrong (nr=%lu, args=%lu %lu %lu %lu %lu %lu)\n",
0108 (unsigned long)regs.user_syscall_nr,
0109 (unsigned long)regs.user_arg0,
0110 (unsigned long)regs.user_arg1,
0111 (unsigned long)regs.user_arg2,
0112 (unsigned long)regs.user_arg3,
0113 (unsigned long)regs.user_arg4,
0114 (unsigned long)regs.user_arg5);
0115 nerrs++;
0116 } else {
0117 printf("[OK]\tInitial nr and args are correct\n"); }
0118
0119 printf("[RUN]\tRestart the syscall (ip = 0x%lx)\n",
0120 (unsigned long)regs.user_ip);
0121
0122
0123
0124
0125
0126 regs.user_ip -= 4;
0127 if (ptrace(PTRACE_SETREGS, chld, 0, ®s) != 0)
0128 err(1, "PTRACE_SETREGS");
0129
0130 if (ptrace(PTRACE_SYSEMU, chld, 0, 0) != 0)
0131 err(1, "PTRACE_SYSEMU");
0132 wait_trap(chld);
0133
0134 if (ptrace(PTRACE_GETREGS, chld, 0, ®s) != 0)
0135 err(1, "PTRACE_GETREGS");
0136
0137 if (regs.user_syscall_nr != SYS_gettid ||
0138 regs.user_arg0 != 10 || regs.user_arg1 != 11 ||
0139 regs.user_arg2 != 12 || regs.user_arg3 != 13 ||
0140 regs.user_arg4 != 14 || regs.user_arg5 != 15) {
0141 printf("[FAIL]\tRestart nr or args are wrong (nr=%lu, args=%lu %lu %lu %lu %lu %lu)\n",
0142 (unsigned long)regs.user_syscall_nr,
0143 (unsigned long)regs.user_arg0,
0144 (unsigned long)regs.user_arg1,
0145 (unsigned long)regs.user_arg2,
0146 (unsigned long)regs.user_arg3,
0147 (unsigned long)regs.user_arg4,
0148 (unsigned long)regs.user_arg5);
0149 nerrs++;
0150 } else {
0151 printf("[OK]\tRestarted nr and args are correct\n");
0152 }
0153
0154 printf("[RUN]\tChange nr and args and restart the syscall (ip = 0x%lx)\n",
0155 (unsigned long)regs.user_ip);
0156
0157
0158
0159
0160
0161 regs.user_syscall_nr = SYS_getpid;
0162 regs.user_arg0 = 20;
0163 regs.user_arg1 = 21;
0164 regs.user_arg2 = 22;
0165 regs.user_arg3 = 23;
0166 regs.user_arg4 = 24;
0167 regs.user_arg5 = 25;
0168 regs.user_ip -= 4;
0169
0170 if (ptrace(PTRACE_SETREGS, chld, 0, ®s) != 0)
0171 err(1, "PTRACE_SETREGS");
0172
0173 if (ptrace(PTRACE_SYSEMU, chld, 0, 0) != 0)
0174 err(1, "PTRACE_SYSEMU");
0175 wait_trap(chld);
0176
0177 if (ptrace(PTRACE_GETREGS, chld, 0, ®s) != 0)
0178 err(1, "PTRACE_GETREGS");
0179
0180
0181
0182
0183
0184
0185 if (regs.user_syscall_nr != SYS_getpid
0186 || regs.user_arg0 != 20 || regs.user_arg1 != 21
0187 || regs.user_arg2 != 22 || regs.user_arg3 != 23
0188 || regs.user_arg4 != 24 || regs.user_arg5 != 25) {
0189
0190 printf("[FAIL]\tRestart nr or args are wrong (nr=%lu, args=%lu %lu %lu %lu %lu %lu)\n",
0191 (unsigned long)regs.user_syscall_nr,
0192 (unsigned long)regs.user_arg0,
0193 (unsigned long)regs.user_arg1,
0194 (unsigned long)regs.user_arg2,
0195 (unsigned long)regs.user_arg3,
0196 (unsigned long)regs.user_arg4,
0197 (unsigned long)regs.user_arg5);
0198 nerrs++;
0199 } else {
0200 printf("[OK]\tReplacement nr and args are correct\n");
0201 }
0202
0203 if (ptrace(PTRACE_CONT, chld, 0, 0) != 0)
0204 err(1, "PTRACE_CONT");
0205
0206 if (waitpid(chld, &status, 0) != chld)
0207 err(1, "waitpid");
0208
0209
0210 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
0211 printf("[FAIL]\tChild failed\n");
0212 nerrs++;
0213 } else {
0214 printf("[OK]\tChild exited cleanly\n");
0215 }
0216 }
0217
0218 int ptrace_syscall(void)
0219 {
0220 test_ptrace_syscall_restart();
0221
0222 return nerrs;
0223 }
0224
0225 int main(void)
0226 {
0227 return test_harness(ptrace_syscall, "ptrace_syscall");
0228 }