/* Copyright (c) the Selfie Project authors. All rights reserved. Please see the AUTHORS file for details. Use of this source code is governed by a BSD license that can be found in the LICENSE file. Selfie is a project of the Computational Systems Group at the Department of Computer Sciences of the University of Salzburg in Austria. For further information and code please refer to: selfie.cs.uni-salzburg.at Buzzr is a fuzzer for selfie ... */ // *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ // ----------------------------------------------------------------- // ------------------- I N T E R F A C E ------------------- // ----------------------------------------------------------------- // *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ // ----------------------------------------------------------------- // ----------------------- MIPSTER SYSCALLS ------------------------ // ----------------------------------------------------------------- void implement_buzzed_exit(uint64_t* context); uint64_t buzz_read(uint64_t* buffer, uint64_t bytes_to_read); void implement_buzzed_read(uint64_t* context); // ------------------------ GLOBAL VARIABLES ----------------------- uint64_t buzzed_input = 0; uint64_t number_of_buzzed_inputs = 0; // ------------------------ GLOBAL CONSTANTS ----------------------- uint64_t MAX_BUZZES = 256; // *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ // ----------------------------------------------------------------- // ---------------------- R U N T I M E ---------------------- // ----------------------------------------------------------------- // *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ // ----------------------------------------------------------------- // ---------------------------- KERNEL ----------------------------- // ----------------------------------------------------------------- uint64_t handle_buzzed_system_call(uint64_t* context); uint64_t handle_buzzed_page_fault(uint64_t* context); uint64_t handle_buzzed_timer(uint64_t* context); uint64_t handle_buzzed_exception(uint64_t* context); // ------------------------ GLOBAL CONSTANTS ----------------------- uint64_t EXITCODE_OUTOFTIME = 100; // ----------------------------------------------------------------- // ------------------------- BUZZING ENGINE ------------------------ // ----------------------------------------------------------------- uint64_t buzzr(uint64_t* to_context); uint64_t selfie_buzz(); // *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ // ----------------------------------------------------------------- // ------------------- I N T E R F A C E ------------------- // ----------------------------------------------------------------- // *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ // ----------------------------------------------------------------- // ----------------------- MIPSTER SYSCALLS ------------------------ // ----------------------------------------------------------------- void implement_buzzed_exit(uint64_t* context) { // parameter; uint64_t signed_int_exit_code; if (debug_syscalls) { printf("(exit): "); print_register_hexadecimal(REG_A0); printf(" |- ->\n"); } signed_int_exit_code = *(get_regs(context) + REG_A0); set_exit_code(context, sign_shrink(signed_int_exit_code, SYSCALL_BITWIDTH)); } uint64_t buzz_read(uint64_t* buffer, uint64_t bytes_to_read) { if (number_of_buzzed_inputs > 0) { if (number_of_buzzed_inputs < MAX_BUZZES) buzzed_input = (buzzed_input + 1) % MAX_BUZZES; else return sign_extend(-1, SYSCALL_BITWIDTH); } *buffer = buzzed_input; number_of_buzzed_inputs = number_of_buzzed_inputs + 1; return bytes_to_read; } void implement_buzzed_read(uint64_t* context) { // parameters uint64_t fd; uint64_t vbuffer; uint64_t size; // local variables uint64_t read_total; uint64_t bytes_to_read; uint64_t failed; uint64_t* buffer; uint64_t actually_read; if (debug_syscalls) { printf("(read): "); print_register_value(REG_A0); printf(","); print_register_hexadecimal(REG_A1); printf(","); print_register_value(REG_A2); printf(" |- "); print_register_value(REG_A0); } fd = *(get_regs(context) + REG_A0); vbuffer = *(get_regs(context) + REG_A1); size = *(get_regs(context) + REG_A2); if (debug_read) printf("%s: trying to read %lu bytes from file with descriptor %lu into buffer at virtual address 0x%08lX\n", selfie_name, size, fd, (uint64_t) vbuffer); read_total = 0; bytes_to_read = WORDSIZE; failed = 0; while (size > 0) { if (size < bytes_to_read) bytes_to_read = size; if (is_virtual_address_valid(vbuffer, WORDSIZE)) if (is_data_stack_heap_address(context, vbuffer)) if (is_virtual_address_mapped(get_pt(context), vbuffer)) { buffer = translate_virtual_to_physical(get_pt(context), vbuffer); actually_read = buzz_read(buffer, bytes_to_read); if (actually_read == bytes_to_read) { read_total = read_total + actually_read; size = size - actually_read; if (size > 0) vbuffer = vbuffer + WORDSIZE; } else { if (signed_less_than(0, actually_read)) read_total = read_total + actually_read; size = 0; } } else { failed = 1; size = 0; printf("%s: reading into virtual address 0x%08lX failed because the address is unmapped\n", selfie_name, (uint64_t) vbuffer); } else { failed = 1; size = 0; printf("%s: reading into virtual address 0x%08lX failed because the address is in an invalid segment\n", selfie_name, (uint64_t) vbuffer); } else { failed = 1; size = 0; printf("%s: reading into virtual address 0x%08lX failed because the address is invalid\n", selfie_name, (uint64_t) vbuffer); } } if (failed) *(get_regs(context) + REG_A0) = sign_shrink(-1, SYSCALL_BITWIDTH); else *(get_regs(context) + REG_A0) = read_total; set_pc(context, get_pc(context) + INSTRUCTIONSIZE); if (debug_read) printf("%s: actually read %lu bytes from file with descriptor %lu\n", selfie_name, read_total, fd); if (debug_syscalls) { printf(" -> "); print_register_value(REG_A0); println(); } } // *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ // ----------------------------------------------------------------- // ---------------------- R U N T I M E ---------------------- // ----------------------------------------------------------------- // *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ *~*~ // ----------------------------------------------------------------- // ---------------------------- KERNEL ----------------------------- // ----------------------------------------------------------------- uint64_t handle_buzzed_system_call(uint64_t* context) { uint64_t a7; set_exception(context, EXCEPTION_NOEXCEPTION); set_ec_syscall(context, get_ec_syscall(context) + 1); a7 = *(get_regs(context) + REG_A7); if (a7 == SYSCALL_BRK) { if (is_gc_enabled(context)) implement_gc_brk(context); else implement_brk(context); } else if (a7 == SYSCALL_READ) { implement_buzzed_read(context); } else if (a7 == SYSCALL_WRITE) implement_write(context); else if (a7 == SYSCALL_OPENAT) implement_openat(context); else if (a7 == SYSCALL_EXIT) { implement_buzzed_exit(context); // TODO: exit only if all contexts have exited return EXIT; } else { printf("%s: unknown system call %lu\n", selfie_name, a7); set_exit_code(context, EXITCODE_UNKNOWNSYSCALL); return EXIT; } return DONOTEXIT; } uint64_t handle_buzzed_page_fault(uint64_t* context) { uint64_t page; set_exception(context, EXCEPTION_NOEXCEPTION); set_ec_page_fault(context, get_ec_page_fault(context) + 1); page = get_fault(context); // TODO: reuse frames if (pavailable()) { map_page(context, page, (uint64_t) palloc()); if (is_heap_address(context, virtual_address_of_page(page))) set_mc_mapped_heap(context, get_mc_mapped_heap(context) + PAGESIZE); return DONOTEXIT; } else { set_exit_code(context, sign_shrink(EXITCODE_OUTOFPHYSICALMEMORY, SYSCALL_BITWIDTH)); return EXIT; } } uint64_t handle_buzzed_timer(uint64_t* context) { set_exception(context, EXCEPTION_NOEXCEPTION); set_ec_timer(context, get_ec_timer(context) + 1); set_exit_code(context, sign_shrink(EXITCODE_OUTOFTIME, SYSCALL_BITWIDTH)); return EXIT; } uint64_t handle_buzzed_exception(uint64_t* context) { uint64_t exception; exception = get_exception(context); if (exception == EXCEPTION_SYSCALL) return handle_buzzed_system_call(context); else if (exception == EXCEPTION_PAGEFAULT) return handle_buzzed_page_fault(context); else if (exception == EXCEPTION_DIVISIONBYZERO) return handle_division_by_zero(context); else if (exception == EXCEPTION_TIMER) return handle_buzzed_timer(context); else { printf("%s: context %s threw uncaught exception: ", selfie_name, get_name(context)); print_exception(exception, get_fault(context)); println(); set_exit_code(context, EXITCODE_UNCAUGHTEXCEPTION); return EXIT; } } // ----------------------------------------------------------------- // ------------------------- BUZZING ENGINE ------------------------ // ----------------------------------------------------------------- uint64_t buzzr(uint64_t* to_context) { uint64_t timeout; uint64_t* from_context; timeout = TIMESLICE; while (1) { from_context = mipster_switch(to_context, timeout); if (get_parent(from_context) != MY_CONTEXT) { // switch to parent which is in charge of handling exceptions to_context = get_parent(from_context); timeout = TIMEROFF; } else if (handle_buzzed_exception(from_context) == EXIT) return get_exit_code(from_context); else { // TODO: scheduler should go here to_context = from_context; timeout = TIMESLICE; } } } uint64_t selfie_buzz() { uint64_t keep_buzzing; uint64_t exit_code; if (string_compare(argument, "-")) { if (number_of_remaining_arguments() > 0) { if (code_size == 0) { printf("%s: nothing to buzz\n", selfie_name); return EXITCODE_BADARGUMENTS; } reset_interpreter(); reset_profiler(); reset_microkernel(); init_memory(atoi(peek_argument(0))); run = 1; printf("%s: buzzing %s with %luMB physical memory\n", selfie_name, binary_name, PHYSICALMEMORYSIZE / MEGABYTE); printf("%s: >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n", selfie_name); TIMESLICE = 10000000; keep_buzzing = 1; while (keep_buzzing) { current_context = create_context(MY_CONTEXT, 0); // assert: number_of_remaining_arguments() > 0 boot_loader(current_context); // current_context is ready to run exit_code = buzzr(current_context); if (number_of_buzzed_inputs == 0) { printf("%s: unbuzzed %lu-bit RISC-U binary %s terminating with exit code %ld\n", selfie_name, WORDSIZEINBITS, binary_name, sign_extend(exit_code, SYSCALL_BITWIDTH)); keep_buzzing = 0; } else if (number_of_buzzed_inputs < MAX_BUZZES) { if (exit_code != 0) if (exit_code != EXITCODE_OUTOFTIME) printf("%s: %lu-bit RISC-U binary %s buzzed with %ld terminating with exit code %ld\n", selfie_name, WORDSIZEINBITS, binary_name, buzzed_input, sign_extend(exit_code, SYSCALL_BITWIDTH)); if (pavailable() == 0) keep_buzzing = 0; } else keep_buzzing = 0; } printf("%s: <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n", selfie_name); run = 0; printf("%s: ################################################################################\n", selfie_name); return EXITCODE_NOERROR; } else return EXITCODE_BADARGUMENTS; } else return EXITCODE_BADARGUMENTS; } // ----------------------------------------------------------------- // ----------------------------- MAIN ------------------------------ // ----------------------------------------------------------------- int main(int argc, char** argv) { uint64_t exit_code; init_selfie((uint64_t) argc, (uint64_t*) argv); init_library(); init_system(); init_target(); init_kernel(); exit_code = selfie(1); if (exit_code == EXITCODE_MOREARGUMENTS) exit_code = selfie_buzz(); return exit_selfie(exit_code, " - ..."); }