AFLplusplus / AFLplusplus/LibAFL

SIGSEGV when using QemuForkExecutor in "arm" feature, and Unknown error: Unix error: ECHILD

Open
#2,632 6 comments 0 reactions 0 assignees View on GitHub
qemu
Dominant language
Rust
Stars
2.6k
Forks
481
Avg merge
2d 30m
Merged PRs (30d)
16

Description

The issue to be present in the current main branch
```bash
$ git log | head -n 1
commit dfd5609c10da85f32e0dec74a72a432acd85310a
```
**Describe the issue**
I am doing some fuzzing practice using an tenda VC 15 router httpd, which is **32-bit arm** architecture. I use a QemuForkExecutor, but got an error when load the initial inputs:

```
Failed to load initial corpus at ["./seed/"]
```

I print the error,
``` rust
if state.must_load_initial_inputs() {
state
.load_initial_inputs(&mut fuzzer, &mut executor, &mut mgr, &intial_dirs)
.unwrap_or_else(|a| {
println!("{}", a);
println!("Failed to load initial corpus at {:?}", &intial_dirs);
process::exit(0);
});
println!("We imported {} inputs from disk.", state.corpus().count());
}
```
and it says:
```
Unknown error: Unix error: ECHILD
```

I debug the fuzzer, and find out that the fuzzer receives a SIGSEGV in trace_edge_hitcount_ptr:
```rust
715 pub unsafe extern "C" fn trace_edge_hitcount_ptr(_: *const (), id: u64) {
716 unsafe {
717 let ptr = LIBAFL_QEMU_EDGES_MAP_PTR.add(id as usize);
► 718 *ptr = (*ptr).wrapping_add(1);
719 }
720 }

pwndbg> p ptr
$1 = (*mut u8) 0x4d55bbdb022cd456
pwndbg> p *ptr
Cannot access memory at address 0x4d55bbdb022cd456
```
It seems that the value of ptr cannot be dereferenced. I know that this function is used to record the coverage, but I don't know what "id" or "ptr" mean. So I read the related instrumentation code in qemu-libafl-bridge.

``` c
//$ git log | head -n 1
//commit 805b14ffc44999952562e8f219d81c21a4fa50b9

// in accel/tcg/cpu_exec.c, cpu_exec_loop
//// --- Begin LibAFL code ---

bool libafl_edge_generated = false;
TranslationBlock *edge;

/* See if we can patch the calling TB. */
if (last_tb) {
// tb_add_jump(last_tb, tb_exit, tb);

if (last_tb->jmp_reset_offset[1] != TB_JMP_OFFSET_INVALID) {
mmap_lock();
edge = libafl_gen_edge(cpu, last_tb->pc, pc, tb_exit, cs_base, flags, cflags);
mmap_unlock();

if (edge) {
tb_add_jump(last_tb, tb_exit, edge);
tb_add_jump(edge, 0, tb);
libafl_edge_generated = true;
} else {
tb_add_jump(last_tb, tb_exit, tb);
}
} else {
tb_add_jump(last_tb, tb_exit, tb);
}
}

if (libafl_edge_generated) {
// execute the edge to make sure to log it the first execution
// the edge will then jump to the translated block
cpu_loop_exec_tb(cpu, edge, pc, &last_tb, &tb_exit);
} else {
cpu_loop_exec_tb(cpu, tb, pc, &last_tb, &tb_exit);
}

//// --- End LibAFL code ---
```
My understanding is: if a new translation block is generated by `libafl_gen_edge`, it is executed first, and then it is recorded on the coverage graph by jumping to `trace_edge_hitcount_ptr` through the hook. (I use StdEdgeCoverageChildModule, and I remember it used the edge type hook.)
Also, I debugged this part of codes. Considering the contents of the `TranslationBlock` structure, I found the specific contents of the `edge` variable:
```
// edge->tc.ptr
pwndbg> p/x *itb
$7 = {
pc = 0x40a23030,
cs_base = 0x480,
flags = 0x0,
cflags = 0x800010,
size = 0x1,
icount = 0x1,
tc = {
ptr = 0x710ee4e00740,
size = 0x38
},
itree = {
rb = {
rb_parent_color = 0xfec7058d4840804b,
rb_right = 0x48fffff959e9ffff,
rb_left = 0x4de9fffffebd058d
},
start = 0x40a23030,
last = 0xffffffffffffffff,
subtree_last = 0x0
},
jmp_lock = {
value = 0x0
},
jmp_reset_offset = {0x20, 0xffff},
jmp_insn_offset = {0x1c, 0xffff},
jmp_target_addr = {0x710ee4e00500, 0x0},
jmp_list_head = 0x710ee4e002c0,
jmp_list_next = {0x0, 0x0},
jmp_dest = {0x710ee4e00440, 0x0}
}

pwndbg> x/16x 0x710ee4e00740
0x710ee4e00740 : 0x3456be48 0x43f7dbc5 0xbf484d55 0x7f076fa0
```
Note the value of `tc.ptr` here. It is . The machine code it points to is `0x43f7dbc53456be48`, and gdb told me it means `movabs rsi, 0x4d5543f7dbc53456`.
While tracing the code flow later, I found that the fuzzer jumped to a small section of code hook to prepare parameters(moving to rdi and rsi), and then jumped to `trace_edge_hitcount_ptr`.
```bash
0x5a457a1901df mov r12, qword ptr [r8 + 0x20]
0x5a457a1901e3 test eax, 0x120
0x5a457a1901e8 jne cpu_exec_loop.isra+1720
0x5a457a1901ee lea rax, [rip + 0x3d2c0cb] RAX => 0x5a457debc2c0 (tcg_qemu_tb_exec) —▸ 0x710ee4e00000 ◂— push rbp /* 0x5641554154415355 */

// R12 is 0x710ee4e00740 (code_gen_buffer+1811) ◂— movabs rsi, 0x4d5543f7dbc53456 /* 0x43f7dbc53456be48 */

0x710ee4e00000 push rbp
0x710ee4e00001 push rbx
0x710ee4e00002 push r12
0x710ee4e00004 push r13
0x710ee4e00006 push r14
0x710ee4e00008 push r15
0x710ee4e0000a mov rbp, rdi RBP => 0x5a457f038920 ◂— 0x123fb400000000
0x710ee4e0000d add rsp, -0x488 RSP => 0x7ffffcc93560 (0x7ffffcc939e8 + -0x488)
0x710ee4e00014 jmp rsi

0x710ee4e00740 movabs rsi, 0x4d5543f7dbc53456 RSI => 0x4d5543f7dbc53456
0x710ee4e0074a movabs rdi, 0x5a457f076fa0 RDI => 0x5a457f076fa0 ◂— 0
► 0x710ee4e00754 call qword ptr [rip + 0x16]
rdi: 0x5a457f076fa0 ◂— 0
rsi: 0x4d5543f7dbc53456
```
This seems to indicate that the number following `movabs rsi,` will become the `id`. But the values ​​I have here don't look right.

My issues now are as follows:
1. What does id actually represent?
2. How is it calculated?
3. How can I solve this problem?
4. Do I need to provide any additional information?

Thank you very much!

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.