void main(void) { int x = 0; s2e_make_concolic(&x, sizeof(x), "x"); s2e_print_expression(x, "x before constraints"); if (x == 0) { s2e_print_expression(x, "x in if branch"); s2e_kill_state(0, "If branch terminated"); } else { s2e_print_expression(x, "x in else branch"); s2e_kill_state(0, "Else branch terminated"); } }
static void __s2e_init_env(int *argcPtr, char ***argvPtr) { int argc = *argcPtr; char** argv = *argvPtr; int new_argc = 0, n_args; char* new_argv[1024]; unsigned max_len, min_argvs, max_argvs; char** final_argv; char sym_arg_name[5] = "arg"; unsigned sym_arg_num = 0; int k=0, i; int concolic_mode = 0; sym_arg_name[4] = '\0'; // Load the process map and get the info about the current process procmap_entry_t* proc_map = load_process_map(); display_process_map(proc_map); register_module(proc_map, argv[0]); register_module(proc_map, "init_env.so"); #ifndef DEBUG_NATIVE s2e_codeselector_select_module("init_env.so"); #endif // Recognize --help when it is the sole argument. if (argc == 2 && __streq(argv[1], "--help")) { __emit_error("s2e_init_env\n\n" "usage: (s2e_init_env) [options] [program arguments]\n" "\n" " -select-process - Enable forking in the current process only\n" " -select-process-userspace - Enable forking in userspace-code of the\n" " current process only\n" " -select-process-code - Enable forking in the code section of the current binary only\n" " -concolic - Augment existing concrete arguments with symbolic values\n" " -sym-arg <N> - Replace by a symbolic argument of length N\n" " -sym-args <MIN> <MAX> <N> - Replace by at least MIN arguments and at most\n" " MAX arguments, each with maximum length N\n\n"); } #ifndef DEBUG_NATIVE s2e_enable_forking(); #endif while (k < argc) { if (__streq(argv[k], "--concolic") || __streq(argv[k], "-concolic")) { concolic_mode = 1; ++k; } else if (__streq(argv[k], "--sym-arg") || __streq(argv[k], "-sym-arg")) { const char *msg = "--sym-arg expects an integer argument <max-len>"; if (++k == argc) __emit_error(msg); max_len = __str_to_int(argv[k++], msg); sym_arg_name[3] = '0' + sym_arg_num++; __add_arg(&new_argc, new_argv, __get_sym_str(max_len, sym_arg_name), 1024); } else if (__streq(argv[k], "--sym-args") || __streq(argv[k], "-sym-args")) { const char *msg = "--sym-args expects three integer arguments <min-argvs> <max-argvs> <max-len>"; if (k+3 >= argc) __emit_error(msg); k++; min_argvs = __str_to_int(argv[k++], msg); max_argvs = __str_to_int(argv[k++], msg); max_len = __str_to_int(argv[k++], msg); n_args = s2e_range(min_argvs, max_argvs+1, "n_args"); for (i=0; i < n_args; i++) { sym_arg_name[3] = '0' + sym_arg_num++; __add_arg(&new_argc, new_argv, __get_sym_str(max_len, sym_arg_name), 1024); } } else if (__streq(argv[k], "--select-process") || __streq(argv[k], "-select-process")) { k++; myprintf("Forks will be restricted to the current address space\n"); s2e_codeselector_enable_address_space(0); } else if (__streq(argv[k], "--select-process-userspace") || __streq(argv[k], "-select-process-userspace")) { k++; myprintf("Forks will be restricted to the user-mode portion of the current address space\n"); s2e_codeselector_enable_address_space(1); } else if (__streq(argv[k], "--select-process-code") || __streq(argv[k], "-select-process-code")) { k++; const char *process_base_name = __base_name(argv[0]); myprintf("Forks will be restricted to %s\n", process_base_name); s2e_codeselector_select_module(process_base_name); } else { /* simply copy arguments */ if (concolic_mode) { sym_arg_name[3] = '0' + k; s2e_make_concolic(argv[k], strlen(argv[k]), sym_arg_name); } __add_arg(&new_argc, new_argv, argv[k++], 1024); } } final_argv = (char**) malloc((new_argc+1) * sizeof(*final_argv)); memcpy(final_argv, new_argv, new_argc * sizeof(*final_argv)); final_argv[new_argc] = 0; *argcPtr = new_argc; *argvPtr = final_argv; }
static void handler_symbfile(const char **args) { const char *filename = args[0]; int fd = open(filename, O_RDWR); if (fd < 0) { s2e_kill_state_printf(-1, "symbfile: could not open %s\n", filename); return; } /* Determine the size of the file */ off_t size = lseek(fd, 0, SEEK_END); if (size < 0) { s2e_kill_state_printf(-1, "symbfile: could not determine the size of %s\n", filename); return; } char buffer[0x1000]; unsigned current_chunk = 0; unsigned total_chunks = size / sizeof(buffer); if (size % sizeof(buffer)) { ++total_chunks; } /** * Replace slashes in the filename with underscores. * It should make it easier for plugins to generate * concrete files, while preserving info about the original path * and without having to deal with the slashes. **/ char cleaned_name[512]; strncpy(cleaned_name, filename, sizeof(cleaned_name)); for (unsigned i = 0; cleaned_name[i]; ++i) { if (cleaned_name[i] == '/') { cleaned_name[i] = '_'; } } off_t offset = 0; do { /* Read the file in chunks of 4K and make them concolic */ char symbvarname[512]; if (lseek(fd, offset, SEEK_SET) < 0) { s2e_kill_state_printf(-1, "symbfile: could not seek to position %d", offset); return; } ssize_t totransfer = size > sizeof(buffer) ? sizeof(buffer) : size; /* Read the data */ ssize_t read_count = read(fd, buffer, totransfer); if (read_count < 0) { s2e_kill_state_printf(-1, "symbfile: could not read from file %s", filename); return; } /** * Make the buffer concolic. * The symbolic variable name encodes the original file name with its path * as well as the chunk id contained in the buffer. * A test case generator should therefore be able to reconstruct concrete * files easily. */ snprintf(symbvarname, sizeof(symbvarname), "__symfile___%s___%d_%d_symfile__", cleaned_name, current_chunk, total_chunks); s2e_make_concolic(buffer, read_count, symbvarname); /* Write it back */ if (lseek(fd, offset, SEEK_SET) < 0) { s2e_kill_state_printf(-1, "symbfile: could not seek to position %d", offset); return; } ssize_t written_count = write(fd, buffer, read_count); if (written_count < 0) { s2e_kill_state_printf(-1, "symbfile: could not write to file %s", filename); return; } if (read_count != written_count) { /* XXX: should probably retry...*/ s2e_kill_state_printf(-1, "symbfile: could not write the read amount"); return; } offset += read_count; size -= read_count; ++current_chunk; } while (size > 0); close(fd); }