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
)
43 if (table
[call
].entry
->flags
& AVOID_SYSCALL
)
44 output(0, "%s is marked as AVOID. Skipping\n", table
[call
].entry
->name
);
46 if (table
[call
].entry
->flags
& NI_SYSCALL
)
47 output(0, "%s is NI_SYSCALL. Skipping\n", table
[call
].entry
->name
);
50 int validate_specific_syscall_silent(const struct syscalltable
*table
, int call
)
55 if (table
[call
].entry
->flags
& AVOID_SYSCALL
)
58 if (table
[call
].entry
->flags
& NI_SYSCALL
)
64 void activate_syscall_in_table(unsigned int calln
, unsigned int *nr_active
, const struct syscalltable
*table
, int *active_syscall
)
66 struct syscall
*call_ptr
;
68 call_ptr
= table
[calln
].entry
;
70 //Check if the call is activated already, and activate it only if needed
71 if (call_ptr
->active_number
== 0) {
73 if ((*nr_active
+ 1) > MAX_NR_SYSCALL
) {
74 output(0, "[tables] MAX_NR_SYSCALL needs to be increased. More syscalls than active table can fit.\n");
79 active_syscall
[*nr_active
] = calln
+ 1;
81 call_ptr
->active_number
= *nr_active
;
85 void deactivate_syscall_in_table(unsigned int calln
, unsigned int *nr_active
, const struct syscalltable
*table
, int *active_syscall
)
87 struct syscall
*call_ptr
;
90 call_ptr
= table
[calln
].entry
;
91 //Check if the call is activated already, and deactivate it only if needed
92 if ((call_ptr
->active_number
!= 0) && (*nr_active
> 0)) {
93 for (i
= call_ptr
->active_number
- 1; i
< *nr_active
- 1; i
++) {
94 active_syscall
[i
] = active_syscall
[i
+ 1];
95 table
[active_syscall
[i
] - 1].entry
->active_number
= i
+ 1;
97 //The last step is to erase the last item.
98 active_syscall
[*nr_active
- 1] = 0;
100 call_ptr
->active_number
= 0;
104 void count_syscalls_enabled(void)
106 if (biarch
== TRUE
) {
107 output(0, "32-bit syscalls: %d enabled, %d disabled. "
108 "64-bit syscalls: %d enabled, %d disabled.\n",
109 shm
->nr_active_32bit_syscalls
, max_nr_32bit_syscalls
- shm
->nr_active_32bit_syscalls
,
110 shm
->nr_active_64bit_syscalls
, max_nr_64bit_syscalls
- shm
->nr_active_64bit_syscalls
);
112 output(0, "Enabled %d syscalls. Disabled %d syscalls.\n",
113 shm
->nr_active_syscalls
, max_nr_syscalls
- shm
->nr_active_syscalls
);
117 void init_syscalls(void)
120 init_syscalls_biarch();
122 init_syscalls_uniarch();
125 bool no_syscalls_enabled(void)
127 if (biarch
== TRUE
) {
128 if ((shm
->nr_active_32bit_syscalls
== 0) && (shm
->nr_active_64bit_syscalls
== 0))
135 if (shm
->nr_active_syscalls
== 0)
141 /* Make sure there's at least one syscall enabled. */
142 int validate_syscall_tables(void)
146 if (biarch
== TRUE
) {
147 ret
= validate_syscall_table_32();
148 ret
|= validate_syscall_table_64();
153 if (shm
->nr_active_syscalls
== 0)
159 static void check_syscall(struct syscall
*entry
)
161 /* check that we have a name set. */
162 #define CHECK(NUMARGS, ARGNUM, ARGTYPE, ARGNAME) \
163 if (entry->num_args > 0) { \
164 if (entry->num_args > NUMARGS) { \
165 if (entry->ARGNAME == NULL) { \
166 outputerr("arg %d of %s has no name\n", ARGNUM, entry->name); \
167 exit(EXIT_FAILURE); \
172 CHECK(0, 1, arg1type, arg1name);
173 CHECK(1, 2, arg2type
, arg2name
);
174 CHECK(2, 3, arg3type
, arg3name
);
175 CHECK(3, 4, arg4type
, arg4name
);
176 CHECK(4, 5, arg5type
, arg5name
);
177 CHECK(5, 6, arg6type
, arg6name
);
179 /* check if we have a type. */
180 /* note: not enabled by default, because we haven't annotated everything yet. */
182 #define CHECK(NUMARGS, ARGNUM, ARGTYPE, ARGNAME) \
183 if (entry->num_args > 0) { \
184 if (entry->num_args > NUMARGS) { \
185 if (entry->ARGTYPE == ARG_UNDEFINED) { \
186 outputerr("%s has an undefined argument type for arg1 (%s)!\n", entry->name, entry->ARGNAME); \
191 /* CHECK(0, 1, arg1type, arg1name);
192 CHECK(1, 2, arg2type, arg2name);
193 CHECK(2, 3, arg3type, arg3name);
194 CHECK(3, 4, arg4type, arg4name);
195 CHECK(4, 5, arg5type, arg5name);
196 CHECK(5, 6, arg6type, arg6name);
200 static void sanity_check(const struct syscalltable
*table
, unsigned int nr
)
204 for (i
= 0; i
< nr
; i
++)
205 check_syscall(table
[i
].entry
);
208 void sanity_check_tables(void)
210 if (biarch
== TRUE
) {
211 sanity_check(syscalls_32bit
, max_nr_32bit_syscalls
);
212 sanity_check(syscalls_64bit
, max_nr_64bit_syscalls
);
217 sanity_check(syscalls
, max_nr_syscalls
);
220 void mark_all_syscalls_active(void)
222 outputstd("Marking all syscalls as enabled.\n");
225 mark_all_syscalls_active_biarch();
227 mark_all_syscalls_active_uniarch();
230 void check_user_specified_arch(const char *arg
, char **arg_name
, bool *only_64bit
, bool *only_32bit
)
232 //Check if the arch is specified
233 char *arg_arch
= strstr(arg
,",");
234 unsigned long size
= 0;
236 if (arg_arch
!= NULL
) {
237 size
= (unsigned long)arg_arch
- (unsigned long)arg
;
238 *arg_name
= malloc(size
+ 1);
239 if (*arg_name
== NULL
)
241 (*arg_name
)[size
] = 0;
242 memcpy(*arg_name
, arg
, size
);
244 //identify architecture
245 if ((only_64bit
!= NULL
) && (only_32bit
!= NULL
)) {
246 if ((strcmp(arg_arch
+ 1, "64") == 0)) {
249 } else if ((strcmp(arg_arch
+ 1,"32") == 0)) {
253 outputerr("Unknown bit width (%s). Choose 32, or 64.\n", arg
);
258 *arg_name
= (char*)arg
;//castaway const.
262 void clear_check_user_specified_arch(const char *arg
, char **arg_name
)
264 //Release memory only if we have allocated it
265 if (((char *)arg
) != *arg_name
) {
271 void toggle_syscall(const char *arg
, bool state
)
273 int specific_syscall
= 0;
274 char * arg_name
= NULL
;
276 if (biarch
== TRUE
) {
277 toggle_syscall_biarch(arg
, state
);
281 /* non-biarch case. */
282 check_user_specified_arch(arg
, &arg_name
, NULL
, NULL
); //We do not care about arch here, just to get rid of arg flags.
283 specific_syscall
= search_syscall_table(syscalls
, max_nr_syscalls
, arg_name
);
284 toggle_syscall_n(specific_syscall
, state
, arg
, arg_name
);
285 clear_check_user_specified_arch(arg
, &arg_name
);
288 void deactivate_disabled_syscalls(void)
290 output(0, "Disabling syscalls marked as disabled by command line options\n");
293 deactivate_disabled_syscalls_biarch();
295 deactivate_disabled_syscalls_uniarch();
298 void show_state(unsigned int state
)
301 outputstd("Enabled");
303 outputstd("Disabled");
306 void dump_syscall_tables(void)
309 dump_syscall_tables_biarch();
311 dump_syscall_tables_uniarch();
315 * This changes the pointers in the table 'from' to be copies in
316 * shared mmaps across all children. We do this so that a child can
317 * modify the flags field (adding AVOID for eg) and have other processes see the change.
319 static struct syscalltable
* copy_syscall_table(struct syscalltable
*from
, unsigned int nr
)
322 struct syscall
*copy
;
324 copy
= alloc_shared(nr
* sizeof(struct syscall
));
328 for (n
= 0; n
< nr
; n
++) {
329 memcpy(copy
+ n
, from
[n
].entry
, sizeof(struct syscall
));
331 copy
[n
].active_number
= 0;
332 from
[n
].entry
= ©
[n
];
337 void select_syscall_tables(void)
339 #ifdef ARCH_IS_BIARCH
340 syscalls_64bit
= copy_syscall_table(SYSCALLS64
, ARRAY_SIZE(SYSCALLS64
));
341 syscalls_32bit
= copy_syscall_table(SYSCALLS32
, ARRAY_SIZE(SYSCALLS32
));
343 max_nr_64bit_syscalls
= ARRAY_SIZE(SYSCALLS64
);
344 max_nr_32bit_syscalls
= ARRAY_SIZE(SYSCALLS32
);
347 syscalls
= copy_syscall_table(SYSCALLS
, ARRAY_SIZE(SYSCALLS
));
348 max_nr_syscalls
= ARRAY_SIZE(SYSCALLS
);
352 int setup_syscall_group(unsigned int group
)
355 return setup_syscall_group_biarch(group
);
357 return setup_syscall_group_uniarch(group
);
360 const char * print_syscall_name(unsigned int callno
, bool is32bit
)
362 const struct syscalltable
*table
;
365 if (biarch
== FALSE
) {
366 max
= max_nr_syscalls
;
369 if (is32bit
== FALSE
) {
370 max
= max_nr_64bit_syscalls
;
371 table
= syscalls_64bit
;
373 max
= max_nr_32bit_syscalls
;
374 table
= syscalls_32bit
;
379 outputstd("Bogus syscall number in %s (%u)\n", __func__
, callno
);
380 return "invalid-syscall";
383 return table
[callno
].entry
->name
;
386 void display_enabled_syscalls(void)
389 display_enabled_syscalls_biarch();
391 display_enabled_syscalls_uniarch();
394 /* If we want just network sockets, don't bother with VM/VFS syscalls */
395 bool is_syscall_net_related(const struct syscalltable
*table
, unsigned int num
)
399 if (no_files
== FALSE
)
402 if (table
[num
].entry
->group
== GROUP_VM
)
404 if (table
[num
].entry
->group
== GROUP_VFS
)
407 for (i
= 0; i
< table
[num
].entry
->num_args
; i
++) {
409 case 0: if (table
[num
].entry
->arg1type
== ARG_PATHNAME
)
412 case 1: if (table
[num
].entry
->arg2type
== ARG_PATHNAME
)
415 case 2: if (table
[num
].entry
->arg3type
== ARG_PATHNAME
)
418 case 3: if (table
[num
].entry
->arg4type
== ARG_PATHNAME
)
421 case 4: if (table
[num
].entry
->arg5type
== ARG_PATHNAME
)
424 case 5: if (table
[num
].entry
->arg6type
== ARG_PATHNAME
)
428 BUG("impossible!\n");
435 void disable_non_net_syscalls(void)
437 output(0, "Disabling non networking related syscalls\n");
440 disable_non_net_syscalls_biarch();
442 disable_non_net_syscalls_uniarch();
444 deactivate_disabled_syscalls();
447 void enable_random_syscalls(void)
451 if (random_selection_num
== 0) {
452 outputerr("-r 0 syscalls ? what?\n");
456 if (biarch
== TRUE
) {
457 if ((random_selection_num
> max_nr_64bit_syscalls
) && do_64_arch
) {
458 outputerr("-r val %d out of range (1-%d)\n", random_selection_num
, max_nr_64bit_syscalls
);
462 if (random_selection_num
> max_nr_syscalls
) {
463 outputerr("-r val %d out of range (1-%d)\n", random_selection_num
, max_nr_syscalls
);
468 outputerr("Enabling %d random syscalls\n", random_selection_num
);
470 for (i
= 0; i
< random_selection_num
; i
++) {
472 enable_random_syscalls_biarch();
474 enable_random_syscalls_uniarch();