Mirror of strace – the linux syscall tracer
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ptrace_syscall_info.c 8.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. /*
  2. * Copyright (c) 2018 Dmitry V. Levin <ldv@altlinux.org>
  3. * Copyright (c) 2018-2019 The strace developers.
  4. * All rights reserved.
  5. *
  6. * SPDX-License-Identifier: LGPL-2.1-or-later
  7. */
  8. #include "defs.h"
  9. #include "kill_save_errno.h"
  10. #include "print_fields.h"
  11. #include "ptrace.h"
  12. #include "ptrace_syscall_info.h"
  13. #include "scno.h"
  14. #include <signal.h>
  15. #include <sys/wait.h>
  16. #include "xlat/ptrace_syscall_info_op.h"
  17. bool ptrace_get_syscall_info_supported;
  18. static int
  19. kill_tracee(pid_t pid)
  20. {
  21. return kill_save_errno(pid, SIGKILL);
  22. }
  23. #define FAIL do { ptrace_stop = -1U; goto done; } while (0)
  24. static const unsigned int expected_none_size =
  25. offsetof(struct ptrace_syscall_info, entry);
  26. static const unsigned int expected_entry_size =
  27. offsetofend(struct ptrace_syscall_info, entry.args);
  28. static const unsigned int expected_exit_size =
  29. offsetofend(struct ptrace_syscall_info, exit.is_error);
  30. static const unsigned int expected_seccomp_size =
  31. offsetofend(struct ptrace_syscall_info, seccomp.ret_data);
  32. /*
  33. * Test that PTRACE_GET_SYSCALL_INFO API is supported by the kernel, and
  34. * that the semantics implemented in the kernel matches our expectations.
  35. */
  36. bool
  37. test_ptrace_get_syscall_info(void)
  38. {
  39. /*
  40. * NOMMU provides no forks necessary for PTRACE_GET_SYSCALL_INFO test,
  41. * leave the default unchanged.
  42. */
  43. #ifdef HAVE_FORK
  44. static const unsigned long args[][7] = {
  45. /* a sequence of architecture-agnostic syscalls */
  46. {
  47. __NR_chdir,
  48. (unsigned long) "",
  49. 0xbad1fed1,
  50. 0xbad2fed2,
  51. 0xbad3fed3,
  52. 0xbad4fed4,
  53. 0xbad5fed5
  54. },
  55. {
  56. __NR_gettid,
  57. 0xcaf0bea0,
  58. 0xcaf1bea1,
  59. 0xcaf2bea2,
  60. 0xcaf3bea3,
  61. 0xcaf4bea4,
  62. 0xcaf5bea5
  63. },
  64. {
  65. __NR_exit_group,
  66. 0,
  67. 0xfac1c0d1,
  68. 0xfac2c0d2,
  69. 0xfac3c0d3,
  70. 0xfac4c0d4,
  71. 0xfac5c0d5
  72. }
  73. };
  74. const unsigned long *exp_args;
  75. int pid = fork();
  76. if (pid < 0)
  77. perror_func_msg_and_die("fork");
  78. if (pid == 0) {
  79. /* get the pid before PTRACE_TRACEME */
  80. pid = getpid();
  81. if (ptrace(PTRACE_TRACEME, 0L, 0L, 0L) < 0) {
  82. /* exit with a nonzero exit status */
  83. perror_func_msg_and_die("PTRACE_TRACEME");
  84. }
  85. kill(pid, SIGSTOP);
  86. for (unsigned int i = 0; i < ARRAY_SIZE(args); ++i) {
  87. syscall(args[i][0],
  88. args[i][1], args[i][2], args[i][3],
  89. args[i][4], args[i][5], args[i][6]);
  90. }
  91. /* unreachable */
  92. _exit(1);
  93. }
  94. const struct {
  95. unsigned int is_error;
  96. int rval;
  97. } *exp_param, exit_param[] = {
  98. { 1, -ENOENT }, /* chdir */
  99. { 0, pid } /* gettid */
  100. };
  101. unsigned int ptrace_stop;
  102. for (ptrace_stop = 0; ; ++ptrace_stop) {
  103. struct ptrace_syscall_info info = {
  104. .op = 0xff /* invalid PTRACE_SYSCALL_INFO_* op */
  105. };
  106. const size_t size = sizeof(info);
  107. int status;
  108. long rc = waitpid(pid, &status, 0);
  109. if (rc != pid) {
  110. /* cannot happen */
  111. kill_tracee(pid);
  112. perror_func_msg_and_die("#%d: unexpected wait result"
  113. " %ld", ptrace_stop, rc);
  114. }
  115. if (WIFEXITED(status)) {
  116. /* tracee is no more */
  117. pid = 0;
  118. if (WEXITSTATUS(status) == 0)
  119. break;
  120. debug_func_msg("#%d: unexpected exit status %u",
  121. ptrace_stop, WEXITSTATUS(status));
  122. FAIL;
  123. }
  124. if (WIFSIGNALED(status)) {
  125. /* tracee is no more */
  126. pid = 0;
  127. debug_func_msg("#%d: unexpected signal %u",
  128. ptrace_stop, WTERMSIG(status));
  129. FAIL;
  130. }
  131. if (!WIFSTOPPED(status)) {
  132. /* cannot happen */
  133. kill_tracee(pid);
  134. error_func_msg_and_die("#%d: unexpected wait status"
  135. " %#x", ptrace_stop, status);
  136. }
  137. switch (WSTOPSIG(status)) {
  138. case SIGSTOP:
  139. if (ptrace_stop) {
  140. debug_func_msg("#%d: unexpected signal stop",
  141. ptrace_stop);
  142. FAIL;
  143. }
  144. if (ptrace(PTRACE_SETOPTIONS, pid, 0L,
  145. PTRACE_O_TRACESYSGOOD) < 0) {
  146. /* cannot happen */
  147. kill_tracee(pid);
  148. perror_func_msg_and_die("PTRACE_SETOPTIONS");
  149. }
  150. rc = ptrace(PTRACE_GET_SYSCALL_INFO, pid,
  151. (void *) size, &info);
  152. if (rc < 0) {
  153. debug_perror_msg("PTRACE_GET_SYSCALL_INFO");
  154. FAIL;
  155. }
  156. if (rc < (long) expected_none_size
  157. || info.op != PTRACE_SYSCALL_INFO_NONE
  158. || !info.arch
  159. || !info.instruction_pointer
  160. || !info.stack_pointer) {
  161. debug_func_msg("signal stop mismatch");
  162. FAIL;
  163. }
  164. break;
  165. case SIGTRAP | 0x80:
  166. rc = ptrace(PTRACE_GET_SYSCALL_INFO, pid,
  167. (void *) size, &info);
  168. if (rc < 0) {
  169. debug_perror_msg("#%d: PTRACE_GET_SYSCALL_INFO",
  170. ptrace_stop);
  171. FAIL;
  172. }
  173. switch (ptrace_stop) {
  174. case 1: /* entering chdir */
  175. case 3: /* entering gettid */
  176. case 5: /* entering exit_group */
  177. exp_args = args[ptrace_stop / 2];
  178. if (rc < (long) expected_entry_size
  179. || info.op != PTRACE_SYSCALL_INFO_ENTRY
  180. || !info.arch
  181. || !info.instruction_pointer
  182. || !info.stack_pointer
  183. || (info.entry.nr != exp_args[0])
  184. || (info.entry.args[0] != exp_args[1])
  185. || (info.entry.args[1] != exp_args[2])
  186. || (info.entry.args[2] != exp_args[3])
  187. || (info.entry.args[3] != exp_args[4])
  188. || (info.entry.args[4] != exp_args[5])
  189. || (info.entry.args[5] != exp_args[6])) {
  190. debug_func_msg("#%d: entry stop"
  191. " mismatch",
  192. ptrace_stop);
  193. FAIL;
  194. }
  195. break;
  196. case 2: /* exiting chdir */
  197. case 4: /* exiting gettid */
  198. exp_param = &exit_param[ptrace_stop / 2 - 1];
  199. if (rc < (long) expected_exit_size
  200. || info.op != PTRACE_SYSCALL_INFO_EXIT
  201. || !info.arch
  202. || !info.instruction_pointer
  203. || !info.stack_pointer
  204. || info.exit.is_error != exp_param->is_error
  205. || info.exit.rval != exp_param->rval) {
  206. debug_func_msg("#%d: exit stop"
  207. " mismatch",
  208. ptrace_stop);
  209. FAIL;
  210. }
  211. break;
  212. default:
  213. debug_func_msg("#%d: unexpected syscall stop",
  214. ptrace_stop);
  215. FAIL;
  216. }
  217. break;
  218. default:
  219. debug_func_msg("#%d: unexpected stop signal %#x",
  220. ptrace_stop, WSTOPSIG(status));
  221. FAIL;
  222. }
  223. if (ptrace(PTRACE_SYSCALL, pid, 0L, 0L) < 0) {
  224. /* cannot happen */
  225. kill_tracee(pid);
  226. perror_func_msg_and_die("PTRACE_SYSCALL");
  227. }
  228. }
  229. done:
  230. if (pid) {
  231. kill_tracee(pid);
  232. waitpid(pid, NULL, 0);
  233. ptrace_stop = -1U;
  234. }
  235. ptrace_get_syscall_info_supported =
  236. ptrace_stop == ARRAY_SIZE(args) * 2;
  237. if (ptrace_get_syscall_info_supported)
  238. debug_msg("PTRACE_GET_SYSCALL_INFO works");
  239. else
  240. debug_msg("PTRACE_GET_SYSCALL_INFO does not work");
  241. #endif /* HAVE_FORK */
  242. return ptrace_get_syscall_info_supported;
  243. }
  244. void
  245. print_ptrace_syscall_info(struct tcb *tcp, kernel_ulong_t addr,
  246. kernel_ulong_t user_len)
  247. {
  248. struct ptrace_syscall_info info;
  249. kernel_ulong_t kernel_len = tcp->u_rval;
  250. kernel_ulong_t ret_len = MIN(user_len, kernel_len);
  251. kernel_ulong_t fetch_size = MIN(ret_len, expected_seccomp_size);
  252. if (!fetch_size || !tfetch_mem(tcp, addr, fetch_size, &info)) {
  253. printaddr(addr);
  254. return;
  255. }
  256. PRINT_FIELD_XVAL("{", info, op, ptrace_syscall_info_op,
  257. "PTRACE_SYSCALL_INFO_???");
  258. if (fetch_size < offsetofend(struct ptrace_syscall_info, arch))
  259. goto printed;
  260. PRINT_FIELD_XVAL(", ", info, arch, audit_arch, "AUDIT_ARCH_???");
  261. if (fetch_size < offsetofend(struct ptrace_syscall_info,
  262. instruction_pointer))
  263. goto printed;
  264. PRINT_FIELD_ADDR64(", ", info, instruction_pointer);
  265. if (fetch_size < offsetofend(struct ptrace_syscall_info, stack_pointer))
  266. goto printed;
  267. PRINT_FIELD_ADDR64(", ", info, stack_pointer);
  268. if (fetch_size < offsetofend(struct ptrace_syscall_info, entry.nr))
  269. goto printed;
  270. switch(info.op) {
  271. case PTRACE_SYSCALL_INFO_ENTRY:
  272. case PTRACE_SYSCALL_INFO_SECCOMP:
  273. PRINT_FIELD_U((info.op == PTRACE_SYSCALL_INFO_ENTRY
  274. ? ", entry={" : ", seccomp={"),
  275. info.entry, nr);
  276. for (unsigned int i = 0;
  277. i < ARRAY_SIZE(info.entry.args); ++i) {
  278. const unsigned int i_size =
  279. offsetofend(struct ptrace_syscall_info,
  280. entry.args[i]);
  281. if (fetch_size < i_size) {
  282. if (i)
  283. break;
  284. goto entry_printed;
  285. }
  286. tprintf(", %s%#" PRIx64,
  287. (i ? "" : "arg=["),
  288. (uint64_t) info.entry.args[i]);
  289. }
  290. tprints("]");
  291. if (info.op == PTRACE_SYSCALL_INFO_SECCOMP
  292. && fetch_size >= expected_seccomp_size)
  293. PRINT_FIELD_U(", ", info.seccomp, ret_data);
  294. entry_printed:
  295. tprints("}");
  296. break;
  297. case PTRACE_SYSCALL_INFO_EXIT:
  298. tprints(", exit={");
  299. if (fetch_size >= expected_exit_size
  300. && info.exit.is_error) {
  301. PRINT_FIELD_ERR_D("", info.exit, rval);
  302. } else {
  303. PRINT_FIELD_D("", info.exit, rval);
  304. }
  305. if (fetch_size >= expected_exit_size)
  306. PRINT_FIELD_U(", ", info.exit, is_error);
  307. tprints("}");
  308. break;
  309. }
  310. printed:
  311. tprints("}");
  312. }