#include #include #include #include #include #include #include #include "bdevs.h" #include "child.h" #include "log.h" #include "net.h" #include "params.h" #include "domains.h" #include "random.h" #include "syscall.h" #include "tables.h" #include "taint.h" #include "trinity.h" // progname bool set_debug = FALSE; bool do_specific_syscall = FALSE; bool do_exclude_syscall = FALSE; bool use_specific_dev_fd = FALSE; bool do_32_arch = TRUE; bool do_64_arch = TRUE; unsigned int specific_domain = 0; unsigned int user_specified_children = 0; bool do_specific_domain = FALSE; bool no_domains[TRINITY_PF_MAX]; bool dopause = FALSE; bool show_syscall_list = FALSE; bool show_ioctl_list = FALSE; unsigned char quiet_level = 0; bool verbose = FALSE; bool monochrome = FALSE; bool dangerous = FALSE; bool dropprivs = FALSE; bool logging = TRUE; bool do_syslog = FALSE; bool random_selection = FALSE; unsigned int random_selection_num; bool user_set_seed = FALSE; unsigned char desired_group = GROUP_NONE; char *specific_domain_optarg = NULL; char *victim_path = NULL; unsigned int kernel_taint_mask = 0xFFFFFFFF; bool kernel_taint_param_occured = FALSE; int server_port = 0; char server_addr[INET6_ADDRSTRLEN] = "\0"; void enable_disable_fd_usage(void) { outputerr(" --enable-fds/--disable-fds= {sockets,pipes,perf,epoll,eventfd,pseudo,timerfd,testfile,memfd}\n"); } static void usage(void) { outputerr("%s\n", progname); outputerr(" --arch, -a: selects syscalls for the specified architecture (32 or 64). Both by default.\n"); outputerr(" --bdev, -b : Add /dev node to list of block devices to use for destructive tests..\n"); outputerr(" --children,-C: specify number of child processes\n"); outputerr(" --debug,-D: enable debug\n"); outputerr(" --dropprivs, -X: if run as root, switch to nobody [EXPERIMENTAL]\n"); outputerr(" --exclude,-x: don't call a specific syscall\n"); enable_disable_fd_usage(); outputerr(" --group,-g = {vfs,vm}: only run syscalls from a certain group.\n"); outputerr(" --ioctls,-I: list all ioctls.\n"); outputerr(" --kernel_taint, -T: controls which kernel taint flags should be considered, for more details refer to README file. \n"); outputerr(" --list,-L: list all syscalls known on this architecture.\n"); outputerr(" --logging,-l: (off=disable logging).\n"); outputerr(" --monochrome,-m: don't output ANSI codes\n"); outputerr(" --domain,-P: specify specific network domain for sockets.\n"); //FIXME: P used to be 'proto' pick something better. outputerr(" --no_domain,-E: specify network domains to be excluded from testing.\n"); outputerr(" --quiet,-q: less output.\n"); outputerr(" --random,-r#: pick N syscalls at random and just fuzz those\n"); outputerr(" --server_addr: supply an IPv4 or IPv6 address to connect, no need for server side.\n"); outputerr(" --server_port: supply an server port to listen or connect, will fuzz between port to (port + 100)\n"); outputerr(" --syslog,-S: log important info to syslog. (useful if syslog is remote)\n"); outputerr(" --verbose,-v: increase output verbosity.\n"); outputerr(" --victims,-V: path to victim files.\n"); outputerr(" --driver,-R: fuzz a device driver in /dev.\n"); outputerr("\n"); outputerr(" -c#,@: target specific syscall (takes syscall name as parameter and optionally 32 or 64 as bit-width. Default:both).\n"); outputerr(" -N#: do # syscalls then exit.\n"); outputerr(" -p: pause after syscall.\n"); outputerr(" -s#: use # as random seed.\n"); exit(EXIT_SUCCESS); } static const char paramstr[] = "a:b:c:C:dDg:hIl:LN:mP:E:pqr:s:T:SV:vx:X:R:"; static const struct option longopts[] = { { "arch", required_argument, NULL, 'a' }, { "bdev", required_argument, NULL, 'b' }, { "children", required_argument, NULL, 'C' }, { "dangerous", no_argument, NULL, 'd' }, { "dropprivs", no_argument, NULL, 'X'}, { "debug", no_argument, NULL, 'D' }, { "disable-fds", required_argument, NULL, 0 }, { "enable-fds", required_argument, NULL, 0 }, { "exclude", required_argument, NULL, 'x' }, { "group", required_argument, NULL, 'g' }, { "kernel_taint", required_argument, NULL, 'T' }, { "help", no_argument, NULL, 'h' }, { "list", no_argument, NULL, 'L' }, { "ioctls", no_argument, NULL, 'I' }, { "logging", required_argument, NULL, 'l' }, { "monochrome", no_argument, NULL, 'm' }, { "no_domain", required_argument, NULL, 'E' }, { "domain", required_argument, NULL, 'P' }, { "quiet", no_argument, NULL, 'q' }, { "random", required_argument, NULL, 'r' }, { "server_addr", required_argument, NULL, 0 }, { "server_port", required_argument, NULL, 0 }, { "syslog", no_argument, NULL, 'S' }, { "verbose", no_argument, NULL, 'v' }, { "victims", required_argument, NULL, 'V' }, { "driver", required_argument, NULL, 'R' }, { NULL, 0, NULL, 0 } }; void parse_args(int argc, char *argv[]) { int opt; int opt_index = 0; while ((opt = getopt_long(argc, argv, paramstr, longopts, &opt_index)) != -1) { switch (opt) { default: if (opt == '?') exit(EXIT_FAILURE); else outputstd("opt:%c\n", opt); return; case 'b': init_bdev_list(); process_bdev_param(optarg); dump_bdev_list(); outputstd("--bdev doesn't do anything useful yet.\n"); exit(EXIT_SUCCESS); case 'c': /* syscalls are all disabled at this point. enable the syscall we care about. */ do_specific_syscall = TRUE; toggle_syscall(optarg, TRUE); break; case 'a': /* One of the architectures selected*/ do_32_arch = FALSE; do_64_arch = FALSE; if (strcmp(optarg, "64") == 0) { do_32_arch = FALSE; do_64_arch = TRUE; } else if (strcmp(optarg, "32") == 0) { do_32_arch = TRUE; do_64_arch = FALSE; } else { outputstd("can't parse %s\n", optarg); exit(EXIT_FAILURE); } break; case 'C': user_specified_children = strtoll(optarg, NULL, 10); max_children = user_specified_children; if (max_children == 0) { outputerr("zero children ? WAT?\n"); exit(EXIT_FAILURE); } break; case 'd': dangerous = TRUE; break; case 'D': set_debug = TRUE; break; case 'g': if (!strcmp(optarg, "vm")) desired_group = GROUP_VM; if (!strcmp(optarg, "vfs")) desired_group = GROUP_VFS; break; /* Show help */ case 'h': usage(); exit(EXIT_SUCCESS); case 'I': show_ioctl_list = TRUE; break; case 'l': if (!strcmp(optarg, "off")) logging = FALSE; break; case 'L': show_syscall_list = TRUE; break; case 'm': monochrome = TRUE; memset(&ANSI_RED, 0, 1); memset(&ANSI_GREEN, 0, 1); memset(&ANSI_YELLOW, 0, 1); memset(&ANSI_BLUE, 0, 1); memset(&ANSI_MAGENTA, 0, 1); memset(&ANSI_CYAN, 0, 1); memset(&ANSI_WHITE, 0, 1); memset(&ANSI_RESET, 0, 1); break; /* Set number of syscalls to do */ case 'N': syscalls_todo = strtoll(optarg, NULL, 10); break; /* Pause after each syscall */ case 'p': dopause = TRUE; break; case 'P': do_specific_domain = TRUE; specific_domain = strtol(optarg, NULL, 10); specific_domain_optarg = optarg; break; case 'E': parse_exclude_domains(optarg); break; case 'q': quiet_level++; break; case 'r': if (do_exclude_syscall == TRUE) { outputerr("-r needs to be before any -x options.\n"); exit(EXIT_FAILURE); } random_selection = TRUE; random_selection_num = strtol(optarg, NULL, 10); break; case 'R': if(fuzz_device_driver(optarg) == FALSE) { outputerr("Unable to open the device driver!\n"); exit(EXIT_FAILURE); } use_specific_dev_fd = TRUE; break; /* Set seed */ case 's': seed = strtol(optarg, NULL, 10); user_set_seed = TRUE; break; case 'S': do_syslog = TRUE; break; case 'T': //Load mask for kernel taint flags. process_taint_arg(optarg); if (kernel_taint_mask != 0xFFFFFFFF) outputstd("Custom kernel taint mask has been specified: 0x%08x (%d).\n", kernel_taint_mask, kernel_taint_mask); break; case 'v': verbose = TRUE; break; case 'V': if (victim_path == NULL) { victim_path = strdup(optarg); break; } else { outputstd("Sorry, only one victim path right now.\n"); exit(EXIT_FAILURE); } //FIXME: Later, allow for multiple victim files break; case 'x': do_exclude_syscall = TRUE; toggle_syscall(optarg, FALSE); break; case 'X': dropprivs = TRUE; break; case 0: /* * FIXME: It's really hard to find two reasonable short * names since S s P p all have been used. Use long * options before we fix this issue. */ if (strcmp("server_addr", longopts[opt_index].name) == 0) { unsigned int optarglen = strlen(optarg); unsigned int len = min((unsigned int)sizeof(server_addr), optarglen); strncpy(server_addr, optarg, len); } if (strcmp("server_port", longopts[opt_index].name) == 0) server_port = atoi(optarg); if (strcmp("disable-fds", longopts[opt_index].name) == 0) process_fds_param(optarg, FALSE); if (strcmp("enable-fds", longopts[opt_index].name) == 0) process_fds_param(optarg, TRUE); break; } } if (quiet_level > MAX_LOGLEVEL) quiet_level = MAX_LOGLEVEL; quiet_level = MAX_LOGLEVEL - quiet_level; output(1, "Done parsing arguments.\n"); } .