AFLplusplus / AFLplusplus/LibAFL

libafl_qemu_build partial linking fails because quoted --dynamic-list argument is passed literally to ld

Abierto
#3,827 0 comentarios 0 reacciones 0 asignados Ver en GitHub
bug
Lenguaje dominante
Rust
Estrellas
2.6k
Forks
481
Merge medio
2 d 30 min
PR fusionados (30 d)
16

Descripción

**IMPORTANT**
1. I have verified that the issue is present in the current `main` branch.

Thank you for making LibAFL better!

**Describe the bug**

When building `fuzzers/full_system/qemu_baremetal`, the QEMU bridge itself appears to build successfully, but `libafl_qemu_build` fails during the partial linking step.

The failure happens in:

```rust
crates/libafl_qemu/libafl_qemu_build/src/build.rs
```

around the code that invokes the C++ compiler with `-r` to generate:

```text
libqemu-partially-linked.o
```

The generated `link.command` contains a linker argument that is shell-quoted with single quotes:

```text
-Xlinker "'--dynamic-list=/home/xilizai/LibAFL/fuzzers/full_system/qemu_baremetal/target/debug/qemu-libafl-bridge/build/plugins/qemu-plugin.symbols'"
```

Since Rust `Command::args()` does not invoke a shell, the single quotes are passed literally to `ld`.

As a result, `ld` tries to find a file named:

```text
'--dynamic-list=/path/to/qemu-plugin.symbols'
```

instead of treating it as the linker option:

```text
--dynamic-list=/path/to/qemu-plugin.symbols
```

The relevant part of `build.rs` is:

```rust
let mut link_command = cpp_compiler.to_command();

link_command
.current_dir(&libafl_qemu_build_dir)
.arg("-o")
.arg("libqemu-partially-linked.o")
.arg("-r")
.args(cmd);
```

Because `Command::args()` does not perform shell parsing, the quoted linker argument is passed to the linker unchanged.

My fuzzer's `Cargo.toml` is the one from:

```text
fuzzers/full_system/qemu_baremetal/Cargo.toml
```

The build was performed with the default `arm` target feature.

Environment:

```text
OS: Ubuntu Linux
Host: x86_64
Rust toolchain: stable-x86_64-unknown-linux-gnu
Example: fuzzers/full_system/qemu_baremetal
Target feature: arm
qemu-libafl-bridge commit: c9c6db9127509e1eeaf10daad8fa6bc12cc54f56
qemu-libafl-bridge commit message: Merge pull request #123 from rmalmain/qemu_update_v10_2_0
LibAFL commit:
```

**To Reproduce**

Steps to reproduce the behavior:

1. Clone LibAFL and checkout the current `main` branch.

2. Go to the baremetal QEMU fuzzer example:

```bash
cd fuzzers/full_system/qemu_baremetal
```

3. Build with verbose output:

```bash
RUST_BACKTRACE=1 CARGO_TERM_VERBOSE=true cargo build -vv
```

4. The build fails during the `libafl_qemu_build` partial linking step with:

```text
thread 'main' panicked at crates/libafl_qemu/libafl_qemu_build/src/build.rs:526:13:
Linking failed.
```

5. Inspect the generated files in the QEMU bridge build directory:

```bash
cd target/debug/qemu-libafl-bridge/build
cat link.command
cat link.stderr
```

**Expected behavior**

The partial linking step should pass the linker argument without literal shell quotes.

Expected form:

```text
-Xlinker --dynamic-list=/path/to/qemu-plugin.symbols
```

or the build script should sanitize shell-quoted arguments before passing them to `Command::args()`.

The build should finish successfully and generate the `qemu_baremetal` binary.

**Screen output/Screenshots**

The build fails with:

```text
thread 'main' panicked at crates/libafl_qemu/libafl_qemu_build/src/build.rs:526:13:
Linking failed.
```

The generated `link.stderr` contains:

```text
/usr/bin/ld: cannot find '--dynamic-list=/home/xilizai/LibAFL/fuzzers/full_system/qemu_baremetal/target/debug/qemu-libafl-bridge/build/plugins/qemu-plugin.symbols': No such file or directory
collect2: error: ld returned 1 exit status
```

The generated `link.command` contains:

```text
-Xlinker "'--dynamic-list=/home/xilizai/LibAFL/fuzzers/full_system/qemu_baremetal/target/debug/qemu-libafl-bridge/build/plugins/qemu-plugin.symbols'"
```

Running `ninja -v` manually inside the generated QEMU build directory does not report an error:

```bash
cd target/debug/qemu-libafl-bridge/build
ninja -v
```

The QEMU bridge artifacts are generated successfully, for example:

```text
libqemu-system-arm.so
libqemuutil.a
subprojects/dtc/libfdt/libfdt.a
```

The failure happens later in the `libafl_qemu_build` partial linking step.

**Additional context**

This does not seem to be a missing dependency issue. The QEMU/Meson/Ninja build itself succeeds. The failure happens when `libafl_qemu_build` performs an additional partial link step to generate:

```text
libqemu-partially-linked.o
```

I was able to build successfully by stripping surrounding quotes before passing arguments to `Command::args()`.

For example:

```rust
fn unquote_link_arg(arg: String) -> String {
if arg.len() >= 2 {
let bytes = arg.as_bytes();
let first = bytes[0];
let last = bytes[bytes.len() - 1];

if (first == b'\'' && last == b'\'') || (first == b'"' && last == b'"') {
return arg[1..arg.len() - 1].to_string();
}
}

arg
}
```

and then:

```rust
let fixed_cmd: Vec = cmd.into_iter().map(unquote_link_arg).collect();

link_command
.current_dir(&libafl_qemu_build_dir)
.arg("-o")
.arg("libqemu-partially-linked.o")
.arg("-r")
.args(fixed_cmd);
```

After this local change, the build succeeds:

```text
Finished `dev` profile [unoptimized + debuginfo] target(s) in 2m 46s
```

I am happy to submit a PR if this approach looks acceptable.

Guía de contribución

Abrir la guía de contribución

Evaluación

Este issue todavía no se ha evaluado.

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.