get_syscall_info.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (c) 2018 Dmitry V. Levin <ldv@altlinux.org>
  4. * All rights reserved.
  5. *
  6. * Check whether PTRACE_GET_SYSCALL_INFO semantics implemented in the kernel
  7. * matches userspace expectations.
  8. */
  9. #include "kselftest_harness.h"
  10. #include <err.h>
  11. #include <signal.h>
  12. #include <asm/unistd.h>
  13. #include "linux/ptrace.h"
  14. static int
  15. kill_tracee(pid_t pid)
  16. {
  17. if (!pid)
  18. return 0;
  19. int saved_errno = errno;
  20. int rc = kill(pid, SIGKILL);
  21. errno = saved_errno;
  22. return rc;
  23. }
  24. static long
  25. sys_ptrace(int request, pid_t pid, unsigned long addr, unsigned long data)
  26. {
  27. return syscall(__NR_ptrace, request, pid, addr, data);
  28. }
  29. #define LOG_KILL_TRACEE(fmt, ...) \
  30. do { \
  31. kill_tracee(pid); \
  32. TH_LOG("wait #%d: " fmt, \
  33. ptrace_stop, ##__VA_ARGS__); \
  34. } while (0)
  35. TEST(get_syscall_info)
  36. {
  37. static const unsigned long args[][7] = {
  38. /* a sequence of architecture-agnostic syscalls */
  39. {
  40. __NR_chdir,
  41. (unsigned long) "",
  42. 0xbad1fed1,
  43. 0xbad2fed2,
  44. 0xbad3fed3,
  45. 0xbad4fed4,
  46. 0xbad5fed5
  47. },
  48. {
  49. __NR_gettid,
  50. 0xcaf0bea0,
  51. 0xcaf1bea1,
  52. 0xcaf2bea2,
  53. 0xcaf3bea3,
  54. 0xcaf4bea4,
  55. 0xcaf5bea5
  56. },
  57. {
  58. __NR_exit_group,
  59. 0,
  60. 0xfac1c0d1,
  61. 0xfac2c0d2,
  62. 0xfac3c0d3,
  63. 0xfac4c0d4,
  64. 0xfac5c0d5
  65. }
  66. };
  67. const unsigned long *exp_args;
  68. pid_t pid = fork();
  69. ASSERT_LE(0, pid) {
  70. TH_LOG("fork: %m");
  71. }
  72. if (pid == 0) {
  73. /* get the pid before PTRACE_TRACEME */
  74. pid = getpid();
  75. ASSERT_EQ(0, sys_ptrace(PTRACE_TRACEME, 0, 0, 0)) {
  76. TH_LOG("PTRACE_TRACEME: %m");
  77. }
  78. ASSERT_EQ(0, kill(pid, SIGSTOP)) {
  79. /* cannot happen */
  80. TH_LOG("kill SIGSTOP: %m");
  81. }
  82. for (unsigned int i = 0; i < ARRAY_SIZE(args); ++i) {
  83. syscall(args[i][0],
  84. args[i][1], args[i][2], args[i][3],
  85. args[i][4], args[i][5], args[i][6]);
  86. }
  87. /* unreachable */
  88. _exit(1);
  89. }
  90. const struct {
  91. unsigned int is_error;
  92. int rval;
  93. } *exp_param, exit_param[] = {
  94. { 1, -ENOENT }, /* chdir */
  95. { 0, pid } /* gettid */
  96. };
  97. unsigned int ptrace_stop;
  98. for (ptrace_stop = 0; ; ++ptrace_stop) {
  99. struct ptrace_syscall_info info = {
  100. .op = 0xff /* invalid PTRACE_SYSCALL_INFO_* op */
  101. };
  102. const size_t size = sizeof(info);
  103. const int expected_none_size =
  104. (void *) &info.entry - (void *) &info;
  105. const int expected_entry_size =
  106. (void *) &info.entry.args[6] - (void *) &info;
  107. const int expected_exit_size =
  108. (void *) (&info.exit.is_error + 1) -
  109. (void *) &info;
  110. int status;
  111. long rc;
  112. ASSERT_EQ(pid, wait(&status)) {
  113. /* cannot happen */
  114. LOG_KILL_TRACEE("wait: %m");
  115. }
  116. if (WIFEXITED(status)) {
  117. pid = 0; /* the tracee is no more */
  118. ASSERT_EQ(0, WEXITSTATUS(status));
  119. break;
  120. }
  121. ASSERT_FALSE(WIFSIGNALED(status)) {
  122. pid = 0; /* the tracee is no more */
  123. LOG_KILL_TRACEE("unexpected signal %u",
  124. WTERMSIG(status));
  125. }
  126. ASSERT_TRUE(WIFSTOPPED(status)) {
  127. /* cannot happen */
  128. LOG_KILL_TRACEE("unexpected wait status %#x", status);
  129. }
  130. switch (WSTOPSIG(status)) {
  131. case SIGSTOP:
  132. ASSERT_EQ(0, ptrace_stop) {
  133. LOG_KILL_TRACEE("unexpected signal stop");
  134. }
  135. ASSERT_EQ(0, sys_ptrace(PTRACE_SETOPTIONS, pid, 0,
  136. PTRACE_O_TRACESYSGOOD)) {
  137. LOG_KILL_TRACEE("PTRACE_SETOPTIONS: %m");
  138. }
  139. ASSERT_LT(0, (rc = sys_ptrace(PTRACE_GET_SYSCALL_INFO,
  140. pid, size,
  141. (unsigned long) &info))) {
  142. LOG_KILL_TRACEE("PTRACE_GET_SYSCALL_INFO: %m");
  143. }
  144. ASSERT_EQ(expected_none_size, rc) {
  145. LOG_KILL_TRACEE("signal stop mismatch");
  146. }
  147. ASSERT_EQ(PTRACE_SYSCALL_INFO_NONE, info.op) {
  148. LOG_KILL_TRACEE("signal stop mismatch");
  149. }
  150. ASSERT_TRUE(info.arch) {
  151. LOG_KILL_TRACEE("signal stop mismatch");
  152. }
  153. ASSERT_TRUE(info.instruction_pointer) {
  154. LOG_KILL_TRACEE("signal stop mismatch");
  155. }
  156. ASSERT_TRUE(info.stack_pointer) {
  157. LOG_KILL_TRACEE("signal stop mismatch");
  158. }
  159. break;
  160. case SIGTRAP | 0x80:
  161. ASSERT_LT(0, (rc = sys_ptrace(PTRACE_GET_SYSCALL_INFO,
  162. pid, size,
  163. (unsigned long) &info))) {
  164. LOG_KILL_TRACEE("PTRACE_GET_SYSCALL_INFO: %m");
  165. }
  166. switch (ptrace_stop) {
  167. case 1: /* entering chdir */
  168. case 3: /* entering gettid */
  169. case 5: /* entering exit_group */
  170. exp_args = args[ptrace_stop / 2];
  171. ASSERT_EQ(expected_entry_size, rc) {
  172. LOG_KILL_TRACEE("entry stop mismatch");
  173. }
  174. ASSERT_EQ(PTRACE_SYSCALL_INFO_ENTRY, info.op) {
  175. LOG_KILL_TRACEE("entry stop mismatch");
  176. }
  177. ASSERT_TRUE(info.arch) {
  178. LOG_KILL_TRACEE("entry stop mismatch");
  179. }
  180. ASSERT_TRUE(info.instruction_pointer) {
  181. LOG_KILL_TRACEE("entry stop mismatch");
  182. }
  183. ASSERT_TRUE(info.stack_pointer) {
  184. LOG_KILL_TRACEE("entry stop mismatch");
  185. }
  186. ASSERT_EQ(exp_args[0], info.entry.nr) {
  187. LOG_KILL_TRACEE("entry stop mismatch");
  188. }
  189. ASSERT_EQ(exp_args[1], info.entry.args[0]) {
  190. LOG_KILL_TRACEE("entry stop mismatch");
  191. }
  192. ASSERT_EQ(exp_args[2], info.entry.args[1]) {
  193. LOG_KILL_TRACEE("entry stop mismatch");
  194. }
  195. ASSERT_EQ(exp_args[3], info.entry.args[2]) {
  196. LOG_KILL_TRACEE("entry stop mismatch");
  197. }
  198. ASSERT_EQ(exp_args[4], info.entry.args[3]) {
  199. LOG_KILL_TRACEE("entry stop mismatch");
  200. }
  201. ASSERT_EQ(exp_args[5], info.entry.args[4]) {
  202. LOG_KILL_TRACEE("entry stop mismatch");
  203. }
  204. ASSERT_EQ(exp_args[6], info.entry.args[5]) {
  205. LOG_KILL_TRACEE("entry stop mismatch");
  206. }
  207. break;
  208. case 2: /* exiting chdir */
  209. case 4: /* exiting gettid */
  210. exp_param = &exit_param[ptrace_stop / 2 - 1];
  211. ASSERT_EQ(expected_exit_size, rc) {
  212. LOG_KILL_TRACEE("exit stop mismatch");
  213. }
  214. ASSERT_EQ(PTRACE_SYSCALL_INFO_EXIT, info.op) {
  215. LOG_KILL_TRACEE("exit stop mismatch");
  216. }
  217. ASSERT_TRUE(info.arch) {
  218. LOG_KILL_TRACEE("exit stop mismatch");
  219. }
  220. ASSERT_TRUE(info.instruction_pointer) {
  221. LOG_KILL_TRACEE("exit stop mismatch");
  222. }
  223. ASSERT_TRUE(info.stack_pointer) {
  224. LOG_KILL_TRACEE("exit stop mismatch");
  225. }
  226. ASSERT_EQ(exp_param->is_error,
  227. info.exit.is_error) {
  228. LOG_KILL_TRACEE("exit stop mismatch");
  229. }
  230. ASSERT_EQ(exp_param->rval, info.exit.rval) {
  231. LOG_KILL_TRACEE("exit stop mismatch");
  232. }
  233. break;
  234. default:
  235. LOG_KILL_TRACEE("unexpected syscall stop");
  236. abort();
  237. }
  238. break;
  239. default:
  240. LOG_KILL_TRACEE("unexpected stop signal %#x",
  241. WSTOPSIG(status));
  242. abort();
  243. }
  244. ASSERT_EQ(0, sys_ptrace(PTRACE_SYSCALL, pid, 0, 0)) {
  245. LOG_KILL_TRACEE("PTRACE_SYSCALL: %m");
  246. }
  247. }
  248. ASSERT_EQ(ARRAY_SIZE(args) * 2, ptrace_stop);
  249. }
  250. TEST_HARNESS_MAIN