Пример #1
0
/**
 * The entry point for passing a signal to a user signal handler
 *
 * See manpage for SA_SIGINFO function.
 */
void app_signal_handler(int signal, siginfo_t *siginfo, void *v_context) {
    int signal_index = signal_map[(signal % MAX_SIGNAL_NUM)];

    if ( (void *)app_actions[signal_index].sa_sigaction == (void *)SIG_IGN ) {
        udi_printf("Signal %d ignored, not passing to application\n", signal);
        return;
    }

    if ( (void *)app_actions[signal_index].sa_sigaction == (void *)SIG_DFL ) {
        // TODO need to emulate the default action
        return;
    }

    sigset_t cur_set;

    if ( setsigmask(SIG_SETMASK, &app_actions[signal_index].sa_mask,
                    &cur_set) != 0 )
    {
        udi_printf("failed to adjust blocked signals for application handler: %s\n",
                   strerror(errno));
    }

    app_actions[signal_index].sa_sigaction(signal, siginfo, v_context);

    if ( setsigmask(SIG_SETMASK, &cur_set, NULL) != 0 ) {
        udi_printf("failed to reset blocked signals after application handler: %s\n",
                   strerror(errno));
    }
}
Пример #2
0
/**
 * Install any breakpoints necessary to capture any interesting events
 * that cannot be captured by wrapping functions
 *
 * @param errmsg the errmsg populated on error
 *
 * @return 0 on success; non-zero on failure
 */
int install_event_breakpoints(udi_errmsg *errmsg) {
    int errnum = 0;

    do {
        // Exit cannot be wrappped because Linux executables can call it
        // directly and do not pass through the PLT
        exit_bp = create_breakpoint((udi_address)(unsigned long)exit);
        if ( exit_bp == NULL ) {
            udi_printf("%s\n", "failed to create exit breakpoint");
            errnum = -1;
            break;
        }

        errnum = install_breakpoint(exit_bp, errmsg);

        if ( errnum != 0 ) {
            udi_printf("%s\n", "failed to install exit breakpoint");
            errnum = -1;
            break;
        }

        if (get_multithread_capable()) {
            errnum = install_thread_event_breakpoints(errmsg);
        }

    } while(0);

    return errnum;
}
Пример #3
0
/**
 * Use dynamic loader to locate functions that are wrapped by library
 * wrappers
 *
 * @param errmsg the errmsg populated on error
 *
 * @return 0 on success; non-zero on failure
 */
int locate_wrapper_functions(udi_errmsg *errmsg) {
    int errnum = 0;
    char *errmsg_tmp;

    // reset dlerror()
    dlerror();

    do {
        // locate symbols for wrapper functions
        real_sigaction = (sigaction_type) dlsym(UDI_RTLD_NEXT, "sigaction");
        errmsg_tmp = dlerror();
        if (errmsg_tmp != NULL) {
            udi_printf("symbol lookup error: %s\n", errmsg_tmp);
            strncpy(errmsg->msg, errmsg_tmp, errmsg->size-1);
            errnum = -1;
            break;
        }

        real_fork = (fork_type) dlsym(UDI_RTLD_NEXT, "fork");
        errmsg_tmp = dlerror();
        if (errmsg_tmp != NULL) {
            udi_printf("symbol lookup error: %s\n", errmsg_tmp);
            strncpy(errmsg->msg, errmsg_tmp, errmsg->size-1);
            errnum = -1;
            break;
        }

        real_execve = (execve_type) dlsym(UDI_RTLD_NEXT, "execve");
        errmsg_tmp = dlerror();
        if (errmsg_tmp != NULL) {
            udi_printf("symbol lookup error: %s\n", errmsg_tmp);
            strncpy(errmsg->msg, errmsg_tmp, errmsg->size-1);
            errnum = -1;
            break;
        }

        real_signal = (signal_type) dlsym(UDI_RTLD_NEXT, "signal");
        errmsg_tmp = dlerror();
        if (errmsg_tmp != NULL) {
            udi_printf("symbol lookup error: %s\n", errmsg_tmp);
            strncpy(errmsg->msg, errmsg_tmp, errmsg->size-1);
            errnum = -1;
            break;
        }
    } while(0);

    return errnum;
}
Пример #4
0
/**
 * Determines the argument to the exit function, given the context at which the exit breakpoint
 * was hit
 *
 * @param context the current context
 * @param errmsg the error message populated by the memory access
 *
 * @return the exit result
 */
exit_result get_exit_argument(const ucontext_t *context, udi_errmsg *errmsg) {
    exit_result ret;
    ret.failure = 0;

    if (__WORDSIZE == 64) {
        // The exit argument is passed in rax
        ret.status = (int)context->uc_mcontext.gregs[X86_64_RAX_OFFSET];
    }else{
        // The exit argument is the first parameter on the stack

        // Get the stack pointer
        unsigned long sp;

        sp = (unsigned long)context->uc_mcontext.gregs[X86_ESP_OFFSET];

        int word_length = sizeof(unsigned long);

        // skip return address
        sp += word_length;

        int read_result = read_memory(&(ret.status), (const void *)sp, sizeof(int), errmsg);
        if ( read_result != 0 ) {
            udi_printf("failed to retrieve exit status off of the stack at 0x%lx\n",
                    sp);
            snprintf(errmsg->msg, errmsg->size,
                    "failed to retrieve exit status off of the stack at 0x%lx: %s",
                    sp, get_mem_errstr());
            ret.failure = read_result;
        }
    }

    return ret;
}
Пример #5
0
/**
 * Waits and executes a command -- used by syscall wrappers
 */
static
void wait_and_execute_command_with_response() {
    udi_errmsg errmsg;
    errmsg.size = ERRMSG_SIZE;
    errmsg.msg[ERRMSG_SIZE-1] = '\0';

    thread *request_thr;
    int req_result = wait_and_execute_command(&errmsg, &request_thr);

    if ( req_result != REQ_SUCCESS ) {
        if ( req_result > REQ_SUCCESS ) {
            strncpy(errmsg.msg, strerror(req_result), errmsg.size-1);
        }

        udi_printf("failed to process command: %s\n", errmsg.msg);

        udi_response resp = create_response_error(&errmsg);
        if ( resp.packed_data != NULL ) {
            // explicitly ignore errors
            if (request_thr != NULL) {
                write_response_to_thr_request(request_thr, &resp);
            } else {
                write_response(&resp);
            }
            udi_free(resp.packed_data);
        }
    }
}
Пример #6
0
/**
 * Sets up the signal handlers for all catchable signals
 *
 * @return 0 on success; non-zero on failure
 */
int setup_signal_handlers() {
    int errnum = 0;

    // Define the default sigaction for the library
    memset(&default_lib_action, 0, sizeof(struct sigaction));
    default_lib_action.sa_sigaction = signal_entry_point;
    sigfillset(&(default_lib_action.sa_mask));
    default_lib_action.sa_flags = SA_SIGINFO | SA_NODEFER;

    // initialize application sigactions and signal map
    int i;
    for (i = 0; i < NUM_SIGNALS; ++i) {
        memset(&app_actions[i], 0, sizeof(struct sigaction));
        app_actions[i].sa_handler = SIG_DFL;

        signal_map[(signals[i] % MAX_SIGNAL_NUM)] = i;
    }

    // Sanity check
    if ( (sizeof(signals) / sizeof(int)) != NUM_SIGNALS ) {
        udi_printf("%s\n", "ASSERT FAIL: signals array length != NUM_SIGNALS");
        return -1;
    }

    for(i = 0; i < NUM_SIGNALS; ++i) {
        if ( real_sigaction(signals[i], &default_lib_action, &app_actions[i]) != 0 ) {
            errnum = errno;
            break;
        }
    }

    return errnum;
}
Пример #7
0
/**
 * The wrapper function for the fork system call.
 *
 * See fork manpage for description.
 */
pid_t fork() {

    pid_t child = real_fork();
    if ( child == 0 ) {
        reinit_udi_rt();
    } else {
        uint64_t thread_id = get_user_thread_id();

        udi_printf(">>> fork entry for 0x%"PRIx64"/%u\n",
                   get_user_thread_id(),
                   get_kernel_thread_id());

        // Need to continue waiting until this thread owns the control of the process
        int block_result = 1;
        while (block_result > 0) {
            block_result = block_other_threads();
            if ( block_result == -1 ) {
                udi_printf("%s\n", "failed to block other threads");
                errno = EAGAIN;
                return -1;
            }
        }

        // create the event
        udi_event_internal event = create_event_fork(thread_id, child);
        do {
            int errnum = write_event(&event);
            if ( errnum != 0 ) {
                udi_printf("failed to write fork event: %s\n", strerror(errnum));
                errno = EAGAIN;
                return -1;
            }
        } while(0);

        wait_and_execute_command_with_response();

        int release_result = release_other_threads();
        if ( release_result != 0 ) {
            udi_printf("%s\n", "failed to release other threads");
            errno = EAGAIN;
            return -1;
        }
    }

    return child;
}
Пример #8
0
/**
 * Gets mapped memory from the OS
 *
 * @param length the size of memory area to map (in bytes)
 *
 * @return the mapped memory
 */
unsigned char *map_mem(size_t length) {
    void * ret = mmap(NULL, length, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS 
            | MAP_PRIVATE, -1, 0);

    if ( ret == MAP_FAILED ) {
        udi_printf("mmap failed: %s\n", strerror(errno));
        return NULL;
    }

    return ret;
}
Пример #9
0
/**
 * Handle the occurence of a hit on the exit breakpoint. This includes gathering all information
 * neccessary to create the exit event.
 *
 * @param context the context for the breakpoint
 * @param errmsg the error message populated on error
 *
 * @return the information extracted about the exit event
 */
static
event_result handle_exit_breakpoint(const ucontext_t *context, udi_errmsg *errmsg) {

    event_result result;
    result.failure = 0;
    result.wait_for_request = 1;

    exit_result exit_result = get_exit_argument(context, errmsg);

    if ( exit_result.failure ) {
        result.failure = exit_result.failure;
        return result;
    }

    udi_printf("exit entered with status %d\n", exit_result.status);
    exiting = 1;

    // create the event
    udi_event_internal exit_event = create_event_exit(get_user_thread_id(), exit_result.status);
    do {
        if ( exit_event.packed_data == NULL ) {
            result.failure = 1;
            break;
        }

        result.failure = write_event(&exit_event);

        udi_free(exit_event.packed_data);
    } while(0);

    if ( result.failure ) {
        udi_printf("failed to report exit status of %d\n", exit_result.status);
    } else {
        if ( udi_debug_on ) {
            dump_heap();
        }
    }

    return result;
}