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.

basic_filters.c 9.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  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. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * 3. The name of the author may not be used to endorse or promote products
  15. * derived from this software without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  18. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  19. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  20. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  21. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  22. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  23. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  24. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  26. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27. */
  28. #include "defs.h"
  29. #include <regex.h>
  30. #include "filter.h"
  31. #include "number_set.h"
  32. #include "xstring.h"
  33. /**
  34. * Checks whether a @-separated personality specification suffix is present.
  35. * Personality suffix is a one of strings stored in personality_designators
  36. * array.
  37. *
  38. * @param[in] s Specification string to check.
  39. * @param[out] p Where to store personality number if it is found.
  40. * @return If personality is found, the provided string is copied without
  41. * suffix and returned as a result (callee should de-alllocate it
  42. * with free() after use), and personality number is written to p.
  43. * Otherwise, NULL is returned and p is untouched.
  44. */
  45. static char *
  46. qualify_syscall_separate_personality(const char *s, unsigned int *p)
  47. {
  48. char *pos = strchr(s, '@');
  49. if (!pos)
  50. return NULL;
  51. for (unsigned int i = 0; i < SUPPORTED_PERSONALITIES; i++) {
  52. if (!strcmp(pos + 1, personality_designators[i])) {
  53. *p = i;
  54. return xstrndup(s, pos - s);
  55. }
  56. }
  57. error_msg_and_help("incorrect personality designator '%s'"
  58. " in qualification '%s'", pos + 1, s);
  59. }
  60. static bool
  61. qualify_syscall_number_personality(int n, unsigned int p,
  62. struct number_set *set)
  63. {
  64. if ((unsigned int) n >= nsyscall_vec[p])
  65. return false;
  66. add_number_to_set_array(n, set, p);
  67. return true;
  68. }
  69. static bool
  70. qualify_syscall_number(const char *s, struct number_set *set)
  71. {
  72. unsigned int p;
  73. char *num_str = qualify_syscall_separate_personality(s, &p);
  74. int n;
  75. if (num_str) {
  76. n = string_to_uint(num_str);
  77. free(num_str);
  78. if (n < 0)
  79. return false;
  80. return qualify_syscall_number_personality(n, p, set);
  81. }
  82. n = string_to_uint(s);
  83. if (n < 0)
  84. return false;
  85. bool done = false;
  86. for (p = 0; p < SUPPORTED_PERSONALITIES; ++p)
  87. done |= qualify_syscall_number_personality(n, p, set);
  88. return done;
  89. }
  90. static void
  91. regerror_msg_and_die(int errcode, const regex_t *preg,
  92. const char *str, const char *pattern)
  93. {
  94. char buf[512];
  95. regerror(errcode, preg, buf, sizeof(buf));
  96. error_msg_and_die("%s: %s: %s", str, pattern, buf);
  97. }
  98. static bool
  99. qualify_syscall_regex(const char *s, struct number_set *set)
  100. {
  101. regex_t preg;
  102. int rc;
  103. if ((rc = regcomp(&preg, s, REG_EXTENDED | REG_NOSUB)) != 0)
  104. regerror_msg_and_die(rc, &preg, "regcomp", s);
  105. bool found = false;
  106. for (unsigned int p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
  107. for (unsigned int i = 0; i < nsyscall_vec[p]; ++i) {
  108. if (!sysent_vec[p][i].sys_name)
  109. continue;
  110. rc = regexec(&preg, sysent_vec[p][i].sys_name,
  111. 0, NULL, 0);
  112. if (rc == REG_NOMATCH) {
  113. char name_buf[128];
  114. char *pos = stpcpy(name_buf,
  115. sysent_vec[p][i].sys_name);
  116. (void) xappendstr(name_buf, pos, "@%s",
  117. personality_designators[p]);
  118. rc = regexec(&preg, name_buf, 0, NULL, 0);
  119. }
  120. if (rc == REG_NOMATCH)
  121. continue;
  122. else if (rc)
  123. regerror_msg_and_die(rc, &preg, "regexec", s);
  124. add_number_to_set_array(i, set, p);
  125. found = true;
  126. }
  127. }
  128. regfree(&preg);
  129. return found;
  130. }
  131. static unsigned int
  132. lookup_class(const char *s)
  133. {
  134. static const struct {
  135. const char *name;
  136. unsigned int value;
  137. } syscall_class[] = {
  138. { "%desc", TRACE_DESC },
  139. { "%file", TRACE_FILE },
  140. { "%memory", TRACE_MEMORY },
  141. { "%process", TRACE_PROCESS },
  142. { "%signal", TRACE_SIGNAL },
  143. { "%ipc", TRACE_IPC },
  144. { "%network", TRACE_NETWORK },
  145. { "%stat", TRACE_STAT },
  146. { "%lstat", TRACE_LSTAT },
  147. { "%fstat", TRACE_FSTAT },
  148. { "%%stat", TRACE_STAT_LIKE },
  149. { "%statfs", TRACE_STATFS },
  150. { "%fstatfs", TRACE_FSTATFS },
  151. { "%%statfs", TRACE_STATFS_LIKE },
  152. { "%pure", TRACE_PURE },
  153. /* legacy class names */
  154. { "desc", TRACE_DESC },
  155. { "file", TRACE_FILE },
  156. { "memory", TRACE_MEMORY },
  157. { "process", TRACE_PROCESS },
  158. { "signal", TRACE_SIGNAL },
  159. { "ipc", TRACE_IPC },
  160. { "network", TRACE_NETWORK },
  161. };
  162. for (unsigned int i = 0; i < ARRAY_SIZE(syscall_class); ++i) {
  163. if (strcmp(s, syscall_class[i].name) == 0)
  164. return syscall_class[i].value;
  165. }
  166. return 0;
  167. }
  168. static bool
  169. qualify_syscall_class(const char *s, struct number_set *set)
  170. {
  171. const unsigned int n = lookup_class(s);
  172. if (!n)
  173. return false;
  174. for (unsigned int p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
  175. for (unsigned int i = 0; i < nsyscall_vec[p]; ++i) {
  176. if (sysent_vec[p][i].sys_name &&
  177. (sysent_vec[p][i].sys_flags & n) == n)
  178. add_number_to_set_array(i, set, p);
  179. }
  180. }
  181. return true;
  182. }
  183. kernel_long_t
  184. scno_by_name(const char *s, unsigned int p, kernel_long_t start)
  185. {
  186. if (p >= SUPPORTED_PERSONALITIES)
  187. return -1;
  188. for (kernel_ulong_t i = start; i < nsyscall_vec[p]; ++i) {
  189. if (sysent_vec[p][i].sys_name &&
  190. strcmp(s, sysent_vec[p][i].sys_name) == 0)
  191. return i;
  192. }
  193. return -1;
  194. }
  195. static bool
  196. qualify_syscall_name_personality(const char *s, unsigned int p,
  197. struct number_set *set)
  198. {
  199. bool found = false;
  200. for (kernel_long_t scno = 0; (scno = scno_by_name(s, p, scno)) >= 0;
  201. ++scno) {
  202. add_number_to_set_array(scno, set, p);
  203. found = true;
  204. }
  205. return found;
  206. }
  207. static bool
  208. qualify_syscall_name(const char *s, struct number_set *set)
  209. {
  210. unsigned int p;
  211. char *name_str = qualify_syscall_separate_personality(s, &p);
  212. bool found = false;
  213. if (name_str) {
  214. found = qualify_syscall_name_personality(name_str, p, set);
  215. free(name_str);
  216. return found;
  217. }
  218. for (p = 0; p < SUPPORTED_PERSONALITIES; ++p)
  219. found |= qualify_syscall_name_personality(s, p, set);
  220. return found;
  221. }
  222. static bool
  223. qualify_syscall(const char *token, struct number_set *set)
  224. {
  225. bool ignore_fail = false;
  226. while (*token == '?') {
  227. token++;
  228. ignore_fail = true;
  229. }
  230. if (*token >= '0' && *token <= '9')
  231. return qualify_syscall_number(token, set) || ignore_fail;
  232. if (*token == '/')
  233. return qualify_syscall_regex(token + 1, set) || ignore_fail;
  234. return qualify_syscall_class(token, set)
  235. || qualify_syscall_name(token, set)
  236. || ignore_fail;
  237. }
  238. /*
  239. * Add syscall numbers to SETs for each supported personality
  240. * according to STR specification.
  241. */
  242. void
  243. qualify_syscall_tokens(const char *const str, struct number_set *const set)
  244. {
  245. /* Clear all sets. */
  246. clear_number_set_array(set, SUPPORTED_PERSONALITIES);
  247. /*
  248. * Each leading ! character means inversion
  249. * of the remaining specification.
  250. */
  251. const char *s = str;
  252. while (*s == '!') {
  253. invert_number_set_array(set, SUPPORTED_PERSONALITIES);
  254. ++s;
  255. }
  256. if (strcmp(s, "none") == 0) {
  257. /*
  258. * No syscall numbers are added to sets.
  259. * Subsequent is_number_in_set* invocations
  260. * will return set[p]->not.
  261. */
  262. return;
  263. } else if (strcmp(s, "all") == 0) {
  264. /* "all" == "!none" */
  265. invert_number_set_array(set, SUPPORTED_PERSONALITIES);
  266. return;
  267. }
  268. /*
  269. * Split the string into comma separated tokens.
  270. * For each token, call qualify_syscall that will take care
  271. * if adding appropriate syscall numbers to sets.
  272. * The absence of tokens or a negative return code
  273. * from qualify_syscall is a fatal error.
  274. */
  275. char *copy = xstrdup(s);
  276. char *saveptr = NULL;
  277. bool done = false;
  278. for (const char *token = strtok_r(copy, ",", &saveptr);
  279. token; token = strtok_r(NULL, ",", &saveptr)) {
  280. done = qualify_syscall(token, set);
  281. if (!done)
  282. error_msg_and_die("invalid system call '%s'", token);
  283. }
  284. free(copy);
  285. if (!done)
  286. error_msg_and_die("invalid system call '%s'", str);
  287. }
  288. /*
  289. * Add numbers to SET according to STR specification.
  290. */
  291. void
  292. qualify_tokens(const char *const str, struct number_set *const set,
  293. string_to_uint_func func, const char *const name)
  294. {
  295. /* Clear the set. */
  296. clear_number_set_array(set, 1);
  297. /*
  298. * Each leading ! character means inversion
  299. * of the remaining specification.
  300. */
  301. const char *s = str;
  302. while (*s == '!') {
  303. invert_number_set_array(set, 1);
  304. ++s;
  305. }
  306. if (strcmp(s, "none") == 0) {
  307. /*
  308. * No numbers are added to the set.
  309. * Subsequent is_number_in_set* invocations
  310. * will return set->not.
  311. */
  312. return;
  313. } else if (strcmp(s, "all") == 0) {
  314. /* "all" == "!none" */
  315. invert_number_set_array(set, 1);
  316. return;
  317. }
  318. /*
  319. * Split the string into comma separated tokens.
  320. * For each token, find out the corresponding number
  321. * by calling FUNC, and add that number to the set.
  322. * The absence of tokens or a negative answer
  323. * from FUNC is a fatal error.
  324. */
  325. char *copy = xstrdup(s);
  326. char *saveptr = NULL;
  327. int number = -1;
  328. for (const char *token = strtok_r(copy, ",", &saveptr);
  329. token; token = strtok_r(NULL, ",", &saveptr)) {
  330. number = func(token);
  331. if (number < 0)
  332. error_msg_and_die("invalid %s '%s'", name, token);
  333. add_number_to_set(number, set);
  334. }
  335. free(copy);
  336. if (number < 0)
  337. error_msg_and_die("invalid %s '%s'", name, str);
  338. }