IMPORTANT
- 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:
crates/libafl_qemu/libafl_qemu_build/src/build.rs
around the code that invokes the C++ compiler with -r to generate:
libqemu-partially-linked.o
The generated link.command contains a linker argument that is shell-quoted with single quotes:
-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:
'--dynamic-list=/path/to/qemu-plugin.symbols'
instead of treating it as the linker option:
--dynamic-list=/path/to/qemu-plugin.symbols
The relevant part of build.rs is:
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:
fuzzers/full_system/qemu_baremetal/Cargo.toml
The build was performed with the default arm target feature.
Environment:
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: <please fill in the output of `git rev-parse HEAD`>
To Reproduce
Steps to reproduce the behavior:
-
Clone LibAFL and checkout the current main branch.
-
Go to the baremetal QEMU fuzzer example:
cd fuzzers/full_system/qemu_baremetal
- Build with verbose output:
RUST_BACKTRACE=1 CARGO_TERM_VERBOSE=true cargo build -vv
- The build fails during the
libafl_qemu_build partial linking step with:
thread 'main' panicked at crates/libafl_qemu/libafl_qemu_build/src/build.rs:526:13:
Linking failed.
- Inspect the generated files in the QEMU bridge build directory:
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:
-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:
thread 'main' panicked at crates/libafl_qemu/libafl_qemu_build/src/build.rs:526:13:
Linking failed.
The generated link.stderr contains:
/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:
-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:
cd target/debug/qemu-libafl-bridge/build
ninja -v
The QEMU bridge artifacts are generated successfully, for example:
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:
libqemu-partially-linked.o
I was able to build successfully by stripping surrounding quotes before passing arguments to Command::args().
For example:
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:
let fixed_cmd: Vec<String> = 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:
Finished `dev` profile [unoptimized + debuginfo] target(s) in 2m 46s
I am happy to submit a PR if this approach looks acceptable.
IMPORTANT
mainbranch.Thank you for making LibAFL better!
Describe the bug
When building
fuzzers/full_system/qemu_baremetal, the QEMU bridge itself appears to build successfully, butlibafl_qemu_buildfails during the partial linking step.The failure happens in:
around the code that invokes the C++ compiler with
-rto generate:The generated
link.commandcontains a linker argument that is shell-quoted with single quotes:Since Rust
Command::args()does not invoke a shell, the single quotes are passed literally told.As a result,
ldtries to find a file named:instead of treating it as the linker option:
The relevant part of
build.rsis:Because
Command::args()does not perform shell parsing, the quoted linker argument is passed to the linker unchanged.My fuzzer's
Cargo.tomlis the one from:The build was performed with the default
armtarget feature.Environment:
To Reproduce
Steps to reproduce the behavior:
Clone LibAFL and checkout the current
mainbranch.Go to the baremetal QEMU fuzzer example:
cd fuzzers/full_system/qemu_baremetallibafl_qemu_buildpartial linking step with:cd target/debug/qemu-libafl-bridge/build cat link.command cat link.stderrExpected behavior
The partial linking step should pass the linker argument without literal shell quotes.
Expected form:
or the build script should sanitize shell-quoted arguments before passing them to
Command::args().The build should finish successfully and generate the
qemu_baremetalbinary.Screen output/Screenshots
The build fails with:
The generated
link.stderrcontains:The generated
link.commandcontains:Running
ninja -vmanually inside the generated QEMU build directory does not report an error:cd target/debug/qemu-libafl-bridge/build ninja -vThe QEMU bridge artifacts are generated successfully, for example:
The failure happens later in the
libafl_qemu_buildpartial 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_buildperforms an additional partial link step to generate:I was able to build successfully by stripping surrounding quotes before passing arguments to
Command::args().For example:
and then:
After this local change, the build succeeds:
I am happy to submit a PR if this approach looks acceptable.