Skip to content

Breakpoints on multithreaded linux user-mode programs #122

@rliebig

Description

@rliebig

Currently, if the

emu.set_breakpoint(guest_addr):

Feature is used to define a breakpoint, the execution is only yielded back if the same thread that set the breakpoint hits the target address. If another thread hits this breakpoint, this does stop this specific thread but does not yield execution to the rust wrapper code back.

The reason is likely inside libafl/exit.c prepare_qemu_exit, which is used by the breakpoint api to throw cpu_loop_exit:

static void prepare_qemu_exit(CPUState* cpu, target_ulong next_pc)
{
    expected_exit = true;
    last_exit_reason.cpu = cpu;
    last_exit_reason.next_pc = next_pc;

#if !defined(CONFIG_USER_ONLY) && defined(AS_LIB)
    qemu_system_return_request();
#endif

     if (cpu->running) {
            cpu->exception_index = EXCP_LIBAFL_EXIT;
            cpu_loop_exit(cpu);
     }
        
}

A workaround seems to be available in iterating over all CPUs, which are in linux user-mode actually threads, and using qemu_cpu_kick to request a shutdown:

    CPU_FOREACH(cpu) {
        if (cpu->running) {
            cpu->exception_index = EXCP_LIBAFL_EXIT;
            qemu_cpu_kick(cpu);
        }
    }

This does however suffer from race conditions. Calling cpu_loop_exit(cpu) while iterating over the different CPUs seems to result in memory failures, therefore I presume some kind of lock is needed.

@rmalmain I would be more than happy to contribute a fix for this, but would like to hear some input in what you would believe to be a good solution for this problem.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions