AFLplusplus / qemuafl

This fork of QEMU enables fuzzing userspace ELF binaries under AFL++.

Home Page:https://aflplus.plus

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Binaries compiled with musl break afl-qemu-trace forkserver behaviour.

forky2 opened this issue · comments

commented

When a target static musl binary is run with AFL_ENTRYPOINT defined, all non-crashing test inputs will produce a crash after a crashing test input is run.

Cause

Unlike GLIBC which will always make a syscall to gettid for its TID, musl caches a thread's TID in the TLS. This is fine for normal fork operations as musl will update the TLS after the fork with a syscall to gettid. However, in the magical case where QEMU is forking the process unbeknownst to the guest process, the child process will keep an invalid TID and use it in calls such as tkill(int tid, int sig).

Remediation

Whilst we might prefer that musl had not implemented its TID recording in this way I don't think this is a musl bug. I propose that the syscall translation in qemuafl modifies such spurious syscalls so that they behave as intended.

By way of example:

  • Say the QEMU forkserver parent TID is 10 just before forking.
  • And the QEMU forkserver child TID is 15 just after forking.
  • Keep these two values in globals so that when a call to __safe_tkill() is made
    • the value of arg1 is compared to parent TID.
    • if and only if they are equal, arg1 is replaced with the recorded value of
      child TID.

I have done a proof of concept of this which is successful at resolving the issue, but it is a bit messy.

I've only tested a fix for tkill in linux-user. I've not done it for other syscalls that take a TID nor have I looked into bsd-user.

Issue repository

I've created a repository to demonstrate the issue.