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

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