augmented_syscalls.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Augment syscalls with the contents of the pointer arguments.
  4. *
  5. * Test it with:
  6. *
  7. * perf trace -e tools/perf/examples/bpf/augmented_syscalls.c cat /etc/passwd > /dev/null
  8. *
  9. * It'll catch some openat syscalls related to the dynamic linked and
  10. * the last one should be the one for '/etc/passwd'.
  11. *
  12. * This matches what is marshalled into the raw_syscall:sys_enter payload
  13. * expected by the 'perf trace' beautifiers, and can be used by them, that will
  14. * check if perf_sample->raw_data is more than what is expected for each
  15. * syscalls:sys_{enter,exit}_SYSCALL tracepoint, uing the extra data as the
  16. * contents of pointer arguments.
  17. */
  18. #include <stdio.h>
  19. #include <linux/socket.h>
  20. struct bpf_map SEC("maps") __augmented_syscalls__ = {
  21. .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
  22. .key_size = sizeof(int),
  23. .value_size = sizeof(u32),
  24. .max_entries = __NR_CPUS__,
  25. };
  26. struct syscall_exit_args {
  27. unsigned long long common_tp_fields;
  28. long syscall_nr;
  29. long ret;
  30. };
  31. struct augmented_filename {
  32. unsigned int size;
  33. int reserved;
  34. char value[256];
  35. };
  36. #define augmented_filename_syscall(syscall) \
  37. struct augmented_enter_##syscall##_args { \
  38. struct syscall_enter_##syscall##_args args; \
  39. struct augmented_filename filename; \
  40. }; \
  41. int syscall_enter(syscall)(struct syscall_enter_##syscall##_args *args) \
  42. { \
  43. struct augmented_enter_##syscall##_args augmented_args = { .filename.reserved = 0, }; \
  44. unsigned int len = sizeof(augmented_args); \
  45. probe_read(&augmented_args.args, sizeof(augmented_args.args), args); \
  46. augmented_args.filename.size = probe_read_str(&augmented_args.filename.value, \
  47. sizeof(augmented_args.filename.value), \
  48. args->filename_ptr); \
  49. if (augmented_args.filename.size < sizeof(augmented_args.filename.value)) { \
  50. len -= sizeof(augmented_args.filename.value) - augmented_args.filename.size; \
  51. len &= sizeof(augmented_args.filename.value) - 1; \
  52. } \
  53. perf_event_output(args, &__augmented_syscalls__, BPF_F_CURRENT_CPU, \
  54. &augmented_args, len); \
  55. return 0; \
  56. } \
  57. int syscall_exit(syscall)(struct syscall_exit_args *args) \
  58. { \
  59. return 1; /* 0 as soon as we start copying data returned by the kernel, e.g. 'read' */ \
  60. }
  61. struct syscall_enter_openat_args {
  62. unsigned long long common_tp_fields;
  63. long syscall_nr;
  64. long dfd;
  65. char *filename_ptr;
  66. long flags;
  67. long mode;
  68. };
  69. augmented_filename_syscall(openat);
  70. struct syscall_enter_open_args {
  71. unsigned long long common_tp_fields;
  72. long syscall_nr;
  73. char *filename_ptr;
  74. long flags;
  75. long mode;
  76. };
  77. augmented_filename_syscall(open);
  78. struct syscall_enter_inotify_add_watch_args {
  79. unsigned long long common_tp_fields;
  80. long syscall_nr;
  81. long fd;
  82. char *filename_ptr;
  83. long mask;
  84. };
  85. augmented_filename_syscall(inotify_add_watch);
  86. struct statbuf;
  87. struct syscall_enter_newstat_args {
  88. unsigned long long common_tp_fields;
  89. long syscall_nr;
  90. char *filename_ptr;
  91. struct stat *statbuf;
  92. };
  93. augmented_filename_syscall(newstat);
  94. #ifndef _K_SS_MAXSIZE
  95. #define _K_SS_MAXSIZE 128
  96. #endif
  97. #define augmented_sockaddr_syscall(syscall) \
  98. struct augmented_enter_##syscall##_args { \
  99. struct syscall_enter_##syscall##_args args; \
  100. struct sockaddr_storage addr; \
  101. }; \
  102. int syscall_enter(syscall)(struct syscall_enter_##syscall##_args *args) \
  103. { \
  104. struct augmented_enter_##syscall##_args augmented_args; \
  105. unsigned long addrlen = sizeof(augmented_args.addr); \
  106. probe_read(&augmented_args.args, sizeof(augmented_args.args), args); \
  107. /* FIXME_CLANG_OPTIMIZATION_THAT_ACCESSES_USER_CONTROLLED_ADDRLEN_DESPITE_THIS_CHECK */ \
  108. /* if (addrlen > augmented_args.args.addrlen) */ \
  109. /* addrlen = augmented_args.args.addrlen; */ \
  110. /* */ \
  111. probe_read(&augmented_args.addr, addrlen, args->addr_ptr); \
  112. perf_event_output(args, &__augmented_syscalls__, BPF_F_CURRENT_CPU, \
  113. &augmented_args, \
  114. sizeof(augmented_args) - sizeof(augmented_args.addr) + addrlen); \
  115. return 0; \
  116. } \
  117. int syscall_exit(syscall)(struct syscall_exit_args *args) \
  118. { \
  119. return 1; /* 0 as soon as we start copying data returned by the kernel, e.g. 'read' */ \
  120. }
  121. struct sockaddr;
  122. struct syscall_enter_bind_args {
  123. unsigned long long common_tp_fields;
  124. long syscall_nr;
  125. long fd;
  126. struct sockaddr *addr_ptr;
  127. unsigned long addrlen;
  128. };
  129. augmented_sockaddr_syscall(bind);
  130. struct syscall_enter_connect_args {
  131. unsigned long long common_tp_fields;
  132. long syscall_nr;
  133. long fd;
  134. struct sockaddr *addr_ptr;
  135. unsigned long addrlen;
  136. };
  137. augmented_sockaddr_syscall(connect);
  138. struct syscall_enter_sendto_args {
  139. unsigned long long common_tp_fields;
  140. long syscall_nr;
  141. long fd;
  142. void *buff;
  143. long len;
  144. unsigned long flags;
  145. struct sockaddr *addr_ptr;
  146. long addr_len;
  147. };
  148. augmented_sockaddr_syscall(sendto);
  149. license(GPL);