Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2016 Dmitry V. Levin <ldv@altlinux.org>
3 : : * Copyright (c) 2016-2017 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 : :
29 : : #include "defs.h"
30 : : #include "nsig.h"
31 : : #include <regex.h>
32 : :
33 : : const struct syscall_class syscall_classes[] = {
34 : : { "desc", TRACE_DESC },
35 : : { "file", TRACE_FILE },
36 : : { "memory", TRACE_MEMORY },
37 : : { "process", TRACE_PROCESS },
38 : : { "signal", TRACE_SIGNAL },
39 : : { "ipc", TRACE_IPC },
40 : : { "network", TRACE_NETWORK },
41 : : { "%desc", TRACE_DESC },
42 : : { "%file", TRACE_FILE },
43 : : { "%memory", TRACE_MEMORY },
44 : : { "%process", TRACE_PROCESS },
45 : : { "%signal", TRACE_SIGNAL },
46 : : { "%ipc", TRACE_IPC },
47 : : { "%network", TRACE_NETWORK },
48 : : { "%stat", TRACE_STAT },
49 : : { "%lstat", TRACE_LSTAT },
50 : : { "%fstat", TRACE_FSTAT },
51 : : { "%%stat", TRACE_STAT_LIKE },
52 : : { "%statfs", TRACE_STATFS },
53 : : { "%fstatfs", TRACE_FSTATFS },
54 : : { "%%statfs", TRACE_STATFS_LIKE },
55 : : {}
56 : : };
57 : :
58 : : typedef unsigned int number_slot_t;
59 : : #define BITS_PER_SLOT (sizeof(number_slot_t) * 8)
60 : :
61 : : struct number_set {
62 : : number_slot_t *vec;
63 : : unsigned int nslots;
64 : : bool not;
65 : : };
66 : :
67 : : struct number_set read_set;
68 : : struct number_set write_set;
69 : : struct number_set signal_set;
70 : :
71 : : static struct number_set abbrev_set[SUPPORTED_PERSONALITIES];
72 : : static struct number_set inject_set[SUPPORTED_PERSONALITIES];
73 : : static struct number_set raw_set[SUPPORTED_PERSONALITIES];
74 : : static struct number_set trace_set[SUPPORTED_PERSONALITIES];
75 : : static struct number_set verbose_set[SUPPORTED_PERSONALITIES];
76 : : #ifdef USE_LUAJIT
77 : : static struct number_set hook_entry_set[SUPPORTED_PERSONALITIES];
78 : : static struct number_set hook_exit_set[SUPPORTED_PERSONALITIES];
79 : : #endif
80 : :
81 : : static void
82 : : number_setbit(const unsigned int i, number_slot_t *const vec)
83 : : {
84 : 561396 : vec[i / BITS_PER_SLOT] |= (number_slot_t) 1 << (i % BITS_PER_SLOT);
85 : : }
86 : :
87 : : static bool
88 : : number_isset(const unsigned int i, const number_slot_t *const vec)
89 : : {
90 : 41447958 : return vec[i / BITS_PER_SLOT] & ((number_slot_t) 1 << (i % BITS_PER_SLOT));
91 : : }
92 : :
93 : : static void
94 : 561396 : reallocate_number_set(struct number_set *const set, const unsigned int new_nslots)
95 : : {
96 [ + + ]: 561396 : if (new_nslots <= set->nslots)
97 : 561396 : return;
98 : 105449 : set->vec = xreallocarray(set->vec, new_nslots, sizeof(*set->vec));
99 : 105449 : memset(set->vec + set->nslots, 0,
100 : 105449 : sizeof(*set->vec) * (new_nslots - set->nslots));
101 : 105449 : set->nslots = new_nslots;
102 : : }
103 : :
104 : : static void
105 : 561396 : add_number_to_set(const unsigned int number, struct number_set *const set)
106 : : {
107 : 561396 : reallocate_number_set(set, number / BITS_PER_SLOT + 1);
108 : 561396 : number_setbit(number, set->vec);
109 : 561396 : }
110 : :
111 : : bool
112 : 509459 : is_number_in_set(const unsigned int number, const struct number_set *const set)
113 : : {
114 : 301143936 : return ((number / BITS_PER_SLOT < set->nslots)
115 [ + + ][ + + ]: 226077625 : && number_isset(number, set->vec)) ^ set->not;
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
116 : : }
117 : :
118 : : typedef int (*string_to_uint_func)(const char *);
119 : :
120 : : /*
121 : : * Add numbers to SET according to STR specification.
122 : : */
123 : : static void
124 : 17980 : qualify_tokens(const char *const str, struct number_set *const set,
125 : : string_to_uint_func func, const char *const name)
126 : : {
127 : : /* Clear the set. */
128 [ + + ]: 17980 : if (set->nslots)
129 : 4 : memset(set->vec, 0, sizeof(*set->vec) * set->nslots);
130 : 17980 : set->not = false;
131 : :
132 : : /*
133 : : * Each leading ! character means inversion
134 : : * of the remaining specification.
135 : : */
136 : 17980 : const char *s = str;
137 : : handle_inversion:
138 [ + + ]: 39741 : while (*s == '!') {
139 : 10945 : set->not = !set->not;
140 : 21761 : ++s;
141 : : }
142 : :
143 [ + + ]: 28796 : if (strcmp(s, "none") == 0) {
144 : : /*
145 : : * No numbers are added to the set.
146 : : * Subsequent is_number_in_set invocations will return set->not.
147 : : */
148 : 17944 : return;
149 [ + + ][ + - ]: 11089 : } else if (strcmp(s, "all") == 0) {
[ + + ][ + + ]
150 : : s = "!none";
151 : : goto handle_inversion;
152 : : }
153 : :
154 : : /*
155 : : * Split the string into comma separated tokens.
156 : : * For each token, find out the corresponding number
157 : : * by calling FUNC, and add that number to the set.
158 : : * The absence of tokens or a negative answer
159 : : * from FUNC is a fatal error.
160 : : */
161 : 273 : char *copy = xstrdup(s);
162 : 273 : char *saveptr = NULL;
163 : : const char *token;
164 : 273 : int number = -1;
165 : :
166 [ + + ]: 4816 : for (token = strtok_r(copy, ",", &saveptr); token;
167 : 4543 : token = strtok_r(NULL, ",", &saveptr)) {
168 : 4571 : number = func(token);
169 [ + + ]: 4571 : if (number < 0) {
170 : 28 : error_msg_and_die("invalid %s '%s'", name, token);
171 : : }
172 : :
173 : 4543 : add_number_to_set(number, set);
174 : : }
175 : :
176 : 245 : free(copy);
177 : :
178 [ + + ]: 245 : if (number < 0) {
179 : 8 : error_msg_and_die("invalid %s '%s'", name, str);
180 : : }
181 : : }
182 : :
183 : : static int
184 : 399 : sigstr_to_uint(const char *s)
185 : : {
186 : : int i;
187 : :
188 [ + + ]: 399 : if (*s >= '0' && *s <= '9')
189 : 154 : return string_to_uint_upto(s, 255);
190 : :
191 [ + + ]: 245 : if (strncasecmp(s, "SIG", 3) == 0)
192 : 116 : s += 3;
193 : :
194 [ + + ]: 5535 : for (i = 0; i <= 255; ++i) {
195 : 5525 : const char *name = signame(i);
196 : :
197 [ + + ]: 5525 : if (strncasecmp(name, "SIG", 3) != 0)
198 : 1910 : continue;
199 : :
200 : 3615 : name += 3;
201 : :
202 [ + + ]: 3615 : if (strcasecmp(name, s) != 0)
203 : 3380 : continue;
204 : :
205 : 235 : return i;
206 : : }
207 : :
208 : : return -1;
209 : : }
210 : :
211 : : static bool
212 : 718 : qualify_syscall_number(const char *s, struct number_set *set)
213 : : {
214 : 718 : int n = string_to_uint(s);
215 [ + + ]: 718 : if (n < 0)
216 : : return false;
217 : :
218 : : unsigned int p;
219 : : bool done = false;
220 : :
221 [ + + ]: 2848 : for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
222 [ + + ]: 2136 : if ((unsigned) n >= nsyscall_vec[p]) {
223 : 24 : continue;
224 : : }
225 : 2112 : add_number_to_set(n, &set[p]);
226 : 2112 : done = true;
227 : : }
228 : :
229 : 712 : return done;
230 : : }
231 : :
232 : : static void
233 : 10 : regerror_msg_and_die(int errcode, const regex_t *preg,
234 : : const char *str, const char *pattern)
235 : : {
236 : : char buf[512];
237 : :
238 : 10 : regerror(errcode, preg, buf, sizeof(buf));
239 : 10 : error_msg_and_die("%s: %s: %s", str, pattern, buf);
240 : : }
241 : :
242 : : static bool
243 : 2520 : qualify_syscall_regex(const char *s, struct number_set *set)
244 : : {
245 : : regex_t preg;
246 : : int rc;
247 : :
248 [ + + ]: 2520 : if ((rc = regcomp(&preg, s, REG_EXTENDED | REG_NOSUB)) != 0)
249 : 10 : regerror_msg_and_die(rc, &preg, "regcomp", s);
250 : :
251 : : unsigned int p;
252 : : bool found = false;
253 [ + + ]: 10040 : for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
254 : : unsigned int i;
255 : :
256 [ + + ]: 3338300 : for (i = 0; i < nsyscall_vec[p]; ++i) {
257 [ + + ]: 3330770 : if (!sysent_vec[p][i].sys_name)
258 : 532120 : continue;
259 : 2798650 : rc = regexec(&preg, sysent_vec[p][i].sys_name,
260 : : 0, NULL, 0);
261 [ + + ]: 2798650 : if (rc == REG_NOMATCH)
262 : 2749806 : continue;
263 [ - + ]: 48844 : else if (rc)
264 : 0 : regerror_msg_and_die(rc, &preg, "regexec", s);
265 : 48844 : add_number_to_set(i, &set[p]);
266 : 48844 : found = true;
267 : : }
268 : : }
269 : :
270 : 2510 : regfree(&preg);
271 : 2510 : return found;
272 : : }
273 : :
274 : : static unsigned int
275 : 9222 : lookup_class(const char *s)
276 : : {
277 : : const struct syscall_class *c;
278 [ + + ]: 168803 : for (c = syscall_classes; c->name; ++c) {
279 [ + + ]: 164779 : if (strcmp(s, c->name) == 0) {
280 : 5198 : return c->value;
281 : : }
282 : : }
283 : :
284 : : return 0;
285 : : }
286 : :
287 : : static bool
288 : 9222 : qualify_syscall_class(const char *s, struct number_set *set)
289 : : {
290 : 9222 : const unsigned int n = lookup_class(s);
291 [ + + ]: 9222 : if (!n)
292 : : return false;
293 : :
294 : : unsigned int p;
295 [ + + ]: 20792 : for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
296 : : unsigned int i;
297 : :
298 [ + + ]: 6913340 : for (i = 0; i < nsyscall_vec[p]; ++i) {
299 [ + + ]: 6897746 : if (!sysent_vec[p][i].sys_name
300 [ + + ]: 5795770 : || (sysent_vec[p][i].sys_flags & n) != n) {
301 : 6636630 : continue;
302 : : }
303 : 261116 : add_number_to_set(i, &set[p]);
304 : : }
305 : : }
306 : :
307 : : return true;
308 : : }
309 : :
310 : : static bool
311 : 4024 : qualify_syscall_name(const char *s, struct number_set *set)
312 : : {
313 : : unsigned int p;
314 : 4024 : bool found = false;
315 : :
316 [ + + ]: 16096 : for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
317 : : unsigned int i;
318 : :
319 [ + + ]: 5351920 : for (i = 0; i < nsyscall_vec[p]; ++i) {
320 [ + + ]: 5339848 : if (!sysent_vec[p][i].sys_name
321 [ + + ]: 4486760 : || strcmp(s, sysent_vec[p][i].sys_name)) {
322 : 5329782 : continue;
323 : : }
324 : 10066 : add_number_to_set(i, &set[p]);
325 : 10066 : found = true;
326 : : }
327 : : }
328 : :
329 : 4024 : return found;
330 : : }
331 : :
332 : : static bool
333 : 12460 : qualify_syscall(const char *token, struct number_set *set)
334 : : {
335 : 12460 : bool ignore_fail = false;
336 : :
337 [ + + ]: 13712 : while (*token == '?') {
338 : 1252 : token++;
339 : 1252 : ignore_fail = true;
340 : : }
341 [ + + ]: 12460 : if (*token >= '0' && *token <= '9')
342 [ + + ][ + - ]: 718 : return qualify_syscall_number(token, set) || ignore_fail;
343 [ + + ]: 11742 : if (*token == '/')
344 [ + + ][ + - ]: 2520 : return qualify_syscall_regex(token + 1, set) || ignore_fail;
345 : 18444 : return qualify_syscall_class(token, set)
346 [ + + ]: 4024 : || qualify_syscall_name(token, set)
347 [ + + ][ + + ]: 9884 : || ignore_fail;
348 : : }
349 : :
350 : : /*
351 : : * Add syscall numbers to SETs for each supported personality
352 : : * according to STR specification.
353 : : */
354 : : static void
355 : 46483 : qualify_syscall_tokens(const char *const str, struct number_set *const set,
356 : : const char *const name)
357 : : {
358 : : /* Clear all sets. */
359 : : unsigned int p;
360 [ + + ]: 185932 : for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
361 [ + + ]: 139449 : if (set[p].nslots)
362 : 6 : memset(set[p].vec, 0,
363 : : sizeof(*set[p].vec) * set[p].nslots);
364 : 139449 : set[p].not = false;
365 : : }
366 : :
367 : : /*
368 : : * Each leading ! character means inversion
369 : : * of the remaining specification.
370 : : */
371 : : const char *s = str;
372 : : handle_inversion:
373 [ + + ]: 112143 : while (*s == '!') {
374 [ + + ]: 131496 : for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
375 : 98622 : set[p].not = !set[p].not;
376 : : }
377 : 65660 : ++s;
378 : : }
379 : :
380 [ + + ]: 79269 : if (strcmp(s, "none") == 0) {
381 : : /*
382 : : * No syscall numbers are added to sets.
383 : : * Subsequent is_number_in_set invocations
384 : : * will return set[p]->not.
385 : : */
386 : 46409 : return;
387 [ + + ][ + + ]: 43664 : } else if (strcmp(s, "all") == 0) {
[ + + ][ + + ]
388 : : s = "!none";
389 : : goto handle_inversion;
390 : : }
391 : :
392 : : /*
393 : : * Split the string into comma separated tokens.
394 : : * For each token, call qualify_syscall that will take care
395 : : * if adding appropriate syscall numbers to sets.
396 : : * The absence of tokens or a negative return code
397 : : * from qualify_syscall is a fatal error.
398 : : */
399 : 10878 : char *copy = xstrdup(s);
400 : 10878 : char *saveptr = NULL;
401 : : const char *token;
402 : 10878 : bool done = false;
403 : :
404 [ + + ]: 23276 : for (token = strtok_r(copy, ",", &saveptr); token;
405 : 12398 : token = strtok_r(NULL, ",", &saveptr)) {
406 : 12460 : done = qualify_syscall(token, set);
407 [ + + ]: 12450 : if (!done) {
408 : 52 : error_msg_and_die("invalid %s '%s'", name, token);
409 : : }
410 : : }
411 : :
412 : 10816 : free(copy);
413 : :
414 [ + + ]: 10816 : if (!done) {
415 : 12 : error_msg_and_die("invalid %s '%s'", name, str);
416 : : }
417 : : }
418 : :
419 : : static int
420 : 750 : find_errno_by_name(const char *name)
421 : : {
422 : : unsigned int i;
423 : :
424 [ + + ]: 48508 : for (i = 1; i < nerrnos; ++i) {
425 [ + + ][ + + ]: 48456 : if (errnoent[i] && (strcasecmp(name, errnoent[i]) == 0))
426 : 698 : return i;
427 : : }
428 : :
429 : : return -1;
430 : : }
431 : :
432 : : static bool
433 : 2634 : parse_inject_token(const char *const token, struct inject_opts *const fopts,
434 : : const bool fault_tokens_only)
435 : : {
436 : : const char *val;
437 : : int intval;
438 : :
439 [ + + ]: 2634 : if ((val = STR_STRIP_PREFIX(token, "when=")) != token) {
440 : : /*
441 : : * == 1+1
442 : : * F == F+0
443 : : * F+ == F+1
444 : : * F+S
445 : : */
446 : : char *end;
447 : 1470 : intval = string_to_uint_ex(val, &end, 0xffff, "+");
448 [ + + ]: 1470 : if (intval < 1)
449 : 104 : return false;
450 : :
451 : 1414 : fopts->first = intval;
452 : :
453 [ + + ]: 1414 : if (*end) {
454 : 1298 : val = end + 1;
455 [ + + ]: 1298 : if (*val) {
456 : : /* F+S */
457 : 1200 : intval = string_to_uint_upto(val, 0xffff);
458 [ + + ]: 1200 : if (intval < 1)
459 : : return false;
460 : 1152 : fopts->step = intval;
461 : : } else {
462 : : /* F+ == F+1 */
463 : 98 : fopts->step = 1;
464 : : }
465 : : } else {
466 : : /* F == F+0 */
467 : 1366 : fopts->step = 0;
468 : : }
469 [ + + ]: 1164 : } else if ((val = STR_STRIP_PREFIX(token, "error=")) != token) {
470 [ + + ]: 1114 : if (fopts->rval != INJECT_OPTS_RVAL_DEFAULT)
471 : : return false;
472 : 1106 : intval = string_to_uint_upto(val, MAX_ERRNO_VALUE);
473 [ + + ]: 1106 : if (intval < 0)
474 : 750 : intval = find_errno_by_name(val);
475 [ + + ]: 1106 : if (intval < 1)
476 : : return false;
477 : 1054 : fopts->rval = -intval;
478 [ + + ]: 50 : } else if (!fault_tokens_only
479 [ + + ]: 36 : && (val = STR_STRIP_PREFIX(token, "retval=")) != token) {
480 [ + + ]: 16 : if (fopts->rval != INJECT_OPTS_RVAL_DEFAULT)
481 : : return false;
482 : 12 : intval = string_to_uint(val);
483 [ + + ]: 12 : if (intval < 0)
484 : : return false;
485 : 10 : fopts->rval = intval;
486 [ + + ]: 34 : } else if (!fault_tokens_only
487 [ + + ]: 20 : && (val = STR_STRIP_PREFIX(token, "signal=")) != token) {
488 : 10 : intval = sigstr_to_uint(val);
489 [ + + ]: 10 : if (intval < 1 || intval > NSIG_BYTES * 8)
490 : : return false;
491 : 6 : fopts->signo = intval;
492 : : } else {
493 : : return false;
494 : : }
495 : :
496 : : return true;
497 : : }
498 : :
499 : : static char *
500 : 1752 : parse_inject_expression(const char *const s, char **buf,
501 : : struct inject_opts *const fopts,
502 : : const bool fault_tokens_only)
503 : : {
504 : 1752 : char *saveptr = NULL;
505 : 1752 : char *name = NULL;
506 : : char *token;
507 : :
508 : 1752 : *buf = xstrdup(s);
509 [ + + ]: 5924 : for (token = strtok_r(*buf, ":", &saveptr); token;
510 : 4172 : token = strtok_r(NULL, ":", &saveptr)) {
511 [ + + ]: 4370 : if (!name)
512 : : name = token;
513 [ + + ]: 2634 : else if (!parse_inject_token(token, fopts, fault_tokens_only))
514 : : goto parse_error;
515 : : }
516 : :
517 [ + + ]: 1554 : if (name)
518 : 1538 : return name;
519 : :
520 : : parse_error:
521 : 214 : free(*buf);
522 : 214 : return *buf = NULL;
523 : : }
524 : :
525 : : static void
526 : 47 : qualify_read(const char *const str)
527 : : {
528 : 47 : qualify_tokens(str, &read_set, string_to_uint, "descriptor");
529 : 37 : }
530 : :
531 : : static void
532 : 49 : qualify_write(const char *const str)
533 : : {
534 : 49 : qualify_tokens(str, &write_set, string_to_uint, "descriptor");
535 : 39 : }
536 : :
537 : : static void
538 : 17884 : qualify_signals(const char *const str)
539 : : {
540 : 17884 : qualify_tokens(str, &signal_set, sigstr_to_uint, "signal");
541 : 17868 : }
542 : :
543 : : static void
544 : 20304 : qualify_trace(const char *const str)
545 : : {
546 : 20304 : qualify_syscall_tokens(str, trace_set, "system call");
547 : 20274 : }
548 : :
549 : : static void
550 : 13425 : qualify_abbrev(const char *const str)
551 : : {
552 : 13425 : qualify_syscall_tokens(str, abbrev_set, "system call");
553 : 13425 : }
554 : :
555 : : static void
556 : 10860 : qualify_verbose(const char *const str)
557 : : {
558 : 10860 : qualify_syscall_tokens(str, verbose_set, "system call");
559 : 10860 : }
560 : :
561 : : static void
562 : 404 : qualify_raw(const char *const str)
563 : : {
564 : 404 : qualify_syscall_tokens(str, raw_set, "system call");
565 : 404 : }
566 : :
567 : : static void
568 : 1752 : qualify_inject_common(const char *const str,
569 : : const bool fault_tokens_only,
570 : : const char *const description)
571 : : {
572 : 1752 : struct inject_opts opts = {
573 : : .first = 1,
574 : : .step = 1,
575 : : .rval = INJECT_OPTS_RVAL_DEFAULT,
576 : : .signo = 0
577 : : };
578 : 1752 : char *buf = NULL;
579 : 1752 : char *name = parse_inject_expression(str, &buf, &opts, fault_tokens_only);
580 [ + + ]: 1752 : if (!name) {
581 : 214 : error_msg_and_die("invalid %s '%s'", description, str);
582 : : }
583 : :
584 : : /* If neither of retval, error, or signal is specified, then ... */
585 [ + + ][ + + ]: 1538 : if (opts.rval == INJECT_OPTS_RVAL_DEFAULT && !opts.signo) {
586 [ + + ]: 484 : if (fault_tokens_only) {
587 : : /* in fault= syntax the default error code is ENOSYS. */
588 : 436 : opts.rval = -ENOSYS;
589 : : } else {
590 : : /* in inject= syntax this is not allowed. */
591 : 48 : error_msg_and_die("invalid %s '%s'", description, str);
592 : : }
593 : : }
594 : :
595 : : struct number_set tmp_set[SUPPORTED_PERSONALITIES];
596 : 1490 : memset(tmp_set, 0, sizeof(tmp_set));
597 : 1490 : qualify_syscall_tokens(name, tmp_set, description);
598 : :
599 : 1446 : free(buf);
600 : :
601 : : /*
602 : : * Initialize inject_vec accourding to tmp_set.
603 : : * Merge tmp_set into inject_set.
604 : : */
605 : : unsigned int p;
606 [ + + ]: 5784 : for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
607 [ + + ][ + + ]: 4338 : if (!tmp_set[p].nslots && !tmp_set[p].not) {
608 : 48 : continue;
609 : : }
610 : :
611 [ + + ]: 4290 : if (!inject_vec[p]) {
612 : 4290 : inject_vec[p] = xcalloc(nsyscall_vec[p],
613 : : sizeof(*inject_vec[p]));
614 : : }
615 : :
616 : : unsigned int i;
617 [ + + ]: 1901900 : for (i = 0; i < nsyscall_vec[p]; ++i) {
618 [ + + ]: 1897610 : if (is_number_in_set(i, &tmp_set[p])) {
619 : 221276 : add_number_to_set(i, &inject_set[p]);
620 : 221276 : inject_vec[p][i] = opts;
621 : : }
622 : : }
623 : :
624 : 4290 : free(tmp_set[p].vec);
625 : : }
626 : 1446 : }
627 : :
628 : : static void
629 : 1584 : qualify_fault(const char *const str)
630 : : {
631 : 1584 : qualify_inject_common(str, true, "fault argument");
632 : 1438 : }
633 : :
634 : : static void
635 : 168 : qualify_inject(const char *const str)
636 : : {
637 : 168 : qualify_inject_common(str, false, "inject argument");
638 : 8 : }
639 : :
640 : : static const struct qual_options {
641 : : const char *name;
642 : : void (*qualify)(const char *);
643 : : } qual_options[] = {
644 : : { "trace", qualify_trace },
645 : : { "t", qualify_trace },
646 : : { "abbrev", qualify_abbrev },
647 : : { "a", qualify_abbrev },
648 : : { "verbose", qualify_verbose },
649 : : { "v", qualify_verbose },
650 : : { "raw", qualify_raw },
651 : : { "x", qualify_raw },
652 : : { "signal", qualify_signals },
653 : : { "signals", qualify_signals },
654 : : { "s", qualify_signals },
655 : : { "read", qualify_read },
656 : : { "reads", qualify_read },
657 : : { "r", qualify_read },
658 : : { "write", qualify_write },
659 : : { "writes", qualify_write },
660 : : { "w", qualify_write },
661 : : { "fault", qualify_fault },
662 : : { "inject", qualify_inject },
663 : : };
664 : :
665 : : void
666 : 64725 : qualify(const char *str)
667 : : {
668 : 64725 : const struct qual_options *opt = qual_options;
669 : : unsigned int i;
670 : :
671 [ + + ]: 438472 : for (i = 0; i < ARRAY_SIZE(qual_options); ++i) {
672 : 431798 : const char *name = qual_options[i].name;
673 : 431798 : const size_t len = strlen(name);
674 : 431798 : const char *val = str_strip_prefix_len(str, name, len);
675 : :
676 [ + + ][ + + ]: 431798 : if (val == str || *val != '=')
677 : 373747 : continue;
678 : 58051 : str = val + 1;
679 : 58051 : opt = &qual_options[i];
680 : 58051 : break;
681 : : }
682 : :
683 : 64725 : opt->qualify(str);
684 : 64353 : }
685 : :
686 : : unsigned int
687 : 37278426 : qual_flags(const unsigned int scno)
688 : : {
689 : 74556852 : return (is_number_in_set(scno, &trace_set[current_personality])
690 : 37278426 : ? QUAL_TRACE : 0)
691 : 74556852 : | (is_number_in_set(scno, &abbrev_set[current_personality])
692 [ + + ]: 37278426 : ? QUAL_ABBREV : 0)
693 : 74556852 : | (is_number_in_set(scno, &verbose_set[current_personality])
694 [ + + ]: 37278426 : ? QUAL_VERBOSE : 0)
695 : 74556852 : | (is_number_in_set(scno, &raw_set[current_personality])
696 [ + + ]: 37278426 : ? QUAL_RAW : 0)
697 : 74556852 : | (is_number_in_set(scno, &inject_set[current_personality])
698 [ + + ]: 37278426 : ? QUAL_INJECT : 0)
699 : : #ifdef USE_LUAJIT
700 : 74556852 : | (is_number_in_set(scno, &hook_entry_set[current_personality])
701 [ + + ]: 37278426 : ? QUAL_HOOK_ENTRY : 0)
702 : 74556852 : | (is_number_in_set(scno, &hook_exit_set[current_personality])
703 [ + + ]: 37278426 : ? QUAL_HOOK_EXIT : 0)
704 : : #endif
705 : : ;
706 : : }
707 : :
708 : : #ifdef USE_LUAJIT
709 : : void
710 : 13439 : set_hook_qual(unsigned int scno, unsigned int pers, bool entry_hook, bool exit_hook)
711 : : {
712 [ + + ]: 13439 : if (entry_hook)
713 : 13397 : add_number_to_set(scno, &hook_entry_set[pers]);
714 [ + + ]: 13439 : if (exit_hook)
715 : 42 : add_number_to_set(scno, &hook_exit_set[pers]);
716 : 13439 : }
717 : : #endif
|