2 * Functions for handling the system call tables.
11 #include "arch-syscalls.h"
17 #include "utils.h" // ARRAY_SIZE
19 unsigned long syscalls_todo
= 0;
23 int search_syscall_table(const struct syscalltable
*table
, unsigned int nr_syscalls
, const char *arg
)
28 for (i
= 0; i
< nr_syscalls
; i
++) {
29 if (strcmp(arg
, table
[i
].entry
->name
) == 0) {
30 //debugf("Found %s at %u\n", table[i].entry->name, i);
38 void validate_specific_syscall(const struct syscalltable
*table
, int call
)
40 struct syscallentry
*entry
;
45 entry
= table
[call
].entry
;
47 if (entry
->flags
& AVOID_SYSCALL
)
48 output(0, "%s is marked as AVOID. Skipping\n", entry
->name
);
50 if (entry
->flags
& NI_SYSCALL
)
51 output(0, "%s is NI_SYSCALL. Skipping\n", entry
->name
);
54 int validate_specific_syscall_silent(const struct syscalltable
*table
, int call
)
56 struct syscallentry
*entry
;
61 entry
= table
[call
].entry
;
63 if (entry
->flags
& AVOID_SYSCALL
)
66 if (entry
->flags
& NI_SYSCALL
)
72 void activate_syscall_in_table(unsigned int calln
, unsigned int *nr_active
, const struct syscalltable
*table
, int *active_syscall
)
74 struct syscallentry
*entry
= table
[calln
].entry
;
76 //Check if the call is activated already, and activate it only if needed
77 if (entry
->active_number
== 0) {
79 if ((*nr_active
+ 1) > MAX_NR_SYSCALL
) {
80 output(0, "[tables] MAX_NR_SYSCALL needs to be increased. More syscalls than active table can fit.\n");
85 active_syscall
[*nr_active
] = calln
+ 1;
87 entry
->active_number
= *nr_active
;
91 void deactivate_syscall_in_table(unsigned int calln
, unsigned int *nr_active
, const struct syscalltable
*table
, int *active_syscall
)
93 struct syscallentry
*entry
;
95 entry
= table
[calln
].entry
;
97 //Check if the call is activated already, and deactivate it only if needed
98 if ((entry
->active_number
!= 0) && (*nr_active
> 0)) {
101 for (i
= entry
->active_number
- 1; i
< *nr_active
- 1; i
++) {
102 active_syscall
[i
] = active_syscall
[i
+ 1];
103 table
[active_syscall
[i
] - 1].entry
->active_number
= i
+ 1;
105 //The last step is to erase the last item.
106 active_syscall
[*nr_active
- 1] = 0;
108 entry
->active_number
= 0;
112 void count_syscalls_enabled(void)
114 if (biarch
== TRUE
) {
115 output(0, "32-bit syscalls: %d enabled, %d disabled. "
116 "64-bit syscalls: %d enabled, %d disabled.\n",
117 shm
->nr_active_32bit_syscalls
, max_nr_32bit_syscalls
- shm
->nr_active_32bit_syscalls
,
118 shm
->nr_active_64bit_syscalls
, max_nr_64bit_syscalls
- shm
->nr_active_64bit_syscalls
);
120 output(0, "Enabled %d syscalls. Disabled %d syscalls.\n",
121 shm
->nr_active_syscalls
, max_nr_syscalls
- shm
->nr_active_syscalls
);
125 void init_syscalls(void)
128 init_syscalls_biarch();
130 init_syscalls_uniarch();
133 bool no_syscalls_enabled(void)
135 if (biarch
== TRUE
) {
136 if ((shm
->nr_active_32bit_syscalls
== 0) && (shm
->nr_active_64bit_syscalls
== 0))
143 if (shm
->nr_active_syscalls
== 0)
149 /* Make sure there's at least one syscall enabled. */
150 int validate_syscall_tables(void)
152 if (biarch
== TRUE
) {
155 ret
= validate_syscall_table_32();
156 ret
|= validate_syscall_table_64();
161 if (shm
->nr_active_syscalls
== 0)
167 static void check_syscall(struct syscallentry
*entry
)
169 /* check that we have a name set. */
170 #define CHECK(NUMARGS, ARGNUM, ARGTYPE, ARGNAME) \
171 if (entry->num_args > 0) { \
172 if (entry->num_args > NUMARGS) { \
173 if (entry->ARGNAME == NULL) { \
174 outputerr("arg %d of %s has no name\n", ARGNUM, entry->name); \
175 exit(EXIT_FAILURE); \
180 CHECK(0, 1, arg1type, arg1name);
181 CHECK(1, 2, arg2type
, arg2name
);
182 CHECK(2, 3, arg3type
, arg3name
);
183 CHECK(3, 4, arg4type
, arg4name
);
184 CHECK(4, 5, arg5type
, arg5name
);
185 CHECK(5, 6, arg6type
, arg6name
);
187 /* check if we have a type. */
188 /* note: not enabled by default, because we haven't annotated everything yet. */
190 #define CHECK(NUMARGS, ARGNUM, ARGTYPE, ARGNAME) \
191 if (entry->num_args > 0) { \
192 if (entry->num_args > NUMARGS) { \
193 if (entry->ARGTYPE == ARG_UNDEFINED) { \
194 outputerr("%s has an undefined argument type for arg1 (%s)!\n", entry->name, entry->ARGNAME); \
199 /* CHECK(0, 1, arg1type, arg1name);
200 CHECK(1, 2, arg2type, arg2name);
201 CHECK(2, 3, arg3type, arg3name);
202 CHECK(3, 4, arg4type, arg4name);
203 CHECK(4, 5, arg5type, arg5name);
204 CHECK(5, 6, arg6type, arg6name);
208 static void sanity_check(const struct syscalltable
*table
, unsigned int nr
)
212 for (i
= 0; i
< nr
; i
++)
213 check_syscall(table
[i
].entry
);
216 void sanity_check_tables(void)
218 if (biarch
== TRUE
) {
219 sanity_check(syscalls_32bit
, max_nr_32bit_syscalls
);
220 sanity_check(syscalls_64bit
, max_nr_64bit_syscalls
);
225 sanity_check(syscalls
, max_nr_syscalls
);
228 void mark_all_syscalls_active(void)
230 outputstd("Marking all syscalls as enabled.\n");
233 mark_all_syscalls_active_biarch();
235 mark_all_syscalls_active_uniarch();
238 void check_user_specified_arch(const char *arg
, char **arg_name
, bool *only_64bit
, bool *only_32bit
)
240 //Check if the arch is specified
241 char *arg_arch
= strstr(arg
,",");
243 if (arg_arch
!= NULL
) {
244 unsigned long size
= 0;
246 size
= (unsigned long)arg_arch
- (unsigned long)arg
;
247 *arg_name
= malloc(size
+ 1);
248 if (*arg_name
== NULL
)
250 (*arg_name
)[size
] = 0;
251 memcpy(*arg_name
, arg
, size
);
253 //identify architecture
254 if ((only_64bit
!= NULL
) && (only_32bit
!= NULL
)) {
255 if ((strcmp(arg_arch
+ 1, "64") == 0)) {
258 } else if ((strcmp(arg_arch
+ 1,"32") == 0)) {
262 outputerr("Unknown bit width (%s). Choose 32, or 64.\n", arg
);
267 *arg_name
= (char*)arg
;//castaway const.
271 void clear_check_user_specified_arch(const char *arg
, char **arg_name
)
273 //Release memory only if we have allocated it
274 if (((char *)arg
) != *arg_name
) {
280 void toggle_syscall(const char *arg
, bool state
)
282 int specific_syscall
= 0;
283 char * arg_name
= NULL
;
285 if (biarch
== TRUE
) {
286 toggle_syscall_biarch(arg
, state
);
290 /* non-biarch case. */
291 check_user_specified_arch(arg
, &arg_name
, NULL
, NULL
); //We do not care about arch here, just to get rid of arg flags.
293 specific_syscall
= search_syscall_table(syscalls
, max_nr_syscalls
, arg_name
);
294 if (specific_syscall
== -1) {
295 outputerr("No idea what syscall (%s) is.\n", arg
);
299 toggle_syscall_n(specific_syscall
, state
, arg
, arg_name
);
302 clear_check_user_specified_arch(arg
, &arg_name
);
305 void deactivate_disabled_syscalls(void)
307 output(0, "Disabling syscalls marked as disabled by command line options\n");
310 deactivate_disabled_syscalls_biarch();
312 deactivate_disabled_syscalls_uniarch();
315 void show_state(unsigned int state
)
318 outputstd("Enabled");
320 outputstd("Disabled");
323 void dump_syscall_tables(void)
326 dump_syscall_tables_biarch();
328 dump_syscall_tables_uniarch();
332 * This changes the pointers in the table 'from' to be copies in
333 * shared mmaps across all children. We do this so that a child can
334 * modify the flags field (adding AVOID for eg) and have other processes see the change.
336 static struct syscalltable
* copy_syscall_table(struct syscalltable
*from
, unsigned int nr
)
339 struct syscallentry
*copy
;
341 copy
= alloc_shared(nr
* sizeof(struct syscallentry
));
345 for (n
= 0; n
< nr
; n
++) {
346 memcpy(copy
+ n
, from
[n
].entry
, sizeof(struct syscallentry
));
348 copy
[n
].active_number
= 0;
349 from
[n
].entry
= ©
[n
];
354 void select_syscall_tables(void)
356 #ifdef ARCH_IS_BIARCH
357 syscalls_64bit
= copy_syscall_table(SYSCALLS64
, ARRAY_SIZE(SYSCALLS64
));
358 syscalls_32bit
= copy_syscall_table(SYSCALLS32
, ARRAY_SIZE(SYSCALLS32
));
360 max_nr_64bit_syscalls
= ARRAY_SIZE(SYSCALLS64
);
361 max_nr_32bit_syscalls
= ARRAY_SIZE(SYSCALLS32
);
364 syscalls
= copy_syscall_table(SYSCALLS
, ARRAY_SIZE(SYSCALLS
));
365 max_nr_syscalls
= ARRAY_SIZE(SYSCALLS
);
369 int setup_syscall_group(unsigned int group
)
372 return setup_syscall_group_biarch(group
);
374 return setup_syscall_group_uniarch(group
);
377 const char * print_syscall_name(unsigned int callno
, bool is32bit
)
379 const struct syscalltable
*table
;
382 if (biarch
== FALSE
) {
383 max
= max_nr_syscalls
;
386 if (is32bit
== FALSE
) {
387 max
= max_nr_64bit_syscalls
;
388 table
= syscalls_64bit
;
390 max
= max_nr_32bit_syscalls
;
391 table
= syscalls_32bit
;
396 outputstd("Bogus syscall number in %s (%u)\n", __func__
, callno
);
397 return "invalid-syscall";
400 return table
[callno
].entry
->name
;
403 void display_enabled_syscalls(void)
406 display_enabled_syscalls_biarch();
408 display_enabled_syscalls_uniarch();
411 static bool check_for_argtype(const struct syscalltable
*table
, unsigned int num
, unsigned int argtype
)
413 struct syscallentry
*entry
= table
[num
].entry
;
417 for (i
= 0; i
< entry
->num_args
; i
++) {
419 case 0: if (entry
->arg1type
== argtype
)
422 case 1: if (entry
->arg2type
== argtype
)
425 case 2: if (entry
->arg3type
== argtype
)
428 case 3: if (entry
->arg4type
== argtype
)
431 case 4: if (entry
->arg5type
== argtype
)
434 case 5: if (entry
->arg6type
== argtype
)
443 /* Consider anything with an ARG_FD or ARG_SOCKADDR a network syscall. */
444 bool is_syscall_net_related(const struct syscalltable
*table
, unsigned int num
)
446 if (check_for_argtype(table
, num
, ARG_FD
) == TRUE
)
449 if (check_for_argtype(table
, num
, ARG_SOCKADDR
) == TRUE
)
455 void disable_non_net_syscalls(void)
457 output(0, "Disabling non networking related syscalls\n");
460 disable_non_net_syscalls_biarch();
462 disable_non_net_syscalls_uniarch();
464 deactivate_disabled_syscalls();
467 void enable_random_syscalls(void)
471 if (random_selection_num
== 0) {
472 outputerr("-r 0 syscalls ? what?\n");
476 if (biarch
== TRUE
) {
477 if ((random_selection_num
> max_nr_64bit_syscalls
) && do_64_arch
) {
478 outputerr("-r val %d out of range (1-%d)\n", random_selection_num
, max_nr_64bit_syscalls
);
482 if (random_selection_num
> max_nr_syscalls
) {
483 outputerr("-r val %d out of range (1-%d)\n", random_selection_num
, max_nr_syscalls
);
488 outputerr("Enabling %d random syscalls\n", random_selection_num
);
490 for (i
= 0; i
< random_selection_num
; i
++) {
492 enable_random_syscalls_biarch();
494 enable_random_syscalls_uniarch();
499 /* This is run *after* we've parsed params */
500 int munge_tables(void)
502 /* By default, all syscall entries will be disabled.
503 * If we didn't pass -c, -x or -r, mark all syscalls active.
505 if ((do_specific_syscall
== FALSE
) && (do_exclude_syscall
== FALSE
) && (random_selection
== FALSE
) && (desired_group
== GROUP_NONE
))
506 mark_all_syscalls_active();
508 if (desired_group
!= GROUP_NONE
) {
511 ret
= setup_syscall_group(desired_group
);
516 if (random_selection
== TRUE
)
517 enable_random_syscalls();
519 /* If we saw a '-x', set all syscalls to enabled, then selectively disable.
520 * Unless we've started enabling them already (with -r) (or if we specified a group -g)
522 if (do_exclude_syscall
== TRUE
) {
523 if ((random_selection
== FALSE
) && (desired_group
== GROUP_NONE
))
524 mark_all_syscalls_active();
525 deactivate_disabled_syscalls();
528 /* if we passed -n, make sure there's no VM/VFS syscalls enabled. */
529 if (no_files
== TRUE
)
530 disable_non_net_syscalls();
532 sanity_check_tables();
534 count_syscalls_enabled();
537 display_enabled_syscalls();
539 if (validate_syscall_tables() == FALSE
) {
540 outputstd("No syscalls were enabled!\n");
541 outputstd("Use 32bit:%d 64bit:%d\n", use_32bit
, use_64bit
);