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 12KB

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