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.

filter_qualify.c 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. /*
  2. * Copyright (c) 2016 Dmitry V. Levin <ldv@altlinux.org>
  3. * Copyright (c) 2016-2018 The strace developers.
  4. * All rights reserved.
  5. *
  6. * SPDX-License-Identifier: LGPL-2.1-or-later
  7. */
  8. #include "defs.h"
  9. #include "nsig.h"
  10. #include "number_set.h"
  11. #include "filter.h"
  12. #include "delay.h"
  13. #include "retval.h"
  14. struct number_set *read_set;
  15. struct number_set *write_set;
  16. struct number_set *signal_set;
  17. static struct number_set *abbrev_set;
  18. static struct number_set *inject_set;
  19. static struct number_set *raw_set;
  20. static struct number_set *trace_set;
  21. static struct number_set *verbose_set;
  22. /* Only syscall numbers are personality-specific so far. */
  23. struct inject_personality_data {
  24. uint16_t scno;
  25. };
  26. static int
  27. sigstr_to_uint(const char *s)
  28. {
  29. if (*s >= '0' && *s <= '9')
  30. return string_to_uint_upto(s, 255);
  31. if (strncasecmp(s, "SIG", 3) == 0)
  32. s += 3;
  33. for (int i = 1; i <= 255; ++i) {
  34. const char *name = signame(i);
  35. if (strncasecmp(name, "SIG", 3) != 0)
  36. continue;
  37. name += 3;
  38. if (strcasecmp(name, s) != 0)
  39. continue;
  40. return i;
  41. }
  42. return -1;
  43. }
  44. static int
  45. find_errno_by_name(const char *name)
  46. {
  47. for (unsigned int i = 1; i < nerrnos; ++i) {
  48. if (errnoent[i] && (strcasecmp(name, errnoent[i]) == 0))
  49. return i;
  50. }
  51. return -1;
  52. }
  53. static bool
  54. parse_delay_token(const char *input, struct inject_opts *fopts, bool isenter)
  55. {
  56. unsigned flag = isenter ? INJECT_F_DELAY_ENTER : INJECT_F_DELAY_EXIT;
  57. if (fopts->data.flags & flag) /* duplicate */
  58. return false;
  59. long long intval = string_to_ulonglong(input);
  60. if (intval < 0) /* couldn't parse */
  61. return false;
  62. if (fopts->data.delay_idx == (uint16_t) -1)
  63. fopts->data.delay_idx = alloc_delay_data();
  64. /* populate .ts_enter or .ts_exit */
  65. fill_delay_data(fopts->data.delay_idx, intval, isenter);
  66. fopts->data.flags |= flag;
  67. return true;
  68. }
  69. static bool
  70. parse_inject_token(const char *const token, struct inject_opts *const fopts,
  71. struct inject_personality_data *const pdata,
  72. const bool fault_tokens_only)
  73. {
  74. const char *val;
  75. int intval;
  76. if ((val = STR_STRIP_PREFIX(token, "when=")) != token) {
  77. /*
  78. * == 1+1
  79. * F == F+0
  80. * F+ == F+1
  81. * F+S
  82. */
  83. char *end;
  84. intval = string_to_uint_ex(val, &end, 0xffff, "+");
  85. if (intval < 1)
  86. return false;
  87. fopts->first = intval;
  88. if (*end) {
  89. val = end + 1;
  90. if (*val) {
  91. /* F+S */
  92. intval = string_to_uint_upto(val, 0xffff);
  93. if (intval < 1)
  94. return false;
  95. fopts->step = intval;
  96. } else {
  97. /* F+ == F+1 */
  98. fopts->step = 1;
  99. }
  100. } else {
  101. /* F == F+0 */
  102. fopts->step = 0;
  103. }
  104. } else if ((val = STR_STRIP_PREFIX(token, "syscall=")) != token) {
  105. if (fopts->data.flags & INJECT_F_SYSCALL)
  106. return false;
  107. for (unsigned int p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
  108. kernel_long_t scno = scno_by_name(val, p, 0);
  109. if (scno < 0)
  110. return false;
  111. /*
  112. * We want to inject only pure system calls with no side
  113. * effects.
  114. */
  115. if (!(sysent_vec[p][scno].sys_flags & TRACE_PURE))
  116. return false;
  117. pdata[p].scno = scno;
  118. }
  119. fopts->data.flags |= INJECT_F_SYSCALL;
  120. } else if ((val = STR_STRIP_PREFIX(token, "error=")) != token) {
  121. if (fopts->data.flags & (INJECT_F_ERROR | INJECT_F_RETVAL))
  122. return false;
  123. intval = string_to_uint_upto(val, MAX_ERRNO_VALUE);
  124. if (intval < 0)
  125. intval = find_errno_by_name(val);
  126. if (intval < 1)
  127. return false;
  128. fopts->data.rval_idx = retval_new(intval);
  129. fopts->data.flags |= INJECT_F_ERROR;
  130. } else if (!fault_tokens_only
  131. && (val = STR_STRIP_PREFIX(token, "retval=")) != token) {
  132. if (fopts->data.flags & (INJECT_F_ERROR | INJECT_F_RETVAL))
  133. return false;
  134. errno = 0;
  135. char *endp;
  136. unsigned long long ullval = strtoull(val, &endp, 0);
  137. if (endp == val || *endp || (kernel_ulong_t) ullval != ullval
  138. || ((ullval == 0 || ullval == ULLONG_MAX) && errno))
  139. return false;
  140. #if ANY_WORDSIZE_LESS_THAN_KERNEL_LONG
  141. bool inadvertent_fault_injection = false;
  142. #endif
  143. #if !HAVE_ARCH_DEDICATED_ERR_REG
  144. if ((kernel_long_t) ullval < 0
  145. && (kernel_long_t) ullval >= -MAX_ERRNO_VALUE) {
  146. # if ANY_WORDSIZE_LESS_THAN_KERNEL_LONG
  147. inadvertent_fault_injection = true;
  148. # endif
  149. error_msg("Inadvertent injection of error %" PRI_kld
  150. " is possible for retval=%llu",
  151. -(kernel_long_t) ullval, ullval);
  152. }
  153. # if ANY_WORDSIZE_LESS_THAN_KERNEL_LONG
  154. else if ((int) ullval < 0 && (int) ullval >= -MAX_ERRNO_VALUE) {
  155. inadvertent_fault_injection = true;
  156. error_msg("Inadvertent injection of error %d is"
  157. " possible in compat personality for"
  158. " retval=%llu",
  159. -(int) ullval, ullval);
  160. }
  161. # endif
  162. #endif
  163. #if ANY_WORDSIZE_LESS_THAN_KERNEL_LONG
  164. if (!inadvertent_fault_injection
  165. && (unsigned int) ullval != ullval) {
  166. error_msg("Injected return value %llu will be"
  167. " clipped to %u in compat personality",
  168. ullval, (unsigned int) ullval);
  169. }
  170. #endif
  171. fopts->data.rval_idx = retval_new(ullval);
  172. fopts->data.flags |= INJECT_F_RETVAL;
  173. } else if (!fault_tokens_only
  174. && (val = STR_STRIP_PREFIX(token, "signal=")) != token) {
  175. if (fopts->data.flags & INJECT_F_SIGNAL)
  176. return false;
  177. intval = sigstr_to_uint(val);
  178. if (intval < 1 || intval > NSIG_BYTES * 8)
  179. return false;
  180. fopts->data.signo = intval;
  181. fopts->data.flags |= INJECT_F_SIGNAL;
  182. } else if (!fault_tokens_only
  183. && (val = STR_STRIP_PREFIX(token, "delay_enter=")) != token) {
  184. if (!parse_delay_token(val, fopts, true))
  185. return false;
  186. } else if (!fault_tokens_only
  187. && (val = STR_STRIP_PREFIX(token, "delay_exit=")) != token) {
  188. if (!parse_delay_token(val, fopts, false))
  189. return false;
  190. } else {
  191. return false;
  192. }
  193. return true;
  194. }
  195. static const char *
  196. parse_inject_expression(char *const str,
  197. struct inject_opts *const fopts,
  198. struct inject_personality_data *const pdata,
  199. const bool fault_tokens_only)
  200. {
  201. if (str[0] == '\0' || str[0] == ':')
  202. return "";
  203. char *saveptr = NULL;
  204. const char *name = strtok_r(str, ":", &saveptr);
  205. char *token;
  206. while ((token = strtok_r(NULL, ":", &saveptr))) {
  207. if (!parse_inject_token(token, fopts, pdata, fault_tokens_only))
  208. return NULL;
  209. }
  210. return name;
  211. }
  212. static void
  213. qualify_read(const char *const str)
  214. {
  215. if (!read_set)
  216. read_set = alloc_number_set_array(1);
  217. qualify_tokens(str, read_set, string_to_uint, "descriptor");
  218. }
  219. static void
  220. qualify_write(const char *const str)
  221. {
  222. if (!write_set)
  223. write_set = alloc_number_set_array(1);
  224. qualify_tokens(str, write_set, string_to_uint, "descriptor");
  225. }
  226. static void
  227. qualify_signals(const char *const str)
  228. {
  229. if (!signal_set)
  230. signal_set = alloc_number_set_array(1);
  231. qualify_tokens(str, signal_set, sigstr_to_uint, "signal");
  232. }
  233. static void
  234. qualify_trace(const char *const str)
  235. {
  236. if (!trace_set)
  237. trace_set = alloc_number_set_array(SUPPORTED_PERSONALITIES);
  238. qualify_syscall_tokens(str, trace_set);
  239. }
  240. static void
  241. qualify_abbrev(const char *const str)
  242. {
  243. if (!abbrev_set)
  244. abbrev_set = alloc_number_set_array(SUPPORTED_PERSONALITIES);
  245. qualify_syscall_tokens(str, abbrev_set);
  246. }
  247. static void
  248. qualify_verbose(const char *const str)
  249. {
  250. if (!verbose_set)
  251. verbose_set = alloc_number_set_array(SUPPORTED_PERSONALITIES);
  252. qualify_syscall_tokens(str, verbose_set);
  253. }
  254. static void
  255. qualify_raw(const char *const str)
  256. {
  257. if (!raw_set)
  258. raw_set = alloc_number_set_array(SUPPORTED_PERSONALITIES);
  259. qualify_syscall_tokens(str, raw_set);
  260. }
  261. static void
  262. qualify_inject_common(const char *const str,
  263. const bool fault_tokens_only,
  264. const char *const description)
  265. {
  266. struct inject_opts opts = {
  267. .first = 1,
  268. .step = 1,
  269. .data = {
  270. .delay_idx = -1
  271. }
  272. };
  273. struct inject_personality_data pdata[SUPPORTED_PERSONALITIES] = { { 0 } };
  274. char *copy = xstrdup(str);
  275. const char *name =
  276. parse_inject_expression(copy, &opts, pdata, fault_tokens_only);
  277. if (!name)
  278. error_msg_and_die("invalid %s '%s'", description, str);
  279. struct number_set *tmp_set =
  280. alloc_number_set_array(SUPPORTED_PERSONALITIES);
  281. qualify_syscall_tokens(name, tmp_set);
  282. free(copy);
  283. /* If neither of retval, error, signal or delay is specified, then ... */
  284. if (!(opts.data.flags & INJECT_ACTION_FLAGS)) {
  285. if (fault_tokens_only) {
  286. /* in fault= syntax the default error code is ENOSYS. */
  287. opts.data.rval_idx = retval_new(ENOSYS);
  288. opts.data.flags |= INJECT_F_ERROR;
  289. } else {
  290. /* in inject= syntax this is not allowed. */
  291. error_msg_and_die("invalid %s '%s'", description, str);
  292. }
  293. }
  294. /*
  295. * Initialize inject_vec according to tmp_set.
  296. * Merge tmp_set into inject_set.
  297. */
  298. for (unsigned int p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
  299. if (number_set_array_is_empty(tmp_set, p))
  300. continue;
  301. if (!inject_set) {
  302. inject_set =
  303. alloc_number_set_array(SUPPORTED_PERSONALITIES);
  304. }
  305. if (!inject_vec[p]) {
  306. inject_vec[p] = xcalloc(nsyscall_vec[p],
  307. sizeof(*inject_vec[p]));
  308. }
  309. for (unsigned int i = 0; i < nsyscall_vec[p]; ++i) {
  310. if (is_number_in_set_array(i, tmp_set, p)) {
  311. add_number_to_set_array(i, inject_set, p);
  312. inject_vec[p][i] = opts;
  313. /* Copy per-personality data. */
  314. inject_vec[p][i].data.scno =
  315. pdata[p].scno;
  316. }
  317. }
  318. }
  319. free_number_set_array(tmp_set, SUPPORTED_PERSONALITIES);
  320. }
  321. static void
  322. qualify_fault(const char *const str)
  323. {
  324. qualify_inject_common(str, true, "fault argument");
  325. }
  326. static void
  327. qualify_inject(const char *const str)
  328. {
  329. qualify_inject_common(str, false, "inject argument");
  330. }
  331. static void
  332. qualify_kvm(const char *const str)
  333. {
  334. if (strcmp(str, "vcpu") == 0) {
  335. #ifdef HAVE_LINUX_KVM_H
  336. if (os_release >= KERNEL_VERSION(4, 16, 0))
  337. kvm_run_structure_decoder_init();
  338. else
  339. error_msg("-e kvm=vcpu option needs"
  340. " Linux 4.16.0 or higher");
  341. #else
  342. error_msg("-e kvm=vcpu option is not implemented"
  343. " for this architecture");
  344. #endif
  345. } else {
  346. error_msg_and_die("invalid -e kvm= argument: '%s'", str);
  347. }
  348. }
  349. static const struct qual_options {
  350. const char *name;
  351. void (*qualify)(const char *);
  352. } qual_options[] = {
  353. { "trace", qualify_trace },
  354. { "t", qualify_trace },
  355. { "abbrev", qualify_abbrev },
  356. { "a", qualify_abbrev },
  357. { "verbose", qualify_verbose },
  358. { "v", qualify_verbose },
  359. { "raw", qualify_raw },
  360. { "x", qualify_raw },
  361. { "signal", qualify_signals },
  362. { "signals", qualify_signals },
  363. { "s", qualify_signals },
  364. { "read", qualify_read },
  365. { "reads", qualify_read },
  366. { "r", qualify_read },
  367. { "write", qualify_write },
  368. { "writes", qualify_write },
  369. { "w", qualify_write },
  370. { "fault", qualify_fault },
  371. { "inject", qualify_inject },
  372. { "kvm", qualify_kvm },
  373. };
  374. void
  375. qualify(const char *str)
  376. {
  377. const struct qual_options *opt = qual_options;
  378. for (unsigned int i = 0; i < ARRAY_SIZE(qual_options); ++i) {
  379. const char *name = qual_options[i].name;
  380. const size_t len = strlen(name);
  381. const char *val = str_strip_prefix_len(str, name, len);
  382. if (val == str || *val != '=')
  383. continue;
  384. str = val + 1;
  385. opt = &qual_options[i];
  386. break;
  387. }
  388. opt->qualify(str);
  389. }
  390. unsigned int
  391. qual_flags(const unsigned int scno)
  392. {
  393. return (is_number_in_set_array(scno, trace_set, current_personality)
  394. ? QUAL_TRACE : 0)
  395. | (is_number_in_set_array(scno, abbrev_set, current_personality)
  396. ? QUAL_ABBREV : 0)
  397. | (is_number_in_set_array(scno, verbose_set, current_personality)
  398. ? QUAL_VERBOSE : 0)
  399. | (is_number_in_set_array(scno, raw_set, current_personality)
  400. ? QUAL_RAW : 0)
  401. | (is_number_in_set_array(scno, inject_set, current_personality)
  402. ? QUAL_INJECT : 0);
  403. }