move shm code out of trinity.c into own file
[trinity.git] / tables.c
blob380143112be0475584e06849adf8943ef8b243af
1 /*
2 * Functions for handling the system call tables.
3 */
5 #include <string.h>
6 #include <stdio.h>
7 #include <unistd.h>
8 #include <stdlib.h>
10 #include "trinity.h" // ARRAY_SIZE, alloc_shared
11 #include "arch.h"
12 #include "arch-syscalls.h"
13 #include "syscall.h"
14 #include "params.h"
15 #include "log.h"
16 #include "shm.h"
17 #include "tables.h"
19 unsigned long syscalls_todo = 0;
21 bool biarch = FALSE;
23 int search_syscall_table(const struct syscalltable *table, unsigned int nr_syscalls, const char *arg)
25 unsigned int i;
27 /* search by name */
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);
31 return i;
35 return -1;
38 void validate_specific_syscall(const struct syscalltable *table, int call)
40 if (call == -1)
41 return;
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)
52 if (call == -1)
53 return FALSE;
55 if (table[call].entry->flags & AVOID_SYSCALL)
56 return FALSE;
58 if (table[call].entry->flags & NI_SYSCALL)
59 return FALSE;
61 return TRUE;
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) {
72 //Sanity check
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");
75 exit(EXIT_FAILURE);
78 //save the call no
79 active_syscall[*nr_active] = calln + 1;
80 (*nr_active) += 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;
88 unsigned int i;
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;
99 (*nr_active) -= 1;
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);
111 } else {
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)
119 if (biarch == TRUE)
120 init_syscalls_biarch();
121 else
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))
129 return TRUE;
130 else
131 return FALSE;
134 /* non-biarch */
135 if (shm->nr_active_syscalls == 0)
136 return TRUE;
137 else
138 return FALSE;
141 /* Make sure there's at least one syscall enabled. */
142 int validate_syscall_tables(void)
144 unsigned int ret;
146 if (biarch == TRUE) {
147 ret = validate_syscall_table_32();
148 ret |= validate_syscall_table_64();
149 return ret;
152 /* non-biarch case*/
153 if (shm->nr_active_syscalls == 0)
154 return FALSE;
155 else
156 return TRUE;
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. */
181 #undef CHECK
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)
202 unsigned int i;
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);
213 return;
216 /* non-biarch case*/
217 sanity_check(syscalls, max_nr_syscalls);
220 void mark_all_syscalls_active(void)
222 outputstd("Marking all syscalls as enabled.\n");
224 if (biarch == TRUE)
225 mark_all_syscalls_active_biarch();
226 else
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)
240 exit(EXIT_FAILURE);
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)) {
247 *only_64bit = TRUE;
248 *only_32bit = FALSE;
249 } else if ((strcmp(arg_arch + 1,"32") == 0)) {
250 *only_64bit = FALSE;
251 *only_32bit = TRUE;
252 } else {
253 outputerr("Unknown bit width (%s). Choose 32, or 64.\n", arg);
254 exit(EXIT_FAILURE);
257 } else {
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) {
266 free(*arg_name);
267 *arg_name = NULL;
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);
278 return;
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");
292 if (biarch == TRUE)
293 deactivate_disabled_syscalls_biarch();
294 else
295 deactivate_disabled_syscalls_uniarch();
298 void show_state(unsigned int state)
300 if (state)
301 outputstd("Enabled");
302 else
303 outputstd("Disabled");
306 void dump_syscall_tables(void)
308 if (biarch == TRUE)
309 dump_syscall_tables_biarch();
310 else
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)
321 unsigned int n;
322 struct syscall *copy;
324 copy = alloc_shared(nr * sizeof(struct syscall));
325 if (copy == NULL)
326 exit(EXIT_FAILURE);
328 for (n = 0; n < nr; n++) {
329 memcpy(copy + n , from[n].entry, sizeof(struct syscall));
330 copy[n].number = n;
331 copy[n].active_number = 0;
332 from[n].entry = &copy[n];
334 return from;
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);
345 biarch = TRUE;
346 #else
347 syscalls = copy_syscall_table(SYSCALLS, ARRAY_SIZE(SYSCALLS));
348 max_nr_syscalls = ARRAY_SIZE(SYSCALLS);
349 #endif
352 int setup_syscall_group(unsigned int group)
354 if (biarch == TRUE)
355 return setup_syscall_group_biarch(group);
356 else
357 return setup_syscall_group_uniarch(group);
360 const char * print_syscall_name(unsigned int callno, bool is32bit)
362 const struct syscalltable *table;
363 unsigned int max;
365 if (biarch == FALSE) {
366 max = max_nr_syscalls;
367 table = syscalls;
368 } else {
369 if (is32bit == FALSE) {
370 max = max_nr_64bit_syscalls;
371 table = syscalls_64bit;
372 } else {
373 max = max_nr_32bit_syscalls;
374 table = syscalls_32bit;
378 if (callno >= max) {
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)
388 if (biarch == TRUE)
389 display_enabled_syscalls_biarch();
390 else
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)
397 unsigned int i;
399 if (no_files == FALSE)
400 return TRUE;
402 if (table[num].entry->group == GROUP_VM)
403 return FALSE;
404 if (table[num].entry->group == GROUP_VFS)
405 return FALSE;
407 for (i = 0; i < table[num].entry->num_args; i++) {
408 switch (i) {
409 case 0: if (table[num].entry->arg1type == ARG_PATHNAME)
410 return FALSE;
411 break;
412 case 1: if (table[num].entry->arg2type == ARG_PATHNAME)
413 return FALSE;
414 break;
415 case 2: if (table[num].entry->arg3type == ARG_PATHNAME)
416 return FALSE;
417 break;
418 case 3: if (table[num].entry->arg4type == ARG_PATHNAME)
419 return FALSE;
420 break;
421 case 4: if (table[num].entry->arg5type == ARG_PATHNAME)
422 return FALSE;
423 break;
424 case 5: if (table[num].entry->arg6type == ARG_PATHNAME)
425 return FALSE;
426 break;
427 default:
428 BUG("impossible!\n");
432 return TRUE;
435 void disable_non_net_syscalls(void)
437 output(0, "Disabling non networking related syscalls\n");
439 if (biarch == TRUE)
440 disable_non_net_syscalls_biarch();
441 else
442 disable_non_net_syscalls_uniarch();
444 deactivate_disabled_syscalls();
447 void enable_random_syscalls(void)
449 unsigned int i;
451 if (random_selection_num == 0) {
452 outputerr("-r 0 syscalls ? what?\n");
453 exit(EXIT_FAILURE);
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);
459 exit(EXIT_FAILURE);
461 } else {
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);
464 exit(EXIT_FAILURE);
468 outputerr("Enabling %d random syscalls\n", random_selection_num);
470 for (i = 0; i < random_selection_num; i++) {
471 if (biarch == TRUE)
472 enable_random_syscalls_biarch();
473 else
474 enable_random_syscalls_uniarch();