Librasan (#3023)
* Fixes to main * Add librasan * Party like it's 2024 * Fix snapshot module to work with guest asan * Fix guest_asan module * Fixes to runner * Fix linking issues using a REL * Fix qemu_launcher * Change modify_mapping to a method * Fix gasan_test * Remove debug from Justfile * Optimize release build of librasan * Set ulimit for qasan and gasan tests * Tidy up symbol renaming * Add missing symbols for PPC * Change to support rustix 1.0.0 * Canonicalize the CUSTOM_ASAN_PATH * Review changes * Restructure backends * release_max_level_info * More review changes * Clippy fixes * Changes to reduce the burden on the CI * Fix macos clippy --------- Co-authored-by: Your Name <you@example.com>
This commit is contained in:
parent
f64554c5db
commit
728b1216bb
41
.github/workflows/build_and_test.yml
vendored
41
.github/workflows/build_and_test.yml
vendored
@ -62,10 +62,10 @@ jobs:
|
||||
if: runner.os == 'MacOS'
|
||||
run: cd docs && mdbook test -L ../target/debug/deps $(python3-config --ldflags | cut -d ' ' -f1)
|
||||
- name: Run tests (Windows)
|
||||
if: runner.os == 'Windows'
|
||||
if: runner.os == 'Windows'
|
||||
run: cargo test -- --test-threads 1
|
||||
- name: Run tests (Linux)
|
||||
if: runner.os != 'Windows'
|
||||
if: runner.os != 'Windows'
|
||||
run: cargo test -- --test-threads 1
|
||||
- name: Test libafl no_std
|
||||
run: cd libafl && cargo test --no-default-features
|
||||
@ -404,6 +404,43 @@ jobs:
|
||||
shell: bash
|
||||
run: ARCH=${{ matrix.arch }} RUN_ON_CI=1 LLVM_CONFIG=llvm-config-${{env.MAIN_LLVM_VERSION}} ./scripts/test_fuzzer.sh ${{ matrix.fuzzer }}
|
||||
|
||||
librasan-build:
|
||||
runs-on: ubuntu-24.04
|
||||
needs:
|
||||
- changes
|
||||
if: ${{ needs.changes.outputs.qemu == 'true' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./.github/workflows/librasan-prepare
|
||||
- name: Build
|
||||
if: runner.os == 'Linux'
|
||||
shell: bash
|
||||
run: |
|
||||
RUN_ON_CI=1 \
|
||||
LLVM_CONFIG=llvm-config-${{env.MAIN_LLVM_VERSION}} \
|
||||
just \
|
||||
-f ./libafl_qemu/librasan/Justfile \
|
||||
build_everything_dev \
|
||||
build_x86_64_release
|
||||
|
||||
librasan-test:
|
||||
runs-on: ubuntu-24.04
|
||||
needs:
|
||||
- changes
|
||||
if: ${{ needs.changes.outputs.qemu == 'true' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./.github/workflows/librasan-prepare
|
||||
- name: Build
|
||||
if: runner.os == 'Linux'
|
||||
shell: bash
|
||||
run: |
|
||||
RUN_ON_CI=1 \
|
||||
LLVM_CONFIG=llvm-config-${{env.MAIN_LLVM_VERSION}} \
|
||||
just \
|
||||
-f ./libafl_qemu/librasan/Justfile \
|
||||
test_everything
|
||||
|
||||
fuzzers-qemu-system:
|
||||
needs:
|
||||
- changes
|
||||
|
73
.github/workflows/librasan-prepare/action.yml
vendored
Normal file
73
.github/workflows/librasan-prepare/action.yml
vendored
Normal file
@ -0,0 +1,73 @@
|
||||
name: Setup QEMU librasan environment
|
||||
description: Sets up the QEMU librasan environment
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Enable i386
|
||||
shell: bash
|
||||
run: sudo dpkg --add-architecture i386
|
||||
- name: Install QEMU deps
|
||||
shell: bash
|
||||
run: |
|
||||
sudo apt-get update && \
|
||||
DEBIAN_FRONTEND=noninteractive \
|
||||
sudo apt-get install -y \
|
||||
build-essential \
|
||||
clang-18 \
|
||||
clang++-18 \
|
||||
cmake \
|
||||
curl \
|
||||
g++-aarch64-linux-gnu \
|
||||
g++-arm-linux-gnueabi \
|
||||
g++-i686-linux-gnu \
|
||||
g++-mipsel-linux-gnu \
|
||||
g++-powerpc-linux-gnu \
|
||||
gcc-aarch64-linux-gnu \
|
||||
gcc-arm-linux-gnueabi \
|
||||
gcc-i686-linux-gnu \
|
||||
gcc-mipsel-linux-gnu \
|
||||
gcc-powerpc-linux-gnu \
|
||||
gdb \
|
||||
gdb-multiarch \
|
||||
git \
|
||||
gnupg \
|
||||
libc6-dev:i386 \
|
||||
libclang-dev \
|
||||
libgcc-13-dev:i386 \
|
||||
libglib2.0-dev \
|
||||
lsb-release \
|
||||
ninja-build \
|
||||
python3 \
|
||||
python3-pip \
|
||||
python3-venv \
|
||||
qemu-user \
|
||||
software-properties-common \
|
||||
wget
|
||||
- uses: dtolnay/rust-toolchain@nightly
|
||||
- name: install just
|
||||
uses: extractions/setup-just@v2
|
||||
with:
|
||||
just-version: 1.39.0
|
||||
- name: Install cargo-binstall
|
||||
shell: bash
|
||||
run: |
|
||||
curl -L --proto '=https' --tlsv1.2 -sSf \
|
||||
https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | \
|
||||
bash
|
||||
- name: Install nextest
|
||||
shell: bash
|
||||
run: |
|
||||
cargo binstall --no-confirm cargo-nextest
|
||||
- name: Install Rust Targets
|
||||
shell: bash
|
||||
run: |
|
||||
rustup target add armv7-unknown-linux-gnueabi && \
|
||||
rustup target add aarch64-unknown-linux-gnu && \
|
||||
rustup target add i686-unknown-linux-gnu && \
|
||||
rustup target add powerpc-unknown-linux-gnu
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: 0
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with: { shared-key: "${{ runner.os }}-shared-fuzzer-cache" }
|
4
.github/workflows/ubuntu-prepare/action.yml
vendored
4
.github/workflows/ubuntu-prepare/action.yml
vendored
@ -7,6 +7,10 @@ runs:
|
||||
shell: bash
|
||||
run: sudo apt-get update && sudo apt-get install -y curl lsb-release wget software-properties-common gnupg ninja-build shellcheck pax-utils nasm libsqlite3-dev libc6-dev libgtk-3-dev gcc g++ gcc-arm-none-eabi gcc-arm-linux-gnueabi g++-arm-linux-gnueabi libslirp-dev libz3-dev build-essential cmake
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- name: install just
|
||||
uses: extractions/setup-just@v2
|
||||
with:
|
||||
just-version: 1.39.0
|
||||
- name: Add stable clippy
|
||||
shell: bash
|
||||
run: rustup toolchain install stable --component clippy --allow-downgrade
|
||||
|
@ -96,6 +96,7 @@ cmake = "0.1.51"
|
||||
document-features = "0.2.10"
|
||||
fastbloom = { version = "0.9.0", default-features = false }
|
||||
hashbrown = { version = "0.14.5", default-features = false } # A faster hashmap, nostd compatible
|
||||
just = "1.40.0"
|
||||
libc = "0.2.159" # For (*nix) libc
|
||||
libipt = "0.3.0"
|
||||
log = "0.4.22"
|
||||
|
@ -47,7 +47,10 @@ libafl = { path = "../../../libafl", features = ["tui_monitor"] }
|
||||
libafl_bolts = { path = "../../../libafl_bolts", features = [
|
||||
"errors_backtrace",
|
||||
] }
|
||||
libafl_qemu = { path = "../../../libafl_qemu", features = ["usermode"] }
|
||||
libafl_qemu = { path = "../../../libafl_qemu", features = [
|
||||
"usermode",
|
||||
"rasan",
|
||||
] }
|
||||
libafl_targets = { path = "../../../libafl_targets" }
|
||||
log = { version = "0.4.22", features = ["release_max_level_info"] }
|
||||
nix = { version = "0.29.0", features = ["fs"] }
|
||||
|
@ -31,6 +31,10 @@ harness: libpng
|
||||
|
||||
[unix]
|
||||
run: harness build
|
||||
#!/bin/bash
|
||||
|
||||
source {{ DOTENV }}
|
||||
CUSTOM_QASAN_PATH={{ BUILD_DIR }}/$CROSS_TARGET/{{ PROFILE_DIR }}/libqasan.so \
|
||||
{{ FUZZER }} \
|
||||
--input ./corpus \
|
||||
--output {{ TARGET_DIR }}/output/ \
|
||||
@ -56,7 +60,12 @@ test_inner: harness build
|
||||
|
||||
# complie again with simple mgr
|
||||
cargo build --profile={{PROFILE}} --features="simplemgr,{{ARCH}}" --target-dir={{ TARGET_DIR }} || exit 1
|
||||
./tests/qasan/test.sh || exit 1
|
||||
|
||||
export CUSTOM_QASAN_PATH={{ BUILD_DIR }}/$CROSS_TARGET/{{ PROFILE_DIR }}/libqasan.so
|
||||
./tests/qasan/qasan_test.sh || exit 1
|
||||
|
||||
export CUSTOM_GASAN_PATH={{ BUILD_DIR }}/$CROSS_TARGET/{{ PROFILE_DIR }}/libgasan.so
|
||||
./tests/qasan/gasan_test.sh || exit 1
|
||||
|
||||
[unix]
|
||||
test:
|
||||
@ -72,6 +81,10 @@ single: harness build
|
||||
{{ HARNESS }}
|
||||
|
||||
asan: harness build
|
||||
#!/bin/bash
|
||||
|
||||
source {{ DOTENV }}
|
||||
CUSTOM_QASAN_PATH={{ BUILD_DIR }}/$CROSS_TARGET/{{ PROFILE_DIR }}/libqasan.so \
|
||||
{{ FUZZER }} \
|
||||
--input ./corpus \
|
||||
--output {{ TARGET_DIR }}/output/ \
|
||||
@ -82,6 +95,10 @@ asan: harness build
|
||||
{{ HARNESS }}
|
||||
|
||||
asan_guest: harness build
|
||||
#!/bin/bash
|
||||
|
||||
source {{ DOTENV }}
|
||||
CUSTOM_GASAN_PATH={{ BUILD_DIR }}/$CROSS_TARGET/{{ PROFILE_DIR }}/libgasan.so \
|
||||
{{ FUZZER }} \
|
||||
--input ./corpus \
|
||||
--output {{ TARGET_DIR }}/output/ \
|
||||
@ -93,4 +110,4 @@ asan_guest: harness build
|
||||
|
||||
[unix]
|
||||
clean:
|
||||
cargo clean
|
||||
cargo clean
|
||||
|
@ -126,6 +126,16 @@ impl Client<'_> {
|
||||
unsafe { AsanModule::builder().env(&env).asan_report().build() }
|
||||
);
|
||||
|
||||
instance_builder.build().run(args, modules, state)
|
||||
} else if is_asan_guest {
|
||||
let modules = tuple_list!(
|
||||
DrCovModule::builder()
|
||||
.filename(drcov.clone())
|
||||
.full_trace(true)
|
||||
.build(),
|
||||
AsanGuestModule::default(&env),
|
||||
);
|
||||
|
||||
instance_builder.build().run(args, modules, state)
|
||||
} else {
|
||||
let modules = tuple_list!(DrCovModule::builder()
|
||||
@ -139,6 +149,10 @@ impl Client<'_> {
|
||||
let modules =
|
||||
tuple_list!(unsafe { AsanModule::builder().env(&env).asan_report().build() });
|
||||
|
||||
instance_builder.build().run(args, modules, state)
|
||||
} else if is_asan_guest {
|
||||
let modules = tuple_list!(AsanGuestModule::default(&env));
|
||||
|
||||
instance_builder.build().run(args, modules, state)
|
||||
} else {
|
||||
let modules = tuple_list!();
|
||||
|
@ -8,9 +8,9 @@ use clap::Parser;
|
||||
#[cfg(feature = "simplemgr")]
|
||||
use libafl::events::SimpleEventManager;
|
||||
#[cfg(not(feature = "simplemgr"))]
|
||||
use libafl::events::{EventConfig, Launcher, MonitorTypedEventManager};
|
||||
use libafl::events::{EventConfig, Launcher, LlmpEventManagerBuilder, MonitorTypedEventManager};
|
||||
use libafl::{
|
||||
events::{ClientDescription, LlmpEventManagerBuilder},
|
||||
events::ClientDescription,
|
||||
monitors::{tui::TuiMonitor, Monitor, MultiMonitor},
|
||||
Error,
|
||||
};
|
||||
|
@ -44,7 +44,8 @@ use libafl_qemu::{
|
||||
cmplog::CmpLogObserver,
|
||||
edges::EdgeCoverageFullVariant,
|
||||
utils::filters::{HasAddressFilter, NopPageFilter, StdAddressFilter},
|
||||
EdgeCoverageModule, EmulatorModuleTuple, SnapshotModule, StdEdgeCoverageModule,
|
||||
AsanGuestModule, EdgeCoverageModule, EmulatorModuleTuple, SnapshotModule,
|
||||
StdEdgeCoverageModule,
|
||||
},
|
||||
Emulator, GuestAddr, Qemu, QemuExecutor,
|
||||
};
|
||||
@ -153,7 +154,7 @@ impl<M: Monitor> Instance<'_, M> {
|
||||
.map_observer(edges_observer.as_mut())
|
||||
.build()?;
|
||||
|
||||
let mut snapshot_module = SnapshotModule::new();
|
||||
let mut snapshot_module = SnapshotModule::with_filters(AsanGuestModule::snapshot_filters());
|
||||
|
||||
/*
|
||||
* Since the generics for the modules are already excessive when taking
|
||||
|
1
fuzzers/binary_only/qemu_launcher/tests/qasan/.gitignore
vendored
Normal file
1
fuzzers/binary_only/qemu_launcher/tests/qasan/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/qasan
|
75
fuzzers/binary_only/qemu_launcher/tests/qasan/gasan_test.sh
Executable file
75
fuzzers/binary_only/qemu_launcher/tests/qasan/gasan_test.sh
Executable file
@ -0,0 +1,75 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
|
||||
if [[ ! -x "$QEMU_LAUNCHER" ]]; then
|
||||
echo "env variable QEMU_LAUNCHER does not point to a valid executable"
|
||||
echo "QEMU_LAUNCHER should point to qemu_launcher"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd "$SCRIPT_DIR"
|
||||
make
|
||||
|
||||
tests=(
|
||||
"overflow"
|
||||
"underflow"
|
||||
"double_free"
|
||||
"memset"
|
||||
"uaf"
|
||||
"test_limits"
|
||||
)
|
||||
|
||||
tests_expected=(
|
||||
"Segmentation fault"
|
||||
"Segmentation fault"
|
||||
"Panic!"
|
||||
"Panic!"
|
||||
"Segmentation fault"
|
||||
"Test-Limits - No Error"
|
||||
)
|
||||
|
||||
tests_not_expected=(
|
||||
"dummy"
|
||||
"dummy"
|
||||
"dummy"
|
||||
"dummy"
|
||||
"dummy"
|
||||
"Context:"
|
||||
)
|
||||
|
||||
# We don't want any core dumps. They can potentially be quite large
|
||||
ulimit -c 0
|
||||
|
||||
for i in "${!tests[@]}"
|
||||
do
|
||||
test="${tests[i]}"
|
||||
expected="${tests_expected[i]}"
|
||||
not_expected="${tests_not_expected[i]}"
|
||||
|
||||
echo "Running $test detection test..."
|
||||
OUT=$("$QEMU_LAUNCHER" \
|
||||
-r "inputs/$test.txt" \
|
||||
--input dummy \
|
||||
--output out \
|
||||
--asan-guest-cores 0 \
|
||||
--cores 0 \
|
||||
-- qasan 2>&1 | tr -d '\0')
|
||||
|
||||
echo "$OUT"
|
||||
|
||||
if ! echo "$OUT" | grep -q "$expected"; then
|
||||
echo "ERROR: Expected: $expected."
|
||||
echo "Output is:"
|
||||
echo "$OUT"
|
||||
exit 1
|
||||
elif echo "$OUT" | grep -q "$not_expected"; then
|
||||
echo "ERROR: Did not expect: $not_expected."
|
||||
echo "Output is:"
|
||||
echo "$OUT"
|
||||
exit 1
|
||||
else
|
||||
echo "OK."
|
||||
fi
|
||||
done
|
@ -71,13 +71,7 @@ int main(int argc, char **argv) {
|
||||
|
||||
char input = '\0';
|
||||
|
||||
// if (read(STDIN_FILENO, &input, 1) < 0) {
|
||||
|
||||
// LOG("Failed to read stdin\n");
|
||||
// return 1;
|
||||
|
||||
// }
|
||||
|
||||
if (argc > 1) { input = argv[1][0]; }
|
||||
LLVMFuzzerTestOneInput(&input, 1);
|
||||
|
||||
LOG("DONE\n");
|
||||
|
@ -22,11 +22,11 @@ tests=(
|
||||
)
|
||||
|
||||
tests_expected=(
|
||||
"is 0 bytes to the right of the 10-byte chunk"
|
||||
"is 1 bytes to the left of the 10-byte chunk"
|
||||
"is 0 bytes inside the 10-byte chunk"
|
||||
"Invalid 11 bytes write at"
|
||||
"is 0 bytes inside the 10-byte chunk"
|
||||
"AddressSanitizer Error"
|
||||
"AddressSanitizer Error"
|
||||
"Panic!"
|
||||
"AddressSanitizer Error"
|
||||
"AddressSanitizer Error"
|
||||
"Test-Limits - No Error"
|
||||
)
|
||||
|
||||
@ -39,6 +39,9 @@ tests_not_expected=(
|
||||
"Context:"
|
||||
)
|
||||
|
||||
# We don't want any core dumps. They can potentially be quite large
|
||||
ulimit -c 0
|
||||
|
||||
for i in "${!tests[@]}"
|
||||
do
|
||||
test="${tests[i]}"
|
@ -1,3 +1,7 @@
|
||||
CROSS_TARGET="aarch64-unknown-linux-gnu"
|
||||
CROSS_CC="aarch64-linux-gnu-gcc"
|
||||
CROSS_CXX="aarch64-linux-gnu-g++"
|
||||
CROSS_CFLAGS=""
|
||||
CROSS_OBJCOPY="aarch64-linux-gnu-objcopy"
|
||||
CROSS_STRIP="aarch64-linux-gnu-strip"
|
||||
CROSS_CFLAGS=""
|
||||
LIBRASAN_CFLAGS="-no-pie -fno-stack-protector"
|
||||
|
@ -1,3 +1,7 @@
|
||||
CROSS_TARGET="armv7-unknown-linux-gnueabi"
|
||||
CROSS_CC="arm-linux-gnueabi-gcc"
|
||||
CROSS_CXX="arm-linux-gnueabi-g++"
|
||||
CROSS_CFLAGS=""
|
||||
CROSS_OBJCOPY="arm-linux-gnueabi-objcopy"
|
||||
CROSS_STRIP="arm-linux-gnueabi-strip"
|
||||
CROSS_CFLAGS=""
|
||||
LIBRASAN_CFLAGS="-no-pie -fno-stack-protector -marm"
|
||||
|
@ -1,3 +1,7 @@
|
||||
CROSS_TARGET="i686-unknown-linux-gnu"
|
||||
CROSS_CC="i686-linux-gnu-gcc"
|
||||
CROSS_CXX="i686-linux-gnu-g++"
|
||||
CROSS_OBJCOPY="i686-linux-gnu-objcopy"
|
||||
CROSS_STRIP="i686-linux-gnu-strip"
|
||||
CROSS_CFLAGS="-m32"
|
||||
LIBRASAN_CFLAGS="-m32 -no-pie -fno-stack-protector"
|
||||
|
@ -1,3 +1,3 @@
|
||||
CROSS_CC="mipsel-linux-gnu-gcc"
|
||||
CROSS_CXX="mipsel-linux-gnu-g++"
|
||||
CROSS_CFLAGS=""
|
||||
CROSS_CFLAGS=""
|
||||
|
@ -1,3 +1,7 @@
|
||||
CROSS_TARGET="powerpc-unknown-linux-gnu"
|
||||
CROSS_CC="powerpc-linux-gnu-gcc"
|
||||
CROSS_CXX="powerpc-linux-gnu-g++"
|
||||
CROSS_OBJCOPY="powerpc-linux-gnu-objcopy"
|
||||
CROSS_STRIP="powerpc-linux-gnu-strip"
|
||||
CROSS_CFLAGS=""
|
||||
LIBRASAN_CFLAGS="-no-pie -fno-stack-protector"
|
||||
|
@ -1,3 +1,7 @@
|
||||
CROSS_TARGET="x86_64-unknown-linux-gnu"
|
||||
CROSS_CC="x86_64-linux-gnu-gcc"
|
||||
CROSS_CXX="x86_64-linux-gnu-g++"
|
||||
CROSS_CFLAGS=""
|
||||
CROSS_OBJCOPY="x86_64-linux-gnu-objcopy"
|
||||
CROSS_STRIP="x86_64-linux-gnu-strip"
|
||||
CROSS_CFLAGS=""
|
||||
LIBRASAN_CFLAGS="-m64 -no-pie -Wl,--no-relax -mcmodel=large -fno-stack-protector"
|
||||
|
@ -2,13 +2,10 @@ import "libafl-qemu.just"
|
||||
|
||||
# Useful rules to build libpng for multiple architecture.
|
||||
|
||||
ARCH := env("ARCH", "x86_64")
|
||||
OPTIMIZATIONS := env("OPTIMIZATIONS", if ARCH == "ppc" { "no" } else { "yes" })
|
||||
|
||||
DEPS_DIR := TARGET_DIR / "deps"
|
||||
|
||||
DOTENV := source_directory() / "envs" / ".env." + ARCH
|
||||
|
||||
[unix]
|
||||
target_dir:
|
||||
mkdir -p {{ TARGET_DIR }}
|
||||
|
@ -1,3 +1,5 @@
|
||||
import "libafl.just"
|
||||
|
||||
export LIBAFL_QEMU_DIR_DEFAULT := BUILD_DIR / "qemu-libafl-bridge"
|
||||
export LIBAFL_QEMU_DIR_DEFAULT := BUILD_DIR / "qemu-libafl-bridge"
|
||||
ARCH := env("ARCH", "x86_64")
|
||||
DOTENV := source_directory() / "envs" / ".env." + ARCH
|
||||
|
@ -52,6 +52,8 @@ fork = ["libafl/fork"]
|
||||
## Build libqasan for address sanitization
|
||||
build_libgasan = []
|
||||
build_libqasan = []
|
||||
## Use Address Sanitizer implementation written in rust (rather than the older C version)
|
||||
rasan = []
|
||||
|
||||
#! ## The following architecture features are mutually exclusive.
|
||||
|
||||
@ -140,6 +142,7 @@ pyo3-build-config = { workspace = true, optional = true }
|
||||
rustversion = { workspace = true }
|
||||
bindgen = { workspace = true }
|
||||
cc = { workspace = true }
|
||||
just = { workspace = true }
|
||||
|
||||
[lib]
|
||||
name = "libafl_qemu"
|
||||
|
@ -212,7 +212,9 @@ pub fn build() {
|
||||
nyx_bindings_file.as_path(),
|
||||
);
|
||||
|
||||
if cfg!(feature = "usermode") && (qemu_asan || qemu_asan_guest) {
|
||||
let rasan = cfg!(feature = "rasan");
|
||||
|
||||
if cfg!(feature = "usermode") && !rasan && (qemu_asan || qemu_asan_guest) {
|
||||
let qasan_dir = Path::new("libqasan");
|
||||
let qasan_dir = fs::canonicalize(qasan_dir).unwrap();
|
||||
println!("cargo:rerun-if-changed={}", qasan_dir.display());
|
||||
@ -232,4 +234,42 @@ pub fn build() {
|
||||
.success()
|
||||
);
|
||||
}
|
||||
|
||||
if cfg!(feature = "usermode") && rasan {
|
||||
let rasan_dir = Path::new("librasan");
|
||||
let rasan_dir = fs::canonicalize(rasan_dir).unwrap();
|
||||
let just_file = rasan_dir.join("Justfile");
|
||||
println!("cargo:rerun-if-changed={}", rasan_dir.display());
|
||||
println!("cargo:rerun-if-changed={}", just_file.display());
|
||||
|
||||
let rasan_dir_str = rasan_dir.to_str().unwrap();
|
||||
let just_file_str = just_file.to_str().unwrap();
|
||||
let target_dir_str = target_dir.to_str().unwrap();
|
||||
|
||||
let profile = if cfg!(debug_assertions) {
|
||||
"dev"
|
||||
} else {
|
||||
"release"
|
||||
};
|
||||
|
||||
let gasan_args = [
|
||||
"just",
|
||||
"-d", rasan_dir_str,
|
||||
"-f", just_file_str,
|
||||
"--set", "ARCH", &cpu_target,
|
||||
"--set", "PROFILE", profile,
|
||||
"--set", "TARGET_DIR", target_dir_str,
|
||||
"build_gasan"];
|
||||
just::run(gasan_args.iter()).expect("Failed to build rust guest address sanitizer library");
|
||||
|
||||
let qasan_args = [
|
||||
"just",
|
||||
"-d", rasan_dir_str,
|
||||
"-f", just_file_str,
|
||||
"--set", "ARCH", &cpu_target,
|
||||
"--set", "PROFILE", profile,
|
||||
"--set", "TARGET_DIR", target_dir_str,
|
||||
"build_qasan"];
|
||||
just::run(qasan_args.iter()).expect("Failed to build rust address sanitizer library");
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
#[cfg(feature = "python")]
|
||||
use core::convert::Infallible;
|
||||
#[cfg(target_os = "linux")]
|
||||
use core::fmt::{self, Display, Formatter};
|
||||
#[cfg(target_os = "linux")]
|
||||
use core::{slice::from_raw_parts, str::from_utf8_unchecked};
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
@ -34,6 +36,46 @@ pub struct MapInfo {
|
||||
is_priv: i32,
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
impl Display for MapInfo {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "{:016x}-{:016x} , ", self.start, self.end)?;
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
if self.flags & i32::from(MmapPerms::Read) == i32::from(MmapPerms::Read) {
|
||||
"r"
|
||||
} else {
|
||||
"-"
|
||||
}
|
||||
)?;
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
if self.flags & i32::from(MmapPerms::Write) == i32::from(MmapPerms::Write) {
|
||||
"w"
|
||||
} else {
|
||||
"-"
|
||||
}
|
||||
)?;
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
if self.flags & i32::from(MmapPerms::Execute) == i32::from(MmapPerms::Execute) {
|
||||
"x"
|
||||
} else {
|
||||
"-"
|
||||
}
|
||||
)?;
|
||||
write!(f, "{}", if self.is_priv == 0 { "s" } else { "p" })?;
|
||||
write!(f, " {:10}", self.offset)?;
|
||||
if let Some(path) = &self.path {
|
||||
write!(f, " {path}")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg_attr(feature = "python", pymethods)]
|
||||
impl MapInfo {
|
||||
|
15
libafl_qemu/librasan/.cargo/config.toml
Normal file
15
libafl_qemu/librasan/.cargo/config.toml
Normal file
@ -0,0 +1,15 @@
|
||||
[target.i686-unknown-linux-gnu]
|
||||
linker = "i686-linux-gnu-gcc"
|
||||
|
||||
[target.armv7-unknown-linux-gnueabi]
|
||||
linker = "arm-linux-gnueabi-gcc"
|
||||
runner = "qemu-arm -L /usr/arm-linux-gnueabi/"
|
||||
|
||||
|
||||
[target.aarch64-unknown-linux-gnu]
|
||||
linker = "aarch64-linux-gnu-gcc"
|
||||
runner = "qemu-aarch64 -L /usr/aarch64-linux-gnu/"
|
||||
|
||||
[target.powerpc-unknown-linux-gnu]
|
||||
linker = "powerpc-linux-gnu-gcc"
|
||||
runner = "qemu-ppc -L /usr/powerpc-linux-gnu/"
|
2
libafl_qemu/librasan/.gitignore
vendored
Normal file
2
libafl_qemu/librasan/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/target/
|
||||
core
|
19
libafl_qemu/librasan/Cargo.toml
Normal file
19
libafl_qemu/librasan/Cargo.toml
Normal file
@ -0,0 +1,19 @@
|
||||
[workspace]
|
||||
members = ["asan", "gasan", "qasan", "zasan", "fuzz", "dummy_libc", "runner"]
|
||||
resolver = "2"
|
||||
|
||||
[workspace.package]
|
||||
version = "0.15.1"
|
||||
license = "MIT OR Apache-2.0"
|
||||
edition = "2024"
|
||||
rust-version = "1.85"
|
||||
|
||||
[profile.dev]
|
||||
panic = "abort"
|
||||
|
||||
[profile.release]
|
||||
panic = "abort"
|
||||
lto = true
|
||||
codegen-units = 1
|
||||
opt-level = 3
|
||||
debug = true
|
140
libafl_qemu/librasan/Justfile
Normal file
140
libafl_qemu/librasan/Justfile
Normal file
@ -0,0 +1,140 @@
|
||||
import "../../just/libafl-qemu.just"
|
||||
import "asan/Justfile"
|
||||
import "dummy_libc/Justfile"
|
||||
import "fuzz/Justfile"
|
||||
import "gasan/Justfile"
|
||||
import "qasan/Justfile"
|
||||
import "runner/Justfile"
|
||||
import "zasan/Justfile"
|
||||
import "fuzzer_name.just"
|
||||
|
||||
build: build_asan build_dummy build_fuzz build_gasan build_qasan build_runner build_zasan
|
||||
|
||||
test: test_asan
|
||||
|
||||
pretty_rust:
|
||||
#!/bin/bash
|
||||
MAIN_LLVM_VERSION=$LLVM_VERSION cargo run --manifest-path ../../utils/libafl_fmt/Cargo.toml --release -- -v
|
||||
|
||||
pretty_toml:
|
||||
#!/bin/bash
|
||||
taplo fmt
|
||||
|
||||
pretty: pretty_rust pretty_toml
|
||||
|
||||
fix: fix_asan fix_dummy fix_fuzz fix_gasan fix_qasan fix_runner fix_zasan
|
||||
|
||||
clippy:
|
||||
#!/bin/bash
|
||||
cargo clippy
|
||||
|
||||
doc:
|
||||
#!/bin/bash
|
||||
cargo doc
|
||||
|
||||
all: fix pretty build test clippy doc
|
||||
|
||||
build_arm_dev:
|
||||
#!/bin/bash
|
||||
ARCH=arm PROFILE=dev just build
|
||||
|
||||
build_aarch64_dev:
|
||||
#!/bin/bash
|
||||
ARCH=aarch64 PROFILE=dev just build
|
||||
|
||||
build_x86_64_dev:
|
||||
#!/bin/bash
|
||||
ARCH=x86_64 PROFILE=dev just build
|
||||
|
||||
build_i386_dev:
|
||||
#!/bin/bash
|
||||
ARCH=i386 PROFILE=dev just build
|
||||
|
||||
build_ppc_dev:
|
||||
#!/bin/bash
|
||||
ARCH=ppc PROFILE=dev just build
|
||||
|
||||
build_arm_release:
|
||||
#!/bin/bash
|
||||
ARCH=arm PROFILE=release just build
|
||||
|
||||
build_aarch64_release:
|
||||
#!/bin/bash
|
||||
ARCH=aarch64 PROFILE=release just build
|
||||
|
||||
build_x86_64_release:
|
||||
#!/bin/bash
|
||||
ARCH=x86_64 PROFILE=release just build
|
||||
|
||||
build_i386_release:
|
||||
#!/bin/bash
|
||||
ARCH=i386 PROFILE=release just build
|
||||
|
||||
build_ppc_release:
|
||||
#!/bin/bash
|
||||
ARCH=ppc PROFILE=release just build
|
||||
|
||||
build_everything_dev: \
|
||||
build_arm_dev \
|
||||
build_aarch64_dev \
|
||||
build_x86_64_dev \
|
||||
build_i386_dev \
|
||||
build_ppc_dev \
|
||||
|
||||
build_everything_release: \
|
||||
build_arm_dev \
|
||||
build_aarch64_dev \
|
||||
build_x86_64_dev \
|
||||
build_i386_dev \
|
||||
build_ppc_dev \
|
||||
|
||||
build_everything: build_everything_dev build_everything_release
|
||||
|
||||
test_arm:
|
||||
#!/bin/bash
|
||||
ARCH=arm \
|
||||
PROFILE=dev \
|
||||
RUSTLOG=debug \
|
||||
RUST_BACKTRACE=full \
|
||||
just test
|
||||
|
||||
test_aarch64:
|
||||
#!/bin/bash
|
||||
ARCH=aarch64 \
|
||||
PROFILE=dev \
|
||||
RUSTLOG=debug \
|
||||
RUST_BACKTRACE=full \
|
||||
just test
|
||||
|
||||
test_x86_64:
|
||||
#!/bin/bash
|
||||
ARCH=x86_64 \
|
||||
PROFILE=dev \
|
||||
RUSTLOG=debug \
|
||||
RUST_BACKTRACE=full \
|
||||
just test
|
||||
|
||||
test_i386:
|
||||
#!/bin/bash
|
||||
ARCH=i386 \
|
||||
PROFILE=dev \
|
||||
RUSTLOG=debug \
|
||||
RUST_BACKTRACE=full \
|
||||
just test
|
||||
|
||||
test_ppc:
|
||||
#!/bin/bash
|
||||
ARCH=ppc \
|
||||
PROFILE=dev \
|
||||
RUSTLOG=debug \
|
||||
RUST_BACKTRACE=full \
|
||||
just test
|
||||
|
||||
test_everything: \
|
||||
test_arm \
|
||||
test_aarch64 \
|
||||
test_x86_64 \
|
||||
test_i386 \
|
||||
test_ppc
|
||||
|
||||
everything: build_everything test_everything clippy
|
38
libafl_qemu/librasan/README.md
Normal file
38
libafl_qemu/librasan/README.md
Normal file
@ -0,0 +1,38 @@
|
||||
# rasan
|
||||
`rasan` is a library intended to be used by a guest running in QEMU to
|
||||
support address sanitizer.
|
||||
|
||||
It has a modular design intended to support different use cases and
|
||||
environments. The following initial variants are implemented:
|
||||
|
||||
- `qasan` - Intended as a drop in replacement for the original libqasan,
|
||||
this will interact with QEMU using the bespoke syscall interface to perform
|
||||
memory tracking and shadow mapping.
|
||||
- `gasan` - This is similar to `qasan`, but rather than having QEMU perform
|
||||
the management of the shadow memory and memory tracking, this work will be
|
||||
carried out purely in the guest (and hence should be more performant).
|
||||
- `zasan` - This variant is intended to have no dependencies on libc, nor
|
||||
any other libraries. It is intended to be used as a starting point for
|
||||
bare-metal targets or targets which have statically linked `libc`.
|
||||
|
||||
The componentized nature of the design is intended to permit the user to
|
||||
adapt `rasan` to their needs with minimal modification by selecting and
|
||||
combining alternative implementations of the various key components.
|
||||
|
||||
## Features
|
||||
- `dlmalloc` - Enable support for the dlmalloc allocator backend.
|
||||
- `guest` - Enable support for shadow memory and tracking in the guest
|
||||
- `host` - Enable support for shadow memory and tracking in the host
|
||||
- `libc` - Enable use of `LibcMmap` to support creation of mappings using
|
||||
`libc`
|
||||
- `linux` - Enable use of `LinuxMmap` to support creation of mappings and
|
||||
host interaction using `rustix`.
|
||||
- `std` - Disable the magic used to support `no_std` environments
|
||||
|
||||
## Testing
|
||||
This project makes use of a number of unit and integration tests to validate the
|
||||
implementation.
|
||||
|
||||
## Fuzzing
|
||||
The project also includes a couple of fuzzing harnesses supported by
|
||||
`cargo-fuzz` in order to supplement unit and integration tests.
|
64
libafl_qemu/librasan/asan/Cargo.toml
Normal file
64
libafl_qemu/librasan/asan/Cargo.toml
Normal file
@ -0,0 +1,64 @@
|
||||
[package]
|
||||
name = "asan"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
|
||||
[lib]
|
||||
crate-type = ["rlib"]
|
||||
|
||||
[features]
|
||||
default = [
|
||||
"dlmalloc",
|
||||
"guest",
|
||||
"hooks",
|
||||
"host",
|
||||
"libc",
|
||||
"linux",
|
||||
"mimalloc",
|
||||
"test",
|
||||
"tracking",
|
||||
]
|
||||
dlmalloc = ["dep:dlmalloc"]
|
||||
guest = []
|
||||
hooks = []
|
||||
host = ["dep:syscalls"]
|
||||
libc = ["dep:libc"]
|
||||
linux = ["dep:rustix"]
|
||||
mimalloc = ["dep:baby-mimalloc"]
|
||||
test = []
|
||||
tracking = []
|
||||
|
||||
[dependencies]
|
||||
baby-mimalloc = { version = "0.2.1", default-features = false, features = [
|
||||
"spin_mutex",
|
||||
], optional = true }
|
||||
bitflags = { version = "2.8.0", default-features = false }
|
||||
dlmalloc = { version = "0.2.7", default-features = false, optional = true }
|
||||
itertools = { version = "0.14.0", default-features = false }
|
||||
log = { version = "0.4.22", default-features = false, features = [
|
||||
"release_max_level_info",
|
||||
] }
|
||||
libc = { version = "0.2.169", default-features = false, optional = true }
|
||||
readonly = { version = "0.2.12", default-features = false }
|
||||
rustix = { version = "1.0.0", default-features = false, features = [
|
||||
"fs",
|
||||
"mm",
|
||||
"process",
|
||||
"stdio",
|
||||
], optional = true }
|
||||
spin = { version = "0.9.8", default-features = false, features = [
|
||||
"lazy",
|
||||
"mutex",
|
||||
"spin_mutex",
|
||||
] }
|
||||
syscalls = { version = "0.6.18", default-features = false, optional = true }
|
||||
thiserror = { version = "2.0.11", default-features = false }
|
||||
|
||||
[build-dependencies]
|
||||
cc = { version = "1.2.13" }
|
||||
|
||||
[dev-dependencies]
|
||||
env_logger = { version = "0.11.6" }
|
||||
mockall = { version = "0.13.1" }
|
||||
widestring = { version = "1.1.0" }
|
43
libafl_qemu/librasan/asan/Justfile
Normal file
43
libafl_qemu/librasan/asan/Justfile
Normal file
@ -0,0 +1,43 @@
|
||||
import "../../../just/libafl-qemu.just"
|
||||
import "../fuzzer_name.just"
|
||||
|
||||
ASAN_SOURCE_DIR := source_directory()
|
||||
|
||||
[unix]
|
||||
compile_asan:
|
||||
#!/bin/bash
|
||||
source {{ DOTENV }}
|
||||
cargo \
|
||||
+nightly \
|
||||
build \
|
||||
--package asan \
|
||||
--target ${CROSS_TARGET} \
|
||||
--profile {{ PROFILE }} \
|
||||
--target-dir {{ TARGET_DIR }}
|
||||
|
||||
[unix]
|
||||
fix_asan:
|
||||
#!/bin/bash
|
||||
source {{ DOTENV }}
|
||||
cargo \
|
||||
+nightly \
|
||||
fix \
|
||||
--package asan \
|
||||
--target ${CROSS_TARGET} \
|
||||
--profile {{ PROFILE }} \
|
||||
--target-dir {{ TARGET_DIR }} \
|
||||
--allow-dirty
|
||||
|
||||
[unix]
|
||||
test_asan:
|
||||
#!/bin/bash
|
||||
source {{ DOTENV }}
|
||||
cd {{ ASAN_SOURCE_DIR }}
|
||||
cargo \
|
||||
+nightly \
|
||||
nextest \
|
||||
run \
|
||||
--target ${CROSS_TARGET}
|
||||
|
||||
[unix]
|
||||
build_asan: compile_asan
|
45
libafl_qemu/librasan/asan/build.rs
Normal file
45
libafl_qemu/librasan/asan/build.rs
Normal file
@ -0,0 +1,45 @@
|
||||
fn main() {
|
||||
println!("cargo:rerun-if-changed=cc/include/hooks.h");
|
||||
println!("cargo:rerun-if-changed=cc/include/trace.h");
|
||||
println!("cargo:rerun-if-changed=cc/include/printf.h");
|
||||
println!("cargo:rerun-if-changed=cc/src/asprintf.c");
|
||||
println!("cargo:rerun-if-changed=cc/src/log.c");
|
||||
println!("cargo:rerun-if-changed=cc/src/printf.c");
|
||||
println!("cargo:rerun-if-changed=cc/src/vasprintf.c");
|
||||
|
||||
cc::Build::new()
|
||||
.define("_GNU_SOURCE", None)
|
||||
.flag("-Werror")
|
||||
.flag("-fno-stack-protector")
|
||||
.flag("-ffunction-sections")
|
||||
.include("cc/include/")
|
||||
.file("cc/src/asprintf.c")
|
||||
.compile("asprintf");
|
||||
|
||||
cc::Build::new()
|
||||
.define("_GNU_SOURCE", None)
|
||||
.flag("-Werror")
|
||||
.flag("-fno-stack-protector")
|
||||
.flag("-ffunction-sections")
|
||||
.include("cc/include/")
|
||||
.file("cc/src/log.c")
|
||||
.compile("log");
|
||||
|
||||
cc::Build::new()
|
||||
.define("_GNU_SOURCE", None)
|
||||
.flag("-Werror")
|
||||
.flag("-fno-stack-protector")
|
||||
.flag("-ffunction-sections")
|
||||
.include("cc/include/")
|
||||
.file("cc/src/printf.c")
|
||||
.compile("printf");
|
||||
|
||||
cc::Build::new()
|
||||
.define("_GNU_SOURCE", None)
|
||||
.flag("-Werror")
|
||||
.flag("-fno-stack-protector")
|
||||
.flag("-ffunction-sections")
|
||||
.include("cc/include/")
|
||||
.file("cc/src/vasprintf.c")
|
||||
.compile("vasprintf");
|
||||
}
|
9
libafl_qemu/librasan/asan/cc/include/hooks.h
Normal file
9
libafl_qemu/librasan/asan/cc/include/hooks.h
Normal file
@ -0,0 +1,9 @@
|
||||
#include <stddef.h>
|
||||
|
||||
void asan_load(const void *addr, size_t size);
|
||||
void asan_store(const void *addr, size_t size);
|
||||
void *asan_alloc(size_t len, size_t align);
|
||||
void asan_dealloc(const void *addr);
|
||||
size_t asan_get_size(const void *addr);
|
||||
size_t asan_sym(const char *name);
|
||||
size_t asan_page_size();
|
116
libafl_qemu/librasan/asan/cc/include/printf.h
Normal file
116
libafl_qemu/librasan/asan/cc/include/printf.h
Normal file
@ -0,0 +1,116 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// \author (c) Marco Paland (info@paland.com)
|
||||
// 2014-2019, PALANDesign Hannover, Germany
|
||||
//
|
||||
// \license The MIT License (MIT)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// \brief Tiny printf, sprintf and snprintf implementation, optimized for speed
|
||||
// on
|
||||
// embedded systems with a very limited resources.
|
||||
// Use this instead of bloated standard/newlib printf.
|
||||
// These routines are thread safe and reentrant.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _PRINTF_H_
|
||||
#define _PRINTF_H_
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Output a character to a custom device like UART, used by the printf()
|
||||
* function This function is declared here only. You have to write your custom
|
||||
* implementation somewhere \param character Character to output
|
||||
*/
|
||||
void _putchar(char character);
|
||||
|
||||
/**
|
||||
* Tiny printf implementation
|
||||
* You have to implement _putchar if you use printf()
|
||||
* To avoid conflicts with the regular printf() API it is overridden by macro
|
||||
* defines and internal underscore-appended functions like printf_() are used
|
||||
* \param format A string that specifies the format of the output
|
||||
* \return The number of characters that are written into the array, not
|
||||
* counting the terminating null character
|
||||
*/
|
||||
#define printf printf_
|
||||
int printf_(const char *format, ...);
|
||||
|
||||
/**
|
||||
* Tiny sprintf implementation
|
||||
* Due to security reasons (buffer overflow) YOU SHOULD CONSIDER USING
|
||||
* (V)SNPRINTF INSTEAD! \param buffer A pointer to the buffer where to store the
|
||||
* formatted string. MUST be big enough to store the output! \param format A
|
||||
* string that specifies the format of the output \return The number of
|
||||
* characters that are WRITTEN into the buffer, not counting the terminating
|
||||
* null character
|
||||
*/
|
||||
#define sprintf sprintf_
|
||||
int sprintf_(char *buffer, const char *format, ...);
|
||||
|
||||
/**
|
||||
* Tiny snprintf/vsnprintf implementation
|
||||
* \param buffer A pointer to the buffer where to store the formatted string
|
||||
* \param count The maximum number of characters to store in the buffer,
|
||||
* including a terminating null character \param format A string that specifies
|
||||
* the format of the output \param va A value identifying a variable arguments
|
||||
* list \return The number of characters that COULD have been written into the
|
||||
* buffer, not counting the terminating null character. A value equal or larger
|
||||
* than count indicates truncation. Only when the returned value is non-negative
|
||||
* and less than count, the string has been completely written.
|
||||
*/
|
||||
#define snprintf snprintf_
|
||||
#define vsnprintf vsnprintf_
|
||||
int snprintf_(char *buffer, size_t count, const char *format, ...);
|
||||
int vsnprintf_(char *buffer, size_t count, const char *format, va_list va);
|
||||
|
||||
/**
|
||||
* Tiny vprintf implementation
|
||||
* \param format A string that specifies the format of the output
|
||||
* \param va A value identifying a variable arguments list
|
||||
* \return The number of characters that are WRITTEN into the buffer, not
|
||||
* counting the terminating null character
|
||||
*/
|
||||
#define vprintf vprintf_
|
||||
int vprintf_(const char *format, va_list va);
|
||||
|
||||
/**
|
||||
* printf with output function
|
||||
* You may use this as dynamic alternative to printf() with its fixed _putchar()
|
||||
* output \param out An output function which takes one character and an
|
||||
* argument pointer \param arg An argument pointer for user data passed to
|
||||
* output function \param format A string that specifies the format of the
|
||||
* output \return The number of characters that are sent to the output function,
|
||||
* not counting the terminating null character
|
||||
*/
|
||||
int fctprintf(void (*out)(char character, void *arg), void *arg,
|
||||
const char *format, ...);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _PRINTF_H_
|
6
libafl_qemu/librasan/asan/cc/include/trace.h
Normal file
6
libafl_qemu/librasan/asan/cc/include/trace.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef _LOG_H_
|
||||
#define _LOG_H_
|
||||
|
||||
void trace(const char *fmt, ...);
|
||||
|
||||
#endif
|
26
libafl_qemu/librasan/asan/cc/src/asprintf.c
Normal file
26
libafl_qemu/librasan/asan/cc/src/asprintf.c
Normal file
@ -0,0 +1,26 @@
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include "hooks.h"
|
||||
#include "printf.h"
|
||||
#include "trace.h"
|
||||
|
||||
int asprintf(char **restrict strp, const char *restrict fmt, ...) {
|
||||
trace("asprintf - strp: %p, fmt: %p\n", strp, fmt);
|
||||
if (strp == NULL) { return -1; }
|
||||
|
||||
if (fmt == NULL) { return -1; }
|
||||
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
int len = vsnprintf_(NULL, 0, fmt, va);
|
||||
va_end(va);
|
||||
|
||||
if (len < 0) { return -1; }
|
||||
|
||||
void *buffer = asan_alloc(len + 1, 0);
|
||||
if (buffer == NULL) { return -1; }
|
||||
|
||||
*strp = buffer;
|
||||
return vsnprintf_(buffer, len, fmt, va);
|
||||
}
|
21
libafl_qemu/librasan/asan/cc/src/log.c
Normal file
21
libafl_qemu/librasan/asan/cc/src/log.c
Normal file
@ -0,0 +1,21 @@
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
#include "printf.h"
|
||||
|
||||
static char log_buffer[PATH_MAX] = {0};
|
||||
|
||||
extern void log_trace(char *msg);
|
||||
|
||||
void trace(const char *fmt, ...) {
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
int len = vsnprintf_(log_buffer, sizeof(log_buffer), fmt, va);
|
||||
if (len > 0) { log_trace(log_buffer); }
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
#ifdef __powerpc__
|
||||
void _putchar(char c) {
|
||||
(void)c;
|
||||
}
|
||||
#endif
|
924
libafl_qemu/librasan/asan/cc/src/printf.c
Normal file
924
libafl_qemu/librasan/asan/cc/src/printf.c
Normal file
@ -0,0 +1,924 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// \author (c) Marco Paland (info@paland.com)
|
||||
// 2014-2019, PALANDesign Hannover, Germany
|
||||
//
|
||||
// \license The MIT License (MIT)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// \brief Tiny printf, sprintf and (v)snprintf implementation, optimized for
|
||||
// speed on
|
||||
// embedded systems with a very limited resources. These routines are
|
||||
// thread safe and reentrant! Use this instead of the bloated
|
||||
// standard/newlib printf cause these use malloc for printf (and may not
|
||||
// be thread safe).
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "printf.h"
|
||||
|
||||
// define this globally (e.g. gcc -DPRINTF_INCLUDE_CONFIG_H ...) to include the
|
||||
// printf_config.h header file
|
||||
// default: undefined
|
||||
#ifdef PRINTF_INCLUDE_CONFIG_H
|
||||
#include "printf_config.h"
|
||||
#endif
|
||||
|
||||
// 'ntoa' conversion buffer size, this must be big enough to hold one converted
|
||||
// numeric number including padded zeros (dynamically created on stack)
|
||||
// default: 32 byte
|
||||
#ifndef PRINTF_NTOA_BUFFER_SIZE
|
||||
#define PRINTF_NTOA_BUFFER_SIZE 32U
|
||||
#endif
|
||||
|
||||
// 'ftoa' conversion buffer size, this must be big enough to hold one converted
|
||||
// float number including padded zeros (dynamically created on stack)
|
||||
// default: 32 byte
|
||||
#ifndef PRINTF_FTOA_BUFFER_SIZE
|
||||
#define PRINTF_FTOA_BUFFER_SIZE 32U
|
||||
#endif
|
||||
|
||||
// support for the floating point type (%f)
|
||||
// default: activated
|
||||
#ifndef PRINTF_DISABLE_SUPPORT_FLOAT
|
||||
#define PRINTF_SUPPORT_FLOAT
|
||||
#endif
|
||||
|
||||
// support for exponential floating point notation (%e/%g)
|
||||
// default: activated
|
||||
#ifndef PRINTF_DISABLE_SUPPORT_EXPONENTIAL
|
||||
#define PRINTF_SUPPORT_EXPONENTIAL
|
||||
#endif
|
||||
|
||||
// define the default floating point precision
|
||||
// default: 6 digits
|
||||
#ifndef PRINTF_DEFAULT_FLOAT_PRECISION
|
||||
#define PRINTF_DEFAULT_FLOAT_PRECISION 6U
|
||||
#endif
|
||||
|
||||
// define the largest float suitable to print with %f
|
||||
// default: 1e9
|
||||
#ifndef PRINTF_MAX_FLOAT
|
||||
#define PRINTF_MAX_FLOAT 1e9
|
||||
#endif
|
||||
|
||||
// support for the long long types (%llu or %p)
|
||||
// default: activated
|
||||
#ifndef PRINTF_DISABLE_SUPPORT_LONG_LONG
|
||||
#define PRINTF_SUPPORT_LONG_LONG
|
||||
#endif
|
||||
|
||||
// support for the ptrdiff_t type (%t)
|
||||
// ptrdiff_t is normally defined in <stddef.h> as long or long long type
|
||||
// default: activated
|
||||
#ifndef PRINTF_DISABLE_SUPPORT_PTRDIFF_T
|
||||
#define PRINTF_SUPPORT_PTRDIFF_T
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// internal flag definitions
|
||||
#define FLAGS_ZEROPAD (1U << 0U)
|
||||
#define FLAGS_LEFT (1U << 1U)
|
||||
#define FLAGS_PLUS (1U << 2U)
|
||||
#define FLAGS_SPACE (1U << 3U)
|
||||
#define FLAGS_HASH (1U << 4U)
|
||||
#define FLAGS_UPPERCASE (1U << 5U)
|
||||
#define FLAGS_CHAR (1U << 6U)
|
||||
#define FLAGS_SHORT (1U << 7U)
|
||||
#define FLAGS_LONG (1U << 8U)
|
||||
#define FLAGS_LONG_LONG (1U << 9U)
|
||||
#define FLAGS_PRECISION (1U << 10U)
|
||||
#define FLAGS_ADAPT_EXP (1U << 11U)
|
||||
|
||||
// import float.h for DBL_MAX
|
||||
#if defined(PRINTF_SUPPORT_FLOAT)
|
||||
#include <float.h>
|
||||
#endif
|
||||
|
||||
// output function type
|
||||
typedef void (*out_fct_type)(char character, void *buffer, size_t idx,
|
||||
size_t maxlen);
|
||||
|
||||
// wrapper (used as buffer) for output function type
|
||||
typedef struct {
|
||||
void (*fct)(char character, void *arg);
|
||||
void *arg;
|
||||
} out_fct_wrap_type;
|
||||
|
||||
// internal buffer output
|
||||
static inline void _out_buffer(char character, void *buffer, size_t idx,
|
||||
size_t maxlen) {
|
||||
if (idx < maxlen) { ((char *)buffer)[idx] = character; }
|
||||
}
|
||||
|
||||
// internal null output
|
||||
static inline void _out_null(char character, void *buffer, size_t idx,
|
||||
size_t maxlen) {
|
||||
(void)character;
|
||||
(void)buffer;
|
||||
(void)idx;
|
||||
(void)maxlen;
|
||||
}
|
||||
|
||||
// internal _putchar wrapper
|
||||
static inline void _out_char(char character, void *buffer, size_t idx,
|
||||
size_t maxlen) {
|
||||
(void)buffer;
|
||||
(void)idx;
|
||||
(void)maxlen;
|
||||
if (character) { _putchar(character); }
|
||||
}
|
||||
|
||||
// internal output function wrapper
|
||||
static inline void _out_fct(char character, void *buffer, size_t idx,
|
||||
size_t maxlen) {
|
||||
(void)idx;
|
||||
(void)maxlen;
|
||||
if (character) {
|
||||
// buffer is the output fct pointer
|
||||
((out_fct_wrap_type *)buffer)
|
||||
->fct(character, ((out_fct_wrap_type *)buffer)->arg);
|
||||
}
|
||||
}
|
||||
|
||||
// internal secure strlen
|
||||
// \return The length of the string (excluding the terminating 0) limited by
|
||||
// 'maxsize'
|
||||
static inline unsigned int _strnlen_s(const char *str, size_t maxsize) {
|
||||
const char *s;
|
||||
for (s = str; *s && maxsize--; ++s)
|
||||
;
|
||||
return (unsigned int)(s - str);
|
||||
}
|
||||
|
||||
// internal test if char is a digit (0-9)
|
||||
// \return true if char is a digit
|
||||
static inline bool _is_digit(char ch) {
|
||||
return (ch >= '0') && (ch <= '9');
|
||||
}
|
||||
|
||||
// internal ASCII string to unsigned int conversion
|
||||
static unsigned int _atoi(const char **str) {
|
||||
unsigned int i = 0U;
|
||||
while (_is_digit(**str)) {
|
||||
i = i * 10U + (unsigned int)(*((*str)++) - '0');
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
// output the specified string in reverse, taking care of any zero-padding
|
||||
static size_t _out_rev(out_fct_type out, char *buffer, size_t idx,
|
||||
size_t maxlen, const char *buf, size_t len,
|
||||
unsigned int width, unsigned int flags) {
|
||||
const size_t start_idx = idx;
|
||||
|
||||
// pad spaces up to given width
|
||||
if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) {
|
||||
for (size_t i = len; i < width; i++) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
|
||||
// reverse string
|
||||
while (len) {
|
||||
out(buf[--len], buffer, idx++, maxlen);
|
||||
}
|
||||
|
||||
// append pad spaces up to given width
|
||||
if (flags & FLAGS_LEFT) {
|
||||
while (idx - start_idx < width) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
// internal itoa format
|
||||
static size_t _ntoa_format(out_fct_type out, char *buffer, size_t idx,
|
||||
size_t maxlen, char *buf, size_t len, bool negative,
|
||||
unsigned int base, unsigned int prec,
|
||||
unsigned int width, unsigned int flags) {
|
||||
// pad leading zeros
|
||||
if (!(flags & FLAGS_LEFT)) {
|
||||
if (width && (flags & FLAGS_ZEROPAD) &&
|
||||
(negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
|
||||
width--;
|
||||
}
|
||||
while ((len < prec) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
while ((flags & FLAGS_ZEROPAD) && (len < width) &&
|
||||
(len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
}
|
||||
|
||||
// handle hash
|
||||
if (flags & FLAGS_HASH) {
|
||||
if (!(flags & FLAGS_PRECISION) && len &&
|
||||
((len == prec) || (len == width))) {
|
||||
len--;
|
||||
if (len && (base == 16U)) { len--; }
|
||||
}
|
||||
if ((base == 16U) && !(flags & FLAGS_UPPERCASE) &&
|
||||
(len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = 'x';
|
||||
} else if ((base == 16U) && (flags & FLAGS_UPPERCASE) &&
|
||||
(len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = 'X';
|
||||
} else if ((base == 2U) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = 'b';
|
||||
}
|
||||
if (len < PRINTF_NTOA_BUFFER_SIZE) { buf[len++] = '0'; }
|
||||
}
|
||||
|
||||
if (len < PRINTF_NTOA_BUFFER_SIZE) {
|
||||
if (negative) {
|
||||
buf[len++] = '-';
|
||||
} else if (flags & FLAGS_PLUS) {
|
||||
buf[len++] = '+'; // ignore the space if the '+' exists
|
||||
} else if (flags & FLAGS_SPACE) {
|
||||
buf[len++] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags);
|
||||
}
|
||||
|
||||
// internal itoa for 'long' type
|
||||
static size_t _ntoa_long(out_fct_type out, char *buffer, size_t idx,
|
||||
size_t maxlen, unsigned long value, bool negative,
|
||||
unsigned long base, unsigned int prec,
|
||||
unsigned int width, unsigned int flags) {
|
||||
char buf[PRINTF_NTOA_BUFFER_SIZE];
|
||||
size_t len = 0U;
|
||||
|
||||
// no hash for 0 values
|
||||
if (!value) { flags &= ~FLAGS_HASH; }
|
||||
|
||||
// write if precision != 0 and value is != 0
|
||||
if (!(flags & FLAGS_PRECISION) || value) {
|
||||
do {
|
||||
const char digit = (char)(value % base);
|
||||
buf[len++] = digit < 10
|
||||
? '0' + digit
|
||||
: (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10;
|
||||
value /= base;
|
||||
} while (value && (len < PRINTF_NTOA_BUFFER_SIZE));
|
||||
}
|
||||
|
||||
return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative,
|
||||
(unsigned int)base, prec, width, flags);
|
||||
}
|
||||
|
||||
// internal itoa for 'long long' type
|
||||
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||
static size_t _ntoa_long_long(out_fct_type out, char *buffer, size_t idx,
|
||||
size_t maxlen, unsigned long long value,
|
||||
bool negative, unsigned long long base,
|
||||
unsigned int prec, unsigned int width,
|
||||
unsigned int flags) {
|
||||
char buf[PRINTF_NTOA_BUFFER_SIZE];
|
||||
size_t len = 0U;
|
||||
|
||||
// no hash for 0 values
|
||||
if (!value) { flags &= ~FLAGS_HASH; }
|
||||
|
||||
// write if precision != 0 and value is != 0
|
||||
if (!(flags & FLAGS_PRECISION) || value) {
|
||||
do {
|
||||
const char digit = (char)(value % base);
|
||||
buf[len++] = digit < 10
|
||||
? '0' + digit
|
||||
: (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10;
|
||||
value /= base;
|
||||
} while (value && (len < PRINTF_NTOA_BUFFER_SIZE));
|
||||
}
|
||||
|
||||
return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative,
|
||||
(unsigned int)base, prec, width, flags);
|
||||
}
|
||||
#endif // PRINTF_SUPPORT_LONG_LONG
|
||||
|
||||
#if defined(PRINTF_SUPPORT_FLOAT)
|
||||
|
||||
#if defined(PRINTF_SUPPORT_EXPONENTIAL)
|
||||
// forward declaration so that _ftoa can switch to exp notation for values >
|
||||
// PRINTF_MAX_FLOAT
|
||||
static size_t _etoa(out_fct_type out, char *buffer, size_t idx, size_t maxlen,
|
||||
double value, unsigned int prec, unsigned int width,
|
||||
unsigned int flags);
|
||||
#endif
|
||||
|
||||
// internal ftoa for fixed decimal floating point
|
||||
static size_t _ftoa(out_fct_type out, char *buffer, size_t idx, size_t maxlen,
|
||||
double value, unsigned int prec, unsigned int width,
|
||||
unsigned int flags) {
|
||||
char buf[PRINTF_FTOA_BUFFER_SIZE];
|
||||
size_t len = 0U;
|
||||
double diff = 0.0;
|
||||
|
||||
// powers of 10
|
||||
static const double pow10[] = {1, 10, 100, 1000,
|
||||
10000, 100000, 1000000, 10000000,
|
||||
100000000, 1000000000};
|
||||
|
||||
// test for special values
|
||||
if (value != value)
|
||||
return _out_rev(out, buffer, idx, maxlen, "nan", 3, width, flags);
|
||||
if (value < -DBL_MAX)
|
||||
return _out_rev(out, buffer, idx, maxlen, "fni-", 4, width, flags);
|
||||
if (value > DBL_MAX)
|
||||
return _out_rev(out, buffer, idx, maxlen,
|
||||
(flags & FLAGS_PLUS) ? "fni+" : "fni",
|
||||
(flags & FLAGS_PLUS) ? 4U : 3U, width, flags);
|
||||
|
||||
// test for very large values
|
||||
// standard printf behavior is to print EVERY whole number digit -- which
|
||||
// could be 100s of characters overflowing your buffers == bad
|
||||
if ((value > PRINTF_MAX_FLOAT) || (value < -PRINTF_MAX_FLOAT)) {
|
||||
#if defined(PRINTF_SUPPORT_EXPONENTIAL)
|
||||
return _etoa(out, buffer, idx, maxlen, value, prec, width, flags);
|
||||
#else
|
||||
return 0U;
|
||||
#endif
|
||||
}
|
||||
|
||||
// test for negative
|
||||
bool negative = false;
|
||||
if (value < 0) {
|
||||
negative = true;
|
||||
value = 0 - value;
|
||||
}
|
||||
|
||||
// set default precision, if not set explicitly
|
||||
if (!(flags & FLAGS_PRECISION)) { prec = PRINTF_DEFAULT_FLOAT_PRECISION; }
|
||||
// limit precision to 9, cause a prec >= 10 can lead to overflow errors
|
||||
while ((len < PRINTF_FTOA_BUFFER_SIZE) && (prec > 9U)) {
|
||||
buf[len++] = '0';
|
||||
prec--;
|
||||
}
|
||||
|
||||
int whole = (int)value;
|
||||
double tmp = (value - whole) * pow10[prec];
|
||||
unsigned long frac = (unsigned long)tmp;
|
||||
diff = tmp - frac;
|
||||
|
||||
if (diff > 0.5) {
|
||||
++frac;
|
||||
// handle rollover, e.g. case 0.99 with prec 1 is 1.0
|
||||
if (frac >= pow10[prec]) {
|
||||
frac = 0;
|
||||
++whole;
|
||||
}
|
||||
} else if (diff < 0.5) {
|
||||
} else if ((frac == 0U) || (frac & 1U)) {
|
||||
// if halfway, round up if odd OR if last digit is 0
|
||||
++frac;
|
||||
}
|
||||
|
||||
if (prec == 0U) {
|
||||
diff = value - (double)whole;
|
||||
if ((!(diff < 0.5) || (diff > 0.5)) && (whole & 1)) {
|
||||
// exactly 0.5 and ODD, then round up
|
||||
// 1.5 -> 2, but 2.5 -> 2
|
||||
++whole;
|
||||
}
|
||||
} else {
|
||||
unsigned int count = prec;
|
||||
// now do fractional part, as an unsigned number
|
||||
while (len < PRINTF_FTOA_BUFFER_SIZE) {
|
||||
--count;
|
||||
buf[len++] = (char)(48U + (frac % 10U));
|
||||
if (!(frac /= 10U)) { break; }
|
||||
}
|
||||
// add extra 0s
|
||||
while ((len < PRINTF_FTOA_BUFFER_SIZE) && (count-- > 0U)) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
if (len < PRINTF_FTOA_BUFFER_SIZE) {
|
||||
// add decimal
|
||||
buf[len++] = '.';
|
||||
}
|
||||
}
|
||||
|
||||
// do whole part, number is reversed
|
||||
while (len < PRINTF_FTOA_BUFFER_SIZE) {
|
||||
buf[len++] = (char)(48 + (whole % 10));
|
||||
if (!(whole /= 10)) { break; }
|
||||
}
|
||||
|
||||
// pad leading zeros
|
||||
if (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD)) {
|
||||
if (width && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
|
||||
width--;
|
||||
}
|
||||
while ((len < width) && (len < PRINTF_FTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
}
|
||||
|
||||
if (len < PRINTF_FTOA_BUFFER_SIZE) {
|
||||
if (negative) {
|
||||
buf[len++] = '-';
|
||||
} else if (flags & FLAGS_PLUS) {
|
||||
buf[len++] = '+'; // ignore the space if the '+' exists
|
||||
} else if (flags & FLAGS_SPACE) {
|
||||
buf[len++] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags);
|
||||
}
|
||||
|
||||
#if defined(PRINTF_SUPPORT_EXPONENTIAL)
|
||||
// internal ftoa variant for exponential floating-point type, contributed by
|
||||
// Martijn Jasperse <m.jasperse@gmail.com>
|
||||
static size_t _etoa(out_fct_type out, char *buffer, size_t idx, size_t maxlen,
|
||||
double value, unsigned int prec, unsigned int width,
|
||||
unsigned int flags) {
|
||||
// check for NaN and special values
|
||||
if ((value != value) || (value > DBL_MAX) || (value < -DBL_MAX)) {
|
||||
return _ftoa(out, buffer, idx, maxlen, value, prec, width, flags);
|
||||
}
|
||||
|
||||
// determine the sign
|
||||
const bool negative = value < 0;
|
||||
if (negative) { value = -value; }
|
||||
|
||||
// default precision
|
||||
if (!(flags & FLAGS_PRECISION)) { prec = PRINTF_DEFAULT_FLOAT_PRECISION; }
|
||||
|
||||
// determine the decimal exponent
|
||||
// based on the algorithm by David Gay (https://www.ampl.com/netlib/fp/dtoa.c)
|
||||
union {
|
||||
uint64_t U;
|
||||
double F;
|
||||
} conv;
|
||||
|
||||
conv.F = value;
|
||||
int exp2 = (int)((conv.U >> 52U) & 0x07FFU) - 1023; // effectively log2
|
||||
conv.U = (conv.U & ((1ULL << 52U) - 1U)) |
|
||||
(1023ULL << 52U); // drop the exponent so conv.F is now in [1,2)
|
||||
// now approximate log10 from the log2 integer part and an expansion of ln
|
||||
// around 1.5
|
||||
int expval = (int)(0.1760912590558 + exp2 * 0.301029995663981 +
|
||||
(conv.F - 1.5) * 0.289529654602168);
|
||||
// now we want to compute 10^expval but we want to be sure it won't overflow
|
||||
exp2 = (int)(expval * 3.321928094887362 + 0.5);
|
||||
const double z = expval * 2.302585092994046 - exp2 * 0.6931471805599453;
|
||||
const double z2 = z * z;
|
||||
conv.U = (uint64_t)(exp2 + 1023) << 52U;
|
||||
// compute exp(z) using continued fractions, see
|
||||
// https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex
|
||||
conv.F *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14)))));
|
||||
// correct for rounding errors
|
||||
if (value < conv.F) {
|
||||
expval--;
|
||||
conv.F /= 10;
|
||||
}
|
||||
|
||||
// the exponent format is "%+03d" and largest value is "307", so set aside 4-5
|
||||
// characters
|
||||
unsigned int minwidth = ((expval < 100) && (expval > -100)) ? 4U : 5U;
|
||||
|
||||
// in "%g" mode, "prec" is the number of *significant figures* not decimals
|
||||
if (flags & FLAGS_ADAPT_EXP) {
|
||||
// do we want to fall-back to "%f" mode?
|
||||
if ((value >= 1e-4) && (value < 1e6)) {
|
||||
if ((int)prec > expval) {
|
||||
prec = (unsigned)((int)prec - expval - 1);
|
||||
} else {
|
||||
prec = 0;
|
||||
}
|
||||
flags |= FLAGS_PRECISION; // make sure _ftoa respects precision
|
||||
// no characters in exponent
|
||||
minwidth = 0U;
|
||||
expval = 0;
|
||||
} else {
|
||||
// we use one sigfig for the whole part
|
||||
if ((prec > 0) && (flags & FLAGS_PRECISION)) { --prec; }
|
||||
}
|
||||
}
|
||||
|
||||
// will everything fit?
|
||||
unsigned int fwidth = width;
|
||||
if (width > minwidth) {
|
||||
// we didn't fall-back so subtract the characters required for the exponent
|
||||
fwidth -= minwidth;
|
||||
} else {
|
||||
// not enough characters, so go back to default sizing
|
||||
fwidth = 0U;
|
||||
}
|
||||
if ((flags & FLAGS_LEFT) && minwidth) {
|
||||
// if we're padding on the right, DON'T pad the floating part
|
||||
fwidth = 0U;
|
||||
}
|
||||
|
||||
// rescale the float value
|
||||
if (expval) { value /= conv.F; }
|
||||
|
||||
// output the floating part
|
||||
const size_t start_idx = idx;
|
||||
idx = _ftoa(out, buffer, idx, maxlen, negative ? -value : value, prec, fwidth,
|
||||
flags & ~FLAGS_ADAPT_EXP);
|
||||
|
||||
// output the exponent part
|
||||
if (minwidth) {
|
||||
// output the exponential symbol
|
||||
out((flags & FLAGS_UPPERCASE) ? 'E' : 'e', buffer, idx++, maxlen);
|
||||
// output the exponent value
|
||||
idx =
|
||||
_ntoa_long(out, buffer, idx, maxlen, (expval < 0) ? -expval : expval,
|
||||
expval < 0, 10, 0, minwidth - 1, FLAGS_ZEROPAD | FLAGS_PLUS);
|
||||
// might need to right-pad spaces
|
||||
if (flags & FLAGS_LEFT) {
|
||||
while (idx - start_idx < width)
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
#endif // PRINTF_SUPPORT_EXPONENTIAL
|
||||
#endif // PRINTF_SUPPORT_FLOAT
|
||||
|
||||
// internal vsnprintf
|
||||
static int _vsnprintf(out_fct_type out, char *buffer, const size_t maxlen,
|
||||
const char *format, va_list va) {
|
||||
unsigned int flags, width, precision, n;
|
||||
size_t idx = 0U;
|
||||
|
||||
if (!buffer) {
|
||||
// use null output function
|
||||
out = _out_null;
|
||||
}
|
||||
|
||||
while (*format) {
|
||||
// format specifier? %[flags][width][.precision][length]
|
||||
if (*format != '%') {
|
||||
// no
|
||||
out(*format, buffer, idx++, maxlen);
|
||||
format++;
|
||||
continue;
|
||||
} else {
|
||||
// yes, evaluate it
|
||||
format++;
|
||||
}
|
||||
|
||||
// evaluate flags
|
||||
flags = 0U;
|
||||
do {
|
||||
switch (*format) {
|
||||
case '0':
|
||||
flags |= FLAGS_ZEROPAD;
|
||||
format++;
|
||||
n = 1U;
|
||||
break;
|
||||
case '-':
|
||||
flags |= FLAGS_LEFT;
|
||||
format++;
|
||||
n = 1U;
|
||||
break;
|
||||
case '+':
|
||||
flags |= FLAGS_PLUS;
|
||||
format++;
|
||||
n = 1U;
|
||||
break;
|
||||
case ' ':
|
||||
flags |= FLAGS_SPACE;
|
||||
format++;
|
||||
n = 1U;
|
||||
break;
|
||||
case '#':
|
||||
flags |= FLAGS_HASH;
|
||||
format++;
|
||||
n = 1U;
|
||||
break;
|
||||
default:
|
||||
n = 0U;
|
||||
break;
|
||||
}
|
||||
} while (n);
|
||||
|
||||
// evaluate width field
|
||||
width = 0U;
|
||||
if (_is_digit(*format)) {
|
||||
width = _atoi(&format);
|
||||
} else if (*format == '*') {
|
||||
const int w = va_arg(va, int);
|
||||
if (w < 0) {
|
||||
flags |= FLAGS_LEFT; // reverse padding
|
||||
width = (unsigned int)-w;
|
||||
} else {
|
||||
width = (unsigned int)w;
|
||||
}
|
||||
format++;
|
||||
}
|
||||
|
||||
// evaluate precision field
|
||||
precision = 0U;
|
||||
if (*format == '.') {
|
||||
flags |= FLAGS_PRECISION;
|
||||
format++;
|
||||
if (_is_digit(*format)) {
|
||||
precision = _atoi(&format);
|
||||
} else if (*format == '*') {
|
||||
const int prec = (int)va_arg(va, int);
|
||||
precision = prec > 0 ? (unsigned int)prec : 0U;
|
||||
format++;
|
||||
}
|
||||
}
|
||||
|
||||
// evaluate length field
|
||||
switch (*format) {
|
||||
case 'l':
|
||||
flags |= FLAGS_LONG;
|
||||
format++;
|
||||
if (*format == 'l') {
|
||||
flags |= FLAGS_LONG_LONG;
|
||||
format++;
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
flags |= FLAGS_SHORT;
|
||||
format++;
|
||||
if (*format == 'h') {
|
||||
flags |= FLAGS_CHAR;
|
||||
format++;
|
||||
}
|
||||
break;
|
||||
#if defined(PRINTF_SUPPORT_PTRDIFF_T)
|
||||
case 't':
|
||||
flags |=
|
||||
(sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
|
||||
format++;
|
||||
break;
|
||||
#endif
|
||||
case 'j':
|
||||
flags |=
|
||||
(sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
|
||||
format++;
|
||||
break;
|
||||
case 'z':
|
||||
flags |=
|
||||
(sizeof(size_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
|
||||
format++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// evaluate specifier
|
||||
switch (*format) {
|
||||
case 'd':
|
||||
case 'i':
|
||||
case 'u':
|
||||
case 'x':
|
||||
case 'X':
|
||||
case 'o':
|
||||
case 'b': {
|
||||
// set the base
|
||||
unsigned int base;
|
||||
if (*format == 'x' || *format == 'X') {
|
||||
base = 16U;
|
||||
} else if (*format == 'o') {
|
||||
base = 8U;
|
||||
} else if (*format == 'b') {
|
||||
base = 2U;
|
||||
} else {
|
||||
base = 10U;
|
||||
flags &= ~FLAGS_HASH; // no hash for dec format
|
||||
}
|
||||
// uppercase
|
||||
if (*format == 'X') { flags |= FLAGS_UPPERCASE; }
|
||||
|
||||
// no plus or space flag for u, x, X, o, b
|
||||
if ((*format != 'i') && (*format != 'd')) {
|
||||
flags &= ~(FLAGS_PLUS | FLAGS_SPACE);
|
||||
}
|
||||
|
||||
// ignore '0' flag when precision is given
|
||||
if (flags & FLAGS_PRECISION) { flags &= ~FLAGS_ZEROPAD; }
|
||||
|
||||
// convert the integer
|
||||
if ((*format == 'i') || (*format == 'd')) {
|
||||
// signed
|
||||
if (flags & FLAGS_LONG_LONG) {
|
||||
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||
const long long value = va_arg(va, long long);
|
||||
idx = _ntoa_long_long(
|
||||
out, buffer, idx, maxlen,
|
||||
(unsigned long long)(value > 0 ? value : 0 - value), value < 0,
|
||||
base, precision, width, flags);
|
||||
#endif
|
||||
} else if (flags & FLAGS_LONG) {
|
||||
const long value = va_arg(va, long);
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen,
|
||||
(unsigned long)(value > 0 ? value : 0 - value),
|
||||
value < 0, base, precision, width, flags);
|
||||
} else {
|
||||
const int value = (flags & FLAGS_CHAR) ? (char)va_arg(va, int)
|
||||
: (flags & FLAGS_SHORT)
|
||||
? (short int)va_arg(va, int)
|
||||
: va_arg(va, int);
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen,
|
||||
(unsigned int)(value > 0 ? value : 0 - value),
|
||||
value < 0, base, precision, width, flags);
|
||||
}
|
||||
} else {
|
||||
// unsigned
|
||||
if (flags & FLAGS_LONG_LONG) {
|
||||
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||
idx = _ntoa_long_long(out, buffer, idx, maxlen,
|
||||
va_arg(va, unsigned long long), false, base,
|
||||
precision, width, flags);
|
||||
#endif
|
||||
} else if (flags & FLAGS_LONG) {
|
||||
idx =
|
||||
_ntoa_long(out, buffer, idx, maxlen, va_arg(va, unsigned long),
|
||||
false, base, precision, width, flags);
|
||||
} else {
|
||||
const unsigned int value =
|
||||
(flags & FLAGS_CHAR) ? (unsigned char)va_arg(va, unsigned int)
|
||||
: (flags & FLAGS_SHORT)
|
||||
? (unsigned short int)va_arg(va, unsigned int)
|
||||
: va_arg(va, unsigned int);
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen, value, false, base,
|
||||
precision, width, flags);
|
||||
}
|
||||
}
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
#if defined(PRINTF_SUPPORT_FLOAT)
|
||||
case 'f':
|
||||
case 'F':
|
||||
if (*format == 'F') flags |= FLAGS_UPPERCASE;
|
||||
idx = _ftoa(out, buffer, idx, maxlen, va_arg(va, double), precision,
|
||||
width, flags);
|
||||
format++;
|
||||
break;
|
||||
#if defined(PRINTF_SUPPORT_EXPONENTIAL)
|
||||
case 'e':
|
||||
case 'E':
|
||||
case 'g':
|
||||
case 'G':
|
||||
if ((*format == 'g') || (*format == 'G')) flags |= FLAGS_ADAPT_EXP;
|
||||
if ((*format == 'E') || (*format == 'G')) flags |= FLAGS_UPPERCASE;
|
||||
idx = _etoa(out, buffer, idx, maxlen, va_arg(va, double), precision,
|
||||
width, flags);
|
||||
format++;
|
||||
break;
|
||||
#endif // PRINTF_SUPPORT_EXPONENTIAL
|
||||
#endif // PRINTF_SUPPORT_FLOAT
|
||||
case 'c': {
|
||||
unsigned int l = 1U;
|
||||
// pre padding
|
||||
if (!(flags & FLAGS_LEFT)) {
|
||||
while (l++ < width) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
// char output
|
||||
out((char)va_arg(va, int), buffer, idx++, maxlen);
|
||||
// post padding
|
||||
if (flags & FLAGS_LEFT) {
|
||||
while (l++ < width) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
|
||||
case 's': {
|
||||
const char *p = va_arg(va, char *);
|
||||
unsigned int l = _strnlen_s(p, precision ? precision : (size_t)-1);
|
||||
// pre padding
|
||||
if (flags & FLAGS_PRECISION) { l = (l < precision ? l : precision); }
|
||||
if (!(flags & FLAGS_LEFT)) {
|
||||
while (l++ < width) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
// string output
|
||||
while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision--)) {
|
||||
out(*(p++), buffer, idx++, maxlen);
|
||||
}
|
||||
// post padding
|
||||
if (flags & FLAGS_LEFT) {
|
||||
while (l++ < width) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'p': {
|
||||
width = sizeof(void *) * 2U;
|
||||
flags |= FLAGS_ZEROPAD | FLAGS_UPPERCASE;
|
||||
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||
const bool is_ll = sizeof(uintptr_t) == sizeof(long long);
|
||||
if (is_ll) {
|
||||
idx = _ntoa_long_long(out, buffer, idx, maxlen,
|
||||
(uintptr_t)va_arg(va, void *), false, 16U,
|
||||
precision, width, flags);
|
||||
} else {
|
||||
#endif
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen,
|
||||
(unsigned long)((uintptr_t)va_arg(va, void *)),
|
||||
false, 16U, precision, width, flags);
|
||||
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||
}
|
||||
#endif
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
|
||||
case '%':
|
||||
out('%', buffer, idx++, maxlen);
|
||||
format++;
|
||||
break;
|
||||
|
||||
default:
|
||||
out(*format, buffer, idx++, maxlen);
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// termination
|
||||
out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen);
|
||||
|
||||
// return written chars without terminating \0
|
||||
return (int)idx;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int printf_(const char *format, ...) {
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
char buffer[1];
|
||||
const int ret = _vsnprintf(_out_char, buffer, (size_t)-1, format, va);
|
||||
va_end(va);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sprintf_(char *buffer, const char *format, ...) {
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
const int ret = _vsnprintf(_out_buffer, buffer, (size_t)-1, format, va);
|
||||
va_end(va);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int snprintf_(char *buffer, size_t count, const char *format, ...) {
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
const int ret = _vsnprintf(_out_buffer, buffer, count, format, va);
|
||||
va_end(va);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int vprintf_(const char *format, va_list va) {
|
||||
char buffer[1];
|
||||
return _vsnprintf(_out_char, buffer, (size_t)-1, format, va);
|
||||
}
|
||||
|
||||
int vsnprintf_(char *buffer, size_t count, const char *format, va_list va) {
|
||||
return _vsnprintf(_out_buffer, buffer, count, format, va);
|
||||
}
|
||||
|
||||
int fctprintf(void (*out)(char character, void *arg), void *arg,
|
||||
const char *format, ...) {
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
const out_fct_wrap_type out_fct_wrap = {out, arg};
|
||||
const int ret = _vsnprintf(_out_fct, (char *)(uintptr_t)&out_fct_wrap,
|
||||
(size_t)-1, format, va);
|
||||
va_end(va);
|
||||
return ret;
|
||||
}
|
23
libafl_qemu/librasan/asan/cc/src/vasprintf.c
Normal file
23
libafl_qemu/librasan/asan/cc/src/vasprintf.c
Normal file
@ -0,0 +1,23 @@
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include "hooks.h"
|
||||
#include "printf.h"
|
||||
#include "trace.h"
|
||||
|
||||
int vasprintf(char **restrict strp, const char *restrict fmt, va_list va) {
|
||||
trace("asprintf - strp: %p, fmt: %p\n", strp, fmt);
|
||||
if (strp == NULL) { return -1; }
|
||||
|
||||
if (fmt == NULL) { return -1; }
|
||||
|
||||
int len = vsnprintf_(NULL, 0, fmt, va);
|
||||
|
||||
if (len < 0) { return -1; }
|
||||
|
||||
void *buffer = asan_alloc(len + 1, 0);
|
||||
if (buffer == NULL) { return -1; }
|
||||
|
||||
*strp = buffer;
|
||||
return vsnprintf_(buffer, len, fmt, va);
|
||||
}
|
105
libafl_qemu/librasan/asan/src/allocator/backend/dlmalloc.rs
Normal file
105
libafl_qemu/librasan/asan/src/allocator/backend/dlmalloc.rs
Normal file
@ -0,0 +1,105 @@
|
||||
//! # dlmalloc
|
||||
//! This allocator makes use of the `dlmalloc` crate to manage memory. It in
|
||||
//! turn uses pages of memory allocated by one of the implementations of the
|
||||
//! `Mmap` trait described in the `mmap` module.
|
||||
use alloc::{
|
||||
alloc::{GlobalAlloc, Layout},
|
||||
fmt::{self, Debug, Formatter},
|
||||
};
|
||||
use core::{marker::PhantomData, mem::forget, ptr::null_mut};
|
||||
|
||||
use dlmalloc::{Allocator, Dlmalloc};
|
||||
use log::debug;
|
||||
use spin::Mutex;
|
||||
|
||||
use crate::mmap::Mmap;
|
||||
|
||||
pub struct DlmallocBackendMap<M: Mmap> {
|
||||
page_size: usize,
|
||||
_phantom: PhantomData<M>,
|
||||
}
|
||||
|
||||
unsafe impl<M: Mmap + Send> Allocator for DlmallocBackendMap<M> {
|
||||
fn alloc(&self, size: usize) -> (*mut u8, usize, u32) {
|
||||
let map = M::map(size);
|
||||
match map {
|
||||
Ok(mut map) => {
|
||||
let slice = map.as_mut_slice();
|
||||
let result = (slice.as_mut_ptr(), slice.len(), 0);
|
||||
forget(map);
|
||||
result
|
||||
}
|
||||
Err(e) => {
|
||||
debug!("alloc failed: {:#?}", e);
|
||||
(null_mut(), 0, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn remap(&self, _ptr: *mut u8, _oldsize: usize, _newsize: usize, _can_move: bool) -> *mut u8 {
|
||||
null_mut()
|
||||
}
|
||||
|
||||
fn free_part(&self, _ptr: *mut u8, _oldsize: usize, _newsize: usize) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn free(&self, _ptr: *mut u8, _size: usize) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn can_release_part(&self, _flags: u32) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn allocates_zeros(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn page_size(&self) -> usize {
|
||||
self.page_size
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: Mmap> DlmallocBackendMap<M> {
|
||||
pub const fn new(page_size: usize) -> DlmallocBackendMap<M> {
|
||||
DlmallocBackendMap {
|
||||
page_size,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DlmallocBackend<M: Mmap> {
|
||||
dlmalloc: Mutex<Dlmalloc<DlmallocBackendMap<M>>>,
|
||||
}
|
||||
|
||||
impl<M: Mmap + Send> DlmallocBackend<M> {
|
||||
pub const fn new(page_size: usize) -> DlmallocBackend<M> {
|
||||
let backend = DlmallocBackendMap::new(page_size);
|
||||
let dlmalloc = Dlmalloc::<DlmallocBackendMap<M>>::new_with_allocator(backend);
|
||||
Self {
|
||||
dlmalloc: Mutex::new(dlmalloc),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: Mmap + Send> Debug for DlmallocBackend<M> {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "DlmallocBackend")
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<M: Mmap> GlobalAlloc for DlmallocBackend<M> {
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||
unsafe { self.dlmalloc.lock().malloc(layout.size(), layout.align()) }
|
||||
}
|
||||
|
||||
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
||||
unsafe {
|
||||
self.dlmalloc
|
||||
.lock()
|
||||
.free(ptr, layout.size(), layout.align())
|
||||
}
|
||||
}
|
||||
}
|
26
libafl_qemu/librasan/asan/src/allocator/backend/mimalloc.rs
Normal file
26
libafl_qemu/librasan/asan/src/allocator/backend/mimalloc.rs
Normal file
@ -0,0 +1,26 @@
|
||||
use alloc::alloc::{GlobalAlloc, Layout};
|
||||
|
||||
use baby_mimalloc::Mimalloc;
|
||||
use spin::Mutex;
|
||||
|
||||
pub struct MimallocBackend<G: GlobalAlloc> {
|
||||
mimalloc: Mutex<Mimalloc<G>>,
|
||||
}
|
||||
|
||||
impl<G: GlobalAlloc> MimallocBackend<G> {
|
||||
pub const fn new(global_allocator: G) -> Self {
|
||||
MimallocBackend {
|
||||
mimalloc: Mutex::new(Mimalloc::with_os_allocator(global_allocator)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<G: GlobalAlloc> GlobalAlloc for MimallocBackend<G> {
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||
unsafe { self.mimalloc.lock().alloc(layout) }
|
||||
}
|
||||
|
||||
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
||||
unsafe { self.mimalloc.lock().dealloc(ptr, layout) }
|
||||
}
|
||||
}
|
18
libafl_qemu/librasan/asan/src/allocator/backend/mod.rs
Normal file
18
libafl_qemu/librasan/asan/src/allocator/backend/mod.rs
Normal file
@ -0,0 +1,18 @@
|
||||
//! # backend
|
||||
//! The backend is responsible for allocating the underlying memory used by the
|
||||
//! application. A backend should implement the `GlobalAlloc` trait. At present
|
||||
//! there are two implemented backends:
|
||||
//!
|
||||
//! - `dlmalloc` - A pure rust allocator based on the `dlmalloc` crate.
|
||||
//! - `mimalloc` - A rust allocator using the baby_mimalloc crate which wraps
|
||||
//! another backend
|
||||
//!
|
||||
//! A number other of possible implementations could be considered:
|
||||
//! - A simple bump allocator allocating from a fixed memory buffer
|
||||
//! - An allocator which calls down into the original `libc` implementation of `malloc`
|
||||
|
||||
#[cfg(feature = "dlmalloc")]
|
||||
pub mod dlmalloc;
|
||||
|
||||
#[cfg(feature = "mimalloc")]
|
||||
pub mod mimalloc;
|
246
libafl_qemu/librasan/asan/src/allocator/frontend/default.rs
Normal file
246
libafl_qemu/librasan/asan/src/allocator/frontend/default.rs
Normal file
@ -0,0 +1,246 @@
|
||||
//! # default
|
||||
//! The default frontend is primarily designed for simplicity. Though called
|
||||
//! the default, it may be subsequently replaced as the preferred frontend
|
||||
//! should a more optimal design be implemented at a later date.
|
||||
//!
|
||||
//! This frontend stores all of it's metadata out-of-band, that is no meta-data
|
||||
//! is stored adjacent to the user's buffers. The size of the red-zone applied
|
||||
//! to each allocation is configurable. The frontend also supports the use of a
|
||||
//! quarantine (whose size is configurable) to prevent user buffers from being
|
||||
//! re-used for a period of time.
|
||||
use alloc::{
|
||||
alloc::{GlobalAlloc, Layout, LayoutError},
|
||||
collections::{BTreeMap, VecDeque},
|
||||
fmt::Debug,
|
||||
};
|
||||
use core::slice::from_raw_parts_mut;
|
||||
|
||||
use log::debug;
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::{
|
||||
GuestAddr,
|
||||
allocator::frontend::AllocatorFrontend,
|
||||
shadow::{PoisonType, Shadow},
|
||||
tracking::Tracking,
|
||||
};
|
||||
|
||||
struct Allocation {
|
||||
frontend_len: usize,
|
||||
backend_addr: GuestAddr,
|
||||
backend_len: usize,
|
||||
backend_align: usize,
|
||||
}
|
||||
|
||||
pub struct DefaultFrontend<B: GlobalAlloc + Send, S: Shadow, T: Tracking> {
|
||||
backend: B,
|
||||
shadow: S,
|
||||
tracking: T,
|
||||
red_zone_size: usize,
|
||||
allocations: BTreeMap<GuestAddr, Allocation>,
|
||||
quarantine: VecDeque<Allocation>,
|
||||
quarantine_size: usize,
|
||||
quaratine_used: usize,
|
||||
}
|
||||
|
||||
impl<B: GlobalAlloc + Send, S: Shadow, T: Tracking> AllocatorFrontend for DefaultFrontend<B, S, T> {
|
||||
type Error = DefaultFrontendError<S, T>;
|
||||
|
||||
fn alloc(&mut self, len: usize, align: usize) -> Result<GuestAddr, Self::Error> {
|
||||
debug!("alloc - len: 0x{:x}, align: 0x{:x}", len, align);
|
||||
if align % size_of::<GuestAddr>() != 0 {
|
||||
Err(DefaultFrontendError::InvalidAlignment(align))?;
|
||||
}
|
||||
let size = len + align;
|
||||
let allocated_size = (self.red_zone_size * 2) + Self::align_up(size);
|
||||
assert!(allocated_size % Self::ALLOC_ALIGN_SIZE == 0);
|
||||
let ptr = unsafe {
|
||||
self.backend.alloc(
|
||||
Layout::from_size_align(allocated_size, Self::ALLOC_ALIGN_SIZE)
|
||||
.map_err(DefaultFrontendError::LayoutError)?,
|
||||
)
|
||||
};
|
||||
|
||||
if ptr.is_null() {
|
||||
Err(DefaultFrontendError::AllocatorError)?;
|
||||
}
|
||||
|
||||
let orig = ptr as GuestAddr;
|
||||
|
||||
debug!(
|
||||
"alloc - buffer: 0x{:x}, len: 0x{:x}, align: 0x{:x}",
|
||||
orig,
|
||||
allocated_size,
|
||||
Self::ALLOC_ALIGN_SIZE
|
||||
);
|
||||
|
||||
let rz = orig + self.red_zone_size;
|
||||
let data = if align == 0 {
|
||||
rz
|
||||
} else {
|
||||
rz + align - (rz % align)
|
||||
};
|
||||
assert!(align == 0 || data % align == 0);
|
||||
assert!(data + len <= orig + allocated_size);
|
||||
|
||||
self.allocations.insert(
|
||||
data,
|
||||
Allocation {
|
||||
frontend_len: len,
|
||||
backend_addr: orig,
|
||||
backend_len: allocated_size,
|
||||
backend_align: Self::ALLOC_ALIGN_SIZE,
|
||||
},
|
||||
);
|
||||
|
||||
self.tracking
|
||||
.alloc(data, len)
|
||||
.map_err(|e| DefaultFrontendError::TrackingError(e))?;
|
||||
self.shadow
|
||||
.poison(orig, data - orig, PoisonType::AsanHeapLeftRz)
|
||||
.map_err(|e| DefaultFrontendError::ShadowError(e))?;
|
||||
self.shadow
|
||||
.unpoison(data, len)
|
||||
.map_err(|e| DefaultFrontendError::ShadowError(e))?;
|
||||
let poison_len = Self::align_up(len) - len + self.red_zone_size;
|
||||
self.shadow
|
||||
.poison(data + len, poison_len, PoisonType::AsanStackRightRz)
|
||||
.map_err(|e| DefaultFrontendError::ShadowError(e))?;
|
||||
|
||||
let buffer = unsafe { from_raw_parts_mut(data as *mut u8, len) };
|
||||
buffer.iter_mut().for_each(|b| *b = 0xff);
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
fn dealloc(&mut self, addr: GuestAddr) -> Result<(), Self::Error> {
|
||||
debug!("dealloc - addr: 0x{:x}", addr);
|
||||
if addr == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let alloc = self
|
||||
.allocations
|
||||
.remove(&addr)
|
||||
.ok_or_else(|| DefaultFrontendError::InvalidAddress(addr))?;
|
||||
self.shadow
|
||||
.poison(
|
||||
alloc.backend_addr,
|
||||
alloc.backend_len,
|
||||
PoisonType::AsanHeapFreed,
|
||||
)
|
||||
.map_err(|e| DefaultFrontendError::ShadowError(e))?;
|
||||
self.tracking
|
||||
.dealloc(addr)
|
||||
.map_err(|e| DefaultFrontendError::TrackingError(e))?;
|
||||
self.quaratine_used += alloc.backend_len;
|
||||
self.quarantine.push_back(alloc);
|
||||
self.purge_quarantine()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_size(&self, addr: GuestAddr) -> Result<usize, Self::Error> {
|
||||
debug!("get_size - addr: 0x{:x}", addr);
|
||||
let alloc = self
|
||||
.allocations
|
||||
.get(&addr)
|
||||
.ok_or_else(|| DefaultFrontendError::InvalidAddress(addr))?;
|
||||
Ok(alloc.frontend_len)
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: GlobalAlloc + Send, S: Shadow, T: Tracking> DefaultFrontend<B, S, T> {
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
const ALLOC_ALIGN_SIZE: usize = 8;
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
const ALLOC_ALIGN_SIZE: usize = 16;
|
||||
|
||||
pub const DEFAULT_REDZONE_SIZE: usize = 128;
|
||||
pub const DEFAULT_QUARANTINE_SIZE: usize = 50 << 20;
|
||||
|
||||
pub fn new(
|
||||
backend: B,
|
||||
shadow: S,
|
||||
tracking: T,
|
||||
red_zone_size: usize,
|
||||
quarantine_size: usize,
|
||||
) -> Result<DefaultFrontend<B, S, T>, DefaultFrontendError<S, T>> {
|
||||
if red_zone_size % Self::ALLOC_ALIGN_SIZE != 0 {
|
||||
Err(DefaultFrontendError::InvalidRedZoneSize(red_zone_size))?;
|
||||
}
|
||||
Ok(DefaultFrontend::<B, S, T> {
|
||||
backend,
|
||||
shadow,
|
||||
tracking,
|
||||
red_zone_size,
|
||||
allocations: BTreeMap::new(),
|
||||
quarantine: VecDeque::new(),
|
||||
quarantine_size,
|
||||
quaratine_used: 0,
|
||||
})
|
||||
}
|
||||
|
||||
fn purge_quarantine(&mut self) -> Result<(), DefaultFrontendError<S, T>> {
|
||||
while self.quaratine_used > self.quarantine_size {
|
||||
let alloc = self
|
||||
.quarantine
|
||||
.pop_front()
|
||||
.ok_or(DefaultFrontendError::QuarantineCorruption)?;
|
||||
unsafe {
|
||||
self.backend.dealloc(
|
||||
alloc.backend_addr as *mut u8,
|
||||
Layout::from_size_align(alloc.backend_len, alloc.backend_align)
|
||||
.map_err(DefaultFrontendError::LayoutError)?,
|
||||
)
|
||||
};
|
||||
self.quaratine_used -= alloc.backend_len;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn align_up(size: usize) -> usize {
|
||||
assert!(size <= GuestAddr::MAX - (Self::ALLOC_ALIGN_SIZE - 1));
|
||||
let val = size + (Self::ALLOC_ALIGN_SIZE - 1);
|
||||
val & !(Self::ALLOC_ALIGN_SIZE - 1)
|
||||
}
|
||||
|
||||
pub fn shadow(&self) -> &S {
|
||||
&self.shadow
|
||||
}
|
||||
|
||||
pub fn shadow_mut(&mut self) -> &mut S {
|
||||
&mut self.shadow
|
||||
}
|
||||
|
||||
pub fn tracking(&self) -> &T {
|
||||
&self.tracking
|
||||
}
|
||||
|
||||
pub fn tracking_mut(&mut self) -> &mut T {
|
||||
&mut self.tracking
|
||||
}
|
||||
|
||||
pub fn backend_mut(&mut self) -> &mut B {
|
||||
&mut self.backend
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Error, Debug, PartialEq)]
|
||||
pub enum DefaultFrontendError<S: Shadow, T: Tracking> {
|
||||
#[error("Invalid red_zone_size: {0}")]
|
||||
InvalidRedZoneSize(usize),
|
||||
#[error("Invalid alignment: {0}")]
|
||||
InvalidAlignment(usize),
|
||||
#[error("Allocator error")]
|
||||
AllocatorError,
|
||||
#[error("Layout error: {0:?}")]
|
||||
LayoutError(LayoutError),
|
||||
#[error("Shadow error: {0:?}")]
|
||||
ShadowError(S::Error),
|
||||
#[error("Tracking error: {0:?}")]
|
||||
TrackingError(T::Error),
|
||||
#[error("Invalid address: {0:x}")]
|
||||
InvalidAddress(GuestAddr),
|
||||
#[error("Quarantine corruption")]
|
||||
QuarantineCorruption,
|
||||
}
|
16
libafl_qemu/librasan/asan/src/allocator/frontend/mod.rs
Normal file
16
libafl_qemu/librasan/asan/src/allocator/frontend/mod.rs
Normal file
@ -0,0 +1,16 @@
|
||||
//! # frontend
|
||||
//! The frontend of the allocator is responsible for applying the value-added
|
||||
//! asan features on behalf of incoming user requests for allocations including
|
||||
//! red-zones, poisoning and memory tracking.
|
||||
use alloc::fmt::Debug;
|
||||
|
||||
use crate::GuestAddr;
|
||||
|
||||
pub mod default;
|
||||
|
||||
pub trait AllocatorFrontend: Sized + Send {
|
||||
type Error: Debug;
|
||||
fn alloc(&mut self, len: usize, align: usize) -> Result<GuestAddr, Self::Error>;
|
||||
fn dealloc(&mut self, addr: GuestAddr) -> Result<(), Self::Error>;
|
||||
fn get_size(&self, addr: GuestAddr) -> Result<usize, Self::Error>;
|
||||
}
|
9
libafl_qemu/librasan/asan/src/allocator/mod.rs
Normal file
9
libafl_qemu/librasan/asan/src/allocator/mod.rs
Normal file
@ -0,0 +1,9 @@
|
||||
//! # allocator
|
||||
//! The allocator is split into two parts:
|
||||
//! - `backend` - The is the portion responsible for allocating the underlying
|
||||
//! memory used by the application.
|
||||
//! - `frontend` - The portion is responsible for applying the value-added asan
|
||||
//! features on behalf of incoming user requests for allocations including
|
||||
//! red-zones, poisoning and memory tracking.
|
||||
pub mod backend;
|
||||
pub mod frontend;
|
4
libafl_qemu/librasan/asan/src/arch/aarch64.rs
Normal file
4
libafl_qemu/librasan/asan/src/arch/aarch64.rs
Normal file
@ -0,0 +1,4 @@
|
||||
#[unsafe(no_mangle)]
|
||||
extern "C" fn getauxval(_type: u64) -> u64 {
|
||||
0
|
||||
}
|
15
libafl_qemu/librasan/asan/src/arch/arm.rs
Normal file
15
libafl_qemu/librasan/asan/src/arch/arm.rs
Normal file
@ -0,0 +1,15 @@
|
||||
use log::error;
|
||||
|
||||
use crate::exit::abort;
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
extern "C" fn __aeabi_unwind_cpp_pr0() {
|
||||
error!("__aeabi_unwind_cpp_pr0");
|
||||
abort();
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
extern "C" fn __aeabi_unwind_cpp_pr1() {
|
||||
error!("__aeabi_unwind_cpp_pr1");
|
||||
abort();
|
||||
}
|
15
libafl_qemu/librasan/asan/src/arch/mod.rs
Normal file
15
libafl_qemu/librasan/asan/src/arch/mod.rs
Normal file
@ -0,0 +1,15 @@
|
||||
use log::error;
|
||||
|
||||
use crate::exit::abort;
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
mod aarch64;
|
||||
|
||||
#[cfg(target_arch = "arm")]
|
||||
mod arm;
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
extern "C" fn _Unwind_Resume() {
|
||||
error!("_Unwind_Resume");
|
||||
abort();
|
||||
}
|
56
libafl_qemu/librasan/asan/src/exit/libc.rs
Normal file
56
libafl_qemu/librasan/asan/src/exit/libc.rs
Normal file
@ -0,0 +1,56 @@
|
||||
use core::ffi::{CStr, c_char, c_int};
|
||||
|
||||
use libc::{SIGABRT, pid_t};
|
||||
|
||||
use crate::{
|
||||
GuestAddr, asan_swap,
|
||||
symbols::{Function, FunctionPointer},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
struct FunctionGetpid;
|
||||
|
||||
impl Function for FunctionGetpid {
|
||||
type Func = unsafe extern "C" fn() -> pid_t;
|
||||
const NAME: &'static CStr = c"getpid";
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct FunctionKill;
|
||||
|
||||
impl Function for FunctionKill {
|
||||
type Func = unsafe extern "C" fn(pid_t, c_int) -> c_int;
|
||||
const NAME: &'static CStr = c"kill";
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct FunctionExit;
|
||||
|
||||
impl Function for FunctionExit {
|
||||
type Func = unsafe extern "C" fn(c_int) -> !;
|
||||
const NAME: &'static CStr = c"_exit";
|
||||
}
|
||||
|
||||
unsafe extern "C" {
|
||||
fn asan_sym(name: *const c_char) -> GuestAddr;
|
||||
}
|
||||
|
||||
pub fn abort() -> ! {
|
||||
let getpid_addr = unsafe { asan_sym(FunctionGetpid::NAME.as_ptr() as *const c_char) };
|
||||
let fn_getpid = FunctionGetpid::as_ptr(getpid_addr).unwrap();
|
||||
|
||||
let kill_addr = unsafe { asan_sym(FunctionKill::NAME.as_ptr() as *const c_char) };
|
||||
let fn_kill = FunctionKill::as_ptr(kill_addr).unwrap();
|
||||
|
||||
unsafe { asan_swap(false) };
|
||||
let pid = unsafe { fn_getpid() };
|
||||
unsafe { fn_kill(pid, SIGABRT) };
|
||||
unreachable!();
|
||||
}
|
||||
|
||||
pub fn exit(status: c_int) -> ! {
|
||||
let exit_addr = unsafe { asan_sym(FunctionExit::NAME.as_ptr() as *const c_char) };
|
||||
let fn_exit = FunctionExit::as_ptr(exit_addr).unwrap();
|
||||
unsafe { asan_swap(false) };
|
||||
unsafe { fn_exit(status) };
|
||||
}
|
14
libafl_qemu/librasan/asan/src/exit/linux.rs
Normal file
14
libafl_qemu/librasan/asan/src/exit/linux.rs
Normal file
@ -0,0 +1,14 @@
|
||||
use core::ffi::c_int;
|
||||
|
||||
use rustix::process::{Signal, kill_current_process_group};
|
||||
use syscalls::{Sysno, syscall1};
|
||||
|
||||
pub fn abort() -> ! {
|
||||
kill_current_process_group(Signal::ABORT).unwrap();
|
||||
unreachable!();
|
||||
}
|
||||
|
||||
pub fn exit(status: c_int) -> ! {
|
||||
unsafe { syscall1(Sysno::exit_group, status as usize) }.unwrap();
|
||||
unreachable!();
|
||||
}
|
16
libafl_qemu/librasan/asan/src/exit/mod.rs
Normal file
16
libafl_qemu/librasan/asan/src/exit/mod.rs
Normal file
@ -0,0 +1,16 @@
|
||||
//! # die
|
||||
//! This module supports exiting the process
|
||||
#[cfg(feature = "libc")]
|
||||
pub use crate::exit::libc::abort;
|
||||
#[cfg(feature = "libc")]
|
||||
pub use crate::exit::libc::exit;
|
||||
#[cfg(all(feature = "linux", not(feature = "libc")))]
|
||||
pub use crate::exit::linux::abort;
|
||||
#[cfg(all(feature = "linux", not(feature = "libc")))]
|
||||
pub use crate::exit::linux::exit;
|
||||
|
||||
#[cfg(feature = "libc")]
|
||||
pub mod libc;
|
||||
|
||||
#[cfg(feature = "linux")]
|
||||
pub mod linux;
|
38
libafl_qemu/librasan/asan/src/hooks/aligned_alloc.rs
Normal file
38
libafl_qemu/librasan/asan/src/hooks/aligned_alloc.rs
Normal file
@ -0,0 +1,38 @@
|
||||
use core::{
|
||||
ffi::{c_char, c_void},
|
||||
mem::size_of,
|
||||
ptr::null_mut,
|
||||
};
|
||||
|
||||
use log::trace;
|
||||
|
||||
use crate::{GuestAddr, asan_alloc, asan_panic, size_t};
|
||||
|
||||
/// # Safety
|
||||
/// See man pages
|
||||
#[unsafe(export_name = "patch_aligned_alloc")]
|
||||
pub unsafe extern "C" fn aligned_alloc(alignment: size_t, size: size_t) -> *mut c_void {
|
||||
unsafe {
|
||||
trace!(
|
||||
"aligned_alloc - alignment: {:#x}, size: {:#x}",
|
||||
alignment, size
|
||||
);
|
||||
|
||||
fn is_power_of_two(n: size_t) -> bool {
|
||||
n != 0 && (n & (n - 1)) == 0
|
||||
}
|
||||
|
||||
if alignment % size_of::<GuestAddr>() != 0 {
|
||||
asan_panic(
|
||||
c"aligned_alloc - alignment is not a multiple of pointer size".as_ptr()
|
||||
as *const c_char,
|
||||
);
|
||||
} else if !is_power_of_two(alignment) {
|
||||
asan_panic(c"aligned_alloc - alignment is not a power of two".as_ptr() as *const c_char);
|
||||
} else if size == 0 {
|
||||
null_mut()
|
||||
} else {
|
||||
asan_alloc(size, alignment)
|
||||
}
|
||||
}
|
||||
}
|
85
libafl_qemu/librasan/asan/src/hooks/atoi.rs
Normal file
85
libafl_qemu/librasan/asan/src/hooks/atoi.rs
Normal file
@ -0,0 +1,85 @@
|
||||
use core::{
|
||||
ffi::{c_char, c_int, c_uint, c_void},
|
||||
slice::from_raw_parts,
|
||||
};
|
||||
|
||||
use log::trace;
|
||||
|
||||
use crate::{asan_load, asan_panic};
|
||||
|
||||
/// # Safety
|
||||
/// See man pages
|
||||
#[unsafe(export_name = "patch_atoi")]
|
||||
pub unsafe extern "C" fn atoi(s: *const c_char) -> c_int {
|
||||
unsafe {
|
||||
trace!("atoi - s: {:p}", s);
|
||||
|
||||
if s.is_null() {
|
||||
asan_panic(c"atoi - s is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
let mut len = 0;
|
||||
while *s.add(len) != 0 {
|
||||
len += 1;
|
||||
}
|
||||
asan_load(s as *const c_void, len + 1);
|
||||
let slice = from_raw_parts(s, len);
|
||||
|
||||
let mut i = 0;
|
||||
|
||||
let ws = [
|
||||
0x20, /* ' ' */
|
||||
0xc, /* \f */
|
||||
0xa, /* \n */
|
||||
0xd, /* \r */
|
||||
0x9, /* \t */
|
||||
0xb, /* \v */
|
||||
];
|
||||
while ws.contains(&slice[i]) {
|
||||
i += 1;
|
||||
}
|
||||
|
||||
let mut negative = false;
|
||||
if slice[i] == 0x2d
|
||||
/* '-' */
|
||||
{
|
||||
negative = true;
|
||||
i += 1;
|
||||
} else if slice[i] == 0x2b
|
||||
/* '+' */
|
||||
{
|
||||
i += 1;
|
||||
}
|
||||
|
||||
let mut val: c_uint = 0;
|
||||
for c in slice.iter().skip(i) {
|
||||
if ('0' as c_char..='9' as c_char).contains(c) {
|
||||
match val.checked_mul(10) {
|
||||
Some(m) => val = m,
|
||||
None => asan_panic(c"atoi - overflow #1".as_ptr() as *const c_char),
|
||||
}
|
||||
let digit = (c - '0' as c_char) as c_uint;
|
||||
match val.checked_add(digit) {
|
||||
Some(a) => val = a,
|
||||
None => asan_panic(c"atoi - overflow #2".as_ptr() as *const c_char),
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if val == 0 {
|
||||
0
|
||||
} else if negative {
|
||||
if val > (c_int::MAX as c_uint) + 1 {
|
||||
asan_panic(c"atoi - overflow #3".as_ptr() as *const c_char);
|
||||
}
|
||||
-((val - 1) as c_int) - 1
|
||||
} else {
|
||||
if val > c_int::MAX as c_uint {
|
||||
asan_panic(c"atoi - overflow #4".as_ptr() as *const c_char);
|
||||
}
|
||||
val as c_int
|
||||
}
|
||||
}
|
||||
}
|
85
libafl_qemu/librasan/asan/src/hooks/atol.rs
Normal file
85
libafl_qemu/librasan/asan/src/hooks/atol.rs
Normal file
@ -0,0 +1,85 @@
|
||||
use core::{
|
||||
ffi::{c_char, c_long, c_ulong, c_void},
|
||||
slice::from_raw_parts,
|
||||
};
|
||||
|
||||
use log::trace;
|
||||
|
||||
use crate::{asan_load, asan_panic};
|
||||
|
||||
/// # Safety
|
||||
/// See man pages
|
||||
#[unsafe(export_name = "patch_atol")]
|
||||
pub unsafe extern "C" fn atol(s: *const c_char) -> c_long {
|
||||
unsafe {
|
||||
trace!("atol - s: {:p}", s);
|
||||
|
||||
if s.is_null() {
|
||||
asan_panic(c"atol - s is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
let mut len = 0;
|
||||
while *s.add(len) != 0 {
|
||||
len += 1;
|
||||
}
|
||||
asan_load(s as *const c_void, len + 1);
|
||||
let slice = from_raw_parts(s, len);
|
||||
|
||||
let mut i = 0;
|
||||
|
||||
let ws = [
|
||||
0x20, /* ' ' */
|
||||
0xc, /* \f */
|
||||
0xa, /* \n */
|
||||
0xd, /* \r */
|
||||
0x9, /* \t */
|
||||
0xb, /* \v */
|
||||
];
|
||||
while ws.contains(&slice[i]) {
|
||||
i += 1;
|
||||
}
|
||||
|
||||
let mut negative = false;
|
||||
if slice[i] == 0x2d
|
||||
/* '-' */
|
||||
{
|
||||
negative = true;
|
||||
i += 1;
|
||||
} else if slice[i] == 0x2b
|
||||
/* '+' */
|
||||
{
|
||||
i += 1;
|
||||
}
|
||||
|
||||
let mut val = 0 as c_ulong;
|
||||
for c in slice.iter().skip(i) {
|
||||
if ('0' as c_char..='9' as c_char).contains(c) {
|
||||
match val.checked_mul(10) {
|
||||
Some(m) => val = m,
|
||||
None => asan_panic(c"atoi - overflow #1".as_ptr() as *const c_char),
|
||||
}
|
||||
let digit = (c - '0' as c_char) as c_ulong;
|
||||
match val.checked_add(digit) {
|
||||
Some(a) => val = a,
|
||||
None => asan_panic(c"atoi - overflow #2".as_ptr() as *const c_char),
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if val == 0 {
|
||||
0
|
||||
} else if negative {
|
||||
if val > (c_long::MAX as c_ulong) + 1 {
|
||||
asan_panic(c"atoi - overflow #3".as_ptr() as *const c_char);
|
||||
}
|
||||
-((val - 1) as c_long) - 1
|
||||
} else {
|
||||
if val > c_long::MAX as c_ulong {
|
||||
asan_panic(c"atoi - overflow #4".as_ptr() as *const c_char);
|
||||
}
|
||||
val as c_long
|
||||
}
|
||||
}
|
||||
}
|
85
libafl_qemu/librasan/asan/src/hooks/atoll.rs
Normal file
85
libafl_qemu/librasan/asan/src/hooks/atoll.rs
Normal file
@ -0,0 +1,85 @@
|
||||
use core::{
|
||||
ffi::{c_char, c_longlong, c_ulonglong, c_void},
|
||||
slice::from_raw_parts,
|
||||
};
|
||||
|
||||
use log::trace;
|
||||
|
||||
use crate::{asan_load, asan_panic};
|
||||
|
||||
/// # Safety
|
||||
/// See man pages
|
||||
#[unsafe(export_name = "patch_atoll")]
|
||||
pub unsafe extern "C" fn atoll(s: *const c_char) -> c_longlong {
|
||||
unsafe {
|
||||
trace!("atoll - s: {:p}", s);
|
||||
|
||||
if s.is_null() {
|
||||
asan_panic(c"atol - s is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
let mut len = 0;
|
||||
while *s.add(len) != 0 {
|
||||
len += 1;
|
||||
}
|
||||
asan_load(s as *const c_void, len + 1);
|
||||
let slice = from_raw_parts(s, len);
|
||||
|
||||
let mut i = 0;
|
||||
|
||||
let ws = [
|
||||
0x20, /* ' ' */
|
||||
0xc, /* \f */
|
||||
0xa, /* \n */
|
||||
0xd, /* \r */
|
||||
0x9, /* \t */
|
||||
0xb, /* \v */
|
||||
];
|
||||
while ws.contains(&slice[i]) {
|
||||
i += 1;
|
||||
}
|
||||
|
||||
let mut negative = false;
|
||||
if slice[i] == 0x2d
|
||||
/* '-' */
|
||||
{
|
||||
negative = true;
|
||||
i += 1;
|
||||
} else if slice[i] == 0x2b
|
||||
/* '+' */
|
||||
{
|
||||
i += 1;
|
||||
}
|
||||
|
||||
let mut val = 0 as c_ulonglong;
|
||||
for c in slice.iter().skip(i) {
|
||||
if ('0' as c_char..='9' as c_char).contains(c) {
|
||||
match val.checked_mul(10) {
|
||||
Some(m) => val = m,
|
||||
None => asan_panic(c"atoi - overflow #1".as_ptr() as *const c_char),
|
||||
}
|
||||
let digit = (c - '0' as c_char) as c_ulonglong;
|
||||
match val.checked_add(digit) {
|
||||
Some(a) => val = a,
|
||||
None => asan_panic(c"atoi - overflow #2".as_ptr() as *const c_char),
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if val == 0 {
|
||||
0
|
||||
} else if negative {
|
||||
if val > (c_longlong::MAX as c_ulonglong) + 1 {
|
||||
asan_panic(c"atoi - overflow #3".as_ptr() as *const c_char);
|
||||
}
|
||||
-((val - 1) as c_longlong) - 1
|
||||
} else {
|
||||
if val > c_longlong::MAX as c_ulonglong {
|
||||
asan_panic(c"atoi - overflow #4".as_ptr() as *const c_char);
|
||||
}
|
||||
val as c_longlong
|
||||
}
|
||||
}
|
||||
}
|
46
libafl_qemu/librasan/asan/src/hooks/bcmp.rs
Normal file
46
libafl_qemu/librasan/asan/src/hooks/bcmp.rs
Normal file
@ -0,0 +1,46 @@
|
||||
use core::{
|
||||
cmp::Ordering,
|
||||
ffi::{c_char, c_int, c_void},
|
||||
slice::from_raw_parts,
|
||||
};
|
||||
|
||||
use log::trace;
|
||||
|
||||
use crate::{asan_load, asan_panic, size_t};
|
||||
|
||||
/// # Safety
|
||||
/// See man pages
|
||||
#[unsafe(export_name = "patch_bcmp")]
|
||||
pub unsafe extern "C" fn bcmp(cx: *const c_void, ct: *const c_void, n: size_t) -> c_int {
|
||||
unsafe {
|
||||
trace!("bcmp - cx: {:p}, ct: {:p}, n: {:#x}", cx, ct, n);
|
||||
|
||||
if n == 0 {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if cx.is_null() {
|
||||
asan_panic(c"bcmp - cx is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
if ct.is_null() {
|
||||
asan_panic(c"bcmp - ct is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
asan_load(cx, n);
|
||||
asan_load(ct, n);
|
||||
|
||||
let slice1 = from_raw_parts(cx as *const u8, n);
|
||||
let slice2 = from_raw_parts(ct as *const u8, n);
|
||||
|
||||
for i in 0..n {
|
||||
match slice1[i].cmp(&slice2[i]) {
|
||||
Ordering::Equal => (),
|
||||
Ordering::Less => return -1,
|
||||
Ordering::Greater => return 1,
|
||||
}
|
||||
}
|
||||
|
||||
0
|
||||
}
|
||||
}
|
28
libafl_qemu/librasan/asan/src/hooks/bzero.rs
Normal file
28
libafl_qemu/librasan/asan/src/hooks/bzero.rs
Normal file
@ -0,0 +1,28 @@
|
||||
use core::{
|
||||
ffi::{c_char, c_void},
|
||||
ptr::write_bytes,
|
||||
};
|
||||
|
||||
use log::trace;
|
||||
|
||||
use crate::{asan_panic, asan_store, size_t};
|
||||
|
||||
/// # Safety
|
||||
/// See man pages
|
||||
#[unsafe(export_name = "patch_bzero")]
|
||||
pub unsafe extern "C" fn bzero(s: *mut c_void, len: size_t) {
|
||||
unsafe {
|
||||
trace!("bzero - s: {:p}, len: {:#x}", s, len);
|
||||
|
||||
if len == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
if s.is_null() {
|
||||
asan_panic(c"bzero - s is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
asan_store(s, len);
|
||||
write_bytes(s, 0, len);
|
||||
}
|
||||
}
|
28
libafl_qemu/librasan/asan/src/hooks/calloc.rs
Normal file
28
libafl_qemu/librasan/asan/src/hooks/calloc.rs
Normal file
@ -0,0 +1,28 @@
|
||||
use core::{
|
||||
ffi::{c_char, c_void},
|
||||
ptr::{null_mut, write_bytes},
|
||||
};
|
||||
|
||||
use log::trace;
|
||||
|
||||
use crate::{asan_alloc, asan_panic, size_t};
|
||||
|
||||
/// # Safety
|
||||
/// See man pages
|
||||
#[unsafe(export_name = "patch_calloc")]
|
||||
pub unsafe extern "C" fn calloc(nobj: size_t, size: size_t) -> *mut c_void {
|
||||
unsafe {
|
||||
trace!("calloc - nobj: {:#x}, size: {:#x}", nobj, size);
|
||||
match nobj.checked_mul(size) {
|
||||
Some(0) => null_mut(),
|
||||
Some(size) => {
|
||||
let ptr = asan_alloc(size, 0);
|
||||
write_bytes(ptr, 0, size);
|
||||
ptr
|
||||
}
|
||||
None => {
|
||||
asan_panic(c"calloc - size would overflow".as_ptr() as *const c_char);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
28
libafl_qemu/librasan/asan/src/hooks/explicit_bzero.rs
Normal file
28
libafl_qemu/librasan/asan/src/hooks/explicit_bzero.rs
Normal file
@ -0,0 +1,28 @@
|
||||
use core::{
|
||||
ffi::{c_char, c_void},
|
||||
ptr::write_bytes,
|
||||
};
|
||||
|
||||
use log::trace;
|
||||
|
||||
use crate::{asan_panic, asan_store, size_t};
|
||||
|
||||
/// # Safety
|
||||
/// See man pages
|
||||
#[unsafe(export_name = "patch_explicit_bzero")]
|
||||
pub unsafe extern "C" fn explicit_bzero(s: *mut c_void, len: size_t) {
|
||||
unsafe {
|
||||
trace!("explicit_bzero - s: {:p}, len: {:#x}", s, len);
|
||||
|
||||
if len == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
if s.is_null() {
|
||||
asan_panic(b"explicit_bzero - s is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
asan_store(s, len);
|
||||
write_bytes(s, 0, len);
|
||||
}
|
||||
}
|
47
libafl_qemu/librasan/asan/src/hooks/fgets.rs
Normal file
47
libafl_qemu/librasan/asan/src/hooks/fgets.rs
Normal file
@ -0,0 +1,47 @@
|
||||
use core::ffi::{CStr, c_char, c_int, c_void};
|
||||
|
||||
use libc::FILE;
|
||||
use log::trace;
|
||||
|
||||
use crate::{
|
||||
asan_load, asan_panic, asan_store, asan_swap, asan_sym,
|
||||
symbols::{AtomicGuestAddr, Function, FunctionPointer},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
struct FunctionFgets;
|
||||
|
||||
impl Function for FunctionFgets {
|
||||
type Func = unsafe extern "C" fn(buf: *mut c_char, n: c_int, stream: *mut FILE) -> *mut c_char;
|
||||
const NAME: &'static CStr = c"fgets";
|
||||
}
|
||||
|
||||
static FGETS_ADDR: AtomicGuestAddr = AtomicGuestAddr::new();
|
||||
|
||||
/// # Safety
|
||||
/// See man pages
|
||||
#[cfg_attr(not(feature = "test"), unsafe(no_mangle))]
|
||||
#[cfg_attr(feature = "test", unsafe(export_name = "patch_fgets"))]
|
||||
pub unsafe extern "C" fn fgets(buf: *mut c_char, n: c_int, stream: *mut FILE) -> *mut c_char {
|
||||
unsafe {
|
||||
trace!("fgets - buf: {:p}, n: {:#x}, stream: {:p}", buf, n, stream);
|
||||
|
||||
if buf.is_null() && n != 0 {
|
||||
asan_panic(c"fgets - buf is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
if stream.is_null() {
|
||||
asan_panic(c"fgets - stream is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
asan_store(buf as *const c_void, n as usize);
|
||||
asan_load(stream as *const c_void, size_of::<FILE>());
|
||||
let addr = FGETS_ADDR
|
||||
.get_or_insert_with(|| asan_sym(FunctionFgets::NAME.as_ptr() as *const c_char));
|
||||
let fn_fgets = FunctionFgets::as_ptr(addr).unwrap();
|
||||
asan_swap(false);
|
||||
let ret = fn_fgets(buf, n, stream);
|
||||
asan_swap(true);
|
||||
ret
|
||||
}
|
||||
}
|
15
libafl_qemu/librasan/asan/src/hooks/free.rs
Normal file
15
libafl_qemu/librasan/asan/src/hooks/free.rs
Normal file
@ -0,0 +1,15 @@
|
||||
use core::ffi::c_void;
|
||||
|
||||
use log::trace;
|
||||
|
||||
use crate::asan_dealloc;
|
||||
|
||||
/// # Safety
|
||||
/// See man pages
|
||||
#[unsafe(export_name = "patch_free")]
|
||||
pub unsafe extern "C" fn free(p: *mut c_void) {
|
||||
unsafe {
|
||||
trace!("free - p: {:p}", p);
|
||||
asan_dealloc(p);
|
||||
}
|
||||
}
|
19
libafl_qemu/librasan/asan/src/hooks/malloc.rs
Normal file
19
libafl_qemu/librasan/asan/src/hooks/malloc.rs
Normal file
@ -0,0 +1,19 @@
|
||||
use core::{ffi::c_void, ptr::null_mut};
|
||||
|
||||
use log::trace;
|
||||
|
||||
use crate::{asan_alloc, size_t};
|
||||
|
||||
/// # Safety
|
||||
/// See man pages
|
||||
#[unsafe(export_name = "patch_malloc")]
|
||||
pub unsafe extern "C" fn malloc(size: size_t) -> *mut c_void {
|
||||
unsafe {
|
||||
trace!("malloc - size: {:#x}", size);
|
||||
if size == 0 {
|
||||
null_mut()
|
||||
} else {
|
||||
asan_alloc(size, 0)
|
||||
}
|
||||
}
|
||||
}
|
15
libafl_qemu/librasan/asan/src/hooks/malloc_usable_size.rs
Normal file
15
libafl_qemu/librasan/asan/src/hooks/malloc_usable_size.rs
Normal file
@ -0,0 +1,15 @@
|
||||
use core::ffi::c_void;
|
||||
|
||||
use log::trace;
|
||||
|
||||
use crate::{asan_get_size, size_t};
|
||||
|
||||
/// # Safety
|
||||
/// See man pages
|
||||
#[unsafe(export_name = "patch_malloc_usable_size")]
|
||||
pub unsafe extern "C" fn malloc_usable_size(ptr: *mut c_void) -> size_t {
|
||||
unsafe {
|
||||
trace!("malloc_usable_size - ptr: {:p}", ptr);
|
||||
if ptr.is_null() { 0 } else { asan_get_size(ptr) }
|
||||
}
|
||||
}
|
33
libafl_qemu/librasan/asan/src/hooks/memalign.rs
Normal file
33
libafl_qemu/librasan/asan/src/hooks/memalign.rs
Normal file
@ -0,0 +1,33 @@
|
||||
use core::{
|
||||
ffi::{c_char, c_void},
|
||||
mem::size_of,
|
||||
ptr::null_mut,
|
||||
};
|
||||
|
||||
use log::trace;
|
||||
|
||||
use crate::{GuestAddr, asan_alloc, asan_panic, size_t};
|
||||
|
||||
/// # Safety
|
||||
/// See man pages
|
||||
#[unsafe(export_name = "patch_memalign")]
|
||||
pub unsafe extern "C" fn memalign(align: size_t, size: size_t) -> *mut c_void {
|
||||
unsafe {
|
||||
trace!("memalign - align: {:#x}, size: {:#x}", align, size);
|
||||
fn is_power_of_two(n: size_t) -> bool {
|
||||
n != 0 && (n & (n - 1)) == 0
|
||||
}
|
||||
|
||||
if align % size_of::<GuestAddr>() != 0 {
|
||||
asan_panic(
|
||||
c"memalign - align is not a multiple of pointer size".as_ptr() as *const c_char,
|
||||
);
|
||||
} else if !is_power_of_two(align) {
|
||||
asan_panic(c"memalign - align is not a power of two".as_ptr() as *const c_char);
|
||||
} else if size == 0 {
|
||||
null_mut()
|
||||
} else {
|
||||
asan_alloc(size, align)
|
||||
}
|
||||
}
|
||||
}
|
34
libafl_qemu/librasan/asan/src/hooks/memchr.rs
Normal file
34
libafl_qemu/librasan/asan/src/hooks/memchr.rs
Normal file
@ -0,0 +1,34 @@
|
||||
use core::{
|
||||
ffi::{c_char, c_int, c_void},
|
||||
ptr::null_mut,
|
||||
slice::from_raw_parts,
|
||||
};
|
||||
|
||||
use log::trace;
|
||||
|
||||
use crate::{asan_load, asan_panic, size_t};
|
||||
|
||||
/// # Safety
|
||||
/// See man pages
|
||||
#[unsafe(export_name = "patch_memchr")]
|
||||
pub unsafe extern "C" fn memchr(cx: *const c_void, c: c_int, n: size_t) -> *mut c_void {
|
||||
unsafe {
|
||||
trace!("memchr - cx: {:p}, c: {:#x}, n: {:#x}", cx, c, n);
|
||||
|
||||
if n == 0 {
|
||||
return null_mut();
|
||||
}
|
||||
|
||||
if cx.is_null() && n != 0 {
|
||||
asan_panic(c"memchr - cx is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
asan_load(cx, n);
|
||||
let slice = from_raw_parts(cx as *const u8, n);
|
||||
let pos = slice.iter().position(|&x| x as c_int == c);
|
||||
match pos {
|
||||
Some(pos) => cx.add(pos) as *mut c_void,
|
||||
None => null_mut(),
|
||||
}
|
||||
}
|
||||
}
|
46
libafl_qemu/librasan/asan/src/hooks/memcmp.rs
Normal file
46
libafl_qemu/librasan/asan/src/hooks/memcmp.rs
Normal file
@ -0,0 +1,46 @@
|
||||
use core::{
|
||||
cmp::Ordering,
|
||||
ffi::{c_char, c_int, c_void},
|
||||
slice::from_raw_parts,
|
||||
};
|
||||
|
||||
use log::trace;
|
||||
|
||||
use crate::{asan_load, asan_panic, size_t};
|
||||
|
||||
/// # Safety
|
||||
/// See man pages
|
||||
#[unsafe(export_name = "patch_memcmp")]
|
||||
pub unsafe extern "C" fn memcmp(cx: *const c_void, ct: *const c_void, n: size_t) -> c_int {
|
||||
unsafe {
|
||||
trace!("memcmp - cx: {:p}, ct: {:p}, n: {:#x}", cx, ct, n);
|
||||
|
||||
if n == 0 {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if cx.is_null() {
|
||||
asan_panic(c"memcmp - cx is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
if ct.is_null() {
|
||||
asan_panic(c"memcmp - ct is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
asan_load(cx, n);
|
||||
asan_load(ct, n);
|
||||
|
||||
let slice1 = from_raw_parts(cx as *const u8, n);
|
||||
let slice2 = from_raw_parts(ct as *const u8, n);
|
||||
|
||||
for i in 0..n {
|
||||
match slice1[i].cmp(&slice2[i]) {
|
||||
Ordering::Equal => (),
|
||||
Ordering::Less => return -1,
|
||||
Ordering::Greater => return 1,
|
||||
}
|
||||
}
|
||||
|
||||
0
|
||||
}
|
||||
}
|
40
libafl_qemu/librasan/asan/src/hooks/memcpy.rs
Normal file
40
libafl_qemu/librasan/asan/src/hooks/memcpy.rs
Normal file
@ -0,0 +1,40 @@
|
||||
use core::{
|
||||
ffi::{c_char, c_void},
|
||||
ptr::copy_nonoverlapping,
|
||||
};
|
||||
|
||||
use log::trace;
|
||||
|
||||
use crate::{asan_load, asan_panic, asan_store, size_t};
|
||||
|
||||
/// # Safety
|
||||
/// See man pages
|
||||
#[unsafe(export_name = "patch_memcpy")]
|
||||
pub unsafe extern "C" fn memcpy(dest: *mut c_void, src: *const c_void, n: size_t) -> *mut c_void {
|
||||
unsafe {
|
||||
trace!("memcpy - dest: {:p}, src: {:p}, n: {:#x}", dest, src, n);
|
||||
|
||||
if n == 0 {
|
||||
return dest;
|
||||
}
|
||||
|
||||
if dest.is_null() {
|
||||
asan_panic(c"memcpy - dest is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
if src.is_null() {
|
||||
asan_panic(c"memcpy - src is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
let src_end = src.add(n);
|
||||
let dest_end = dest.add(n) as *const c_void;
|
||||
if src_end > dest && dest_end > src {
|
||||
asan_panic(c"memcpy - overlap".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
asan_load(src, n);
|
||||
asan_store(dest, n);
|
||||
copy_nonoverlapping(src, dest, n);
|
||||
dest
|
||||
}
|
||||
}
|
56
libafl_qemu/librasan/asan/src/hooks/memmem.rs
Normal file
56
libafl_qemu/librasan/asan/src/hooks/memmem.rs
Normal file
@ -0,0 +1,56 @@
|
||||
use core::{
|
||||
ffi::{c_char, c_void},
|
||||
ptr::null_mut,
|
||||
slice::from_raw_parts,
|
||||
};
|
||||
|
||||
use log::trace;
|
||||
|
||||
use crate::{asan_load, asan_panic, size_t};
|
||||
|
||||
/// # Safety
|
||||
/// See man pages
|
||||
#[unsafe(export_name = "patch_memmem")]
|
||||
pub unsafe extern "C" fn memmem(
|
||||
haystack: *const c_void,
|
||||
haystacklen: size_t,
|
||||
needle: *const c_void,
|
||||
needlelen: size_t,
|
||||
) -> *mut c_void {
|
||||
unsafe {
|
||||
trace!(
|
||||
"memmem - haystack: {:p}, haystacklen: {:#x}, needle: {:p}, needlelen: {:#x}",
|
||||
haystack, haystacklen, needle, needlelen
|
||||
);
|
||||
|
||||
if needlelen == 0 {
|
||||
return haystack as *mut c_void;
|
||||
}
|
||||
|
||||
if needlelen > haystacklen {
|
||||
return null_mut();
|
||||
}
|
||||
|
||||
if haystack.is_null() {
|
||||
asan_panic(c"memmem - haystack is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
if needle.is_null() {
|
||||
asan_panic(c"memmem - needle is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
asan_load(haystack, haystacklen);
|
||||
asan_load(needle, needlelen);
|
||||
|
||||
let haystack_buffer = from_raw_parts(haystack as *const u8, haystacklen);
|
||||
let needle_buffer = from_raw_parts(needle as *const u8, needlelen);
|
||||
|
||||
for i in 0..(haystacklen - needlelen + 1) {
|
||||
if &haystack_buffer[i..i + needlelen] == needle_buffer {
|
||||
return haystack.add(i) as *mut c_void;
|
||||
}
|
||||
}
|
||||
|
||||
null_mut()
|
||||
}
|
||||
}
|
34
libafl_qemu/librasan/asan/src/hooks/memmove.rs
Normal file
34
libafl_qemu/librasan/asan/src/hooks/memmove.rs
Normal file
@ -0,0 +1,34 @@
|
||||
use core::{
|
||||
ffi::{c_char, c_void},
|
||||
ptr::copy,
|
||||
};
|
||||
|
||||
use log::trace;
|
||||
|
||||
use crate::{asan_load, asan_panic, asan_store, size_t};
|
||||
|
||||
/// # Safety
|
||||
/// See man pages
|
||||
#[unsafe(export_name = "patch_memmove")]
|
||||
pub unsafe extern "C" fn memmove(dest: *mut c_void, src: *const c_void, n: size_t) -> *mut c_void {
|
||||
unsafe {
|
||||
trace!("memmove - dest: {:p}, src: {:p}, n: {:#x}", dest, src, n);
|
||||
|
||||
if n == 0 {
|
||||
return dest;
|
||||
}
|
||||
|
||||
if dest.is_null() {
|
||||
asan_panic(c"memmove - dest is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
if src.is_null() {
|
||||
asan_panic(c"memmove - src is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
asan_load(src, n);
|
||||
asan_store(dest, n);
|
||||
copy(src, dest, n);
|
||||
dest
|
||||
}
|
||||
}
|
40
libafl_qemu/librasan/asan/src/hooks/mempcpy.rs
Normal file
40
libafl_qemu/librasan/asan/src/hooks/mempcpy.rs
Normal file
@ -0,0 +1,40 @@
|
||||
use core::{
|
||||
ffi::{c_char, c_void},
|
||||
ptr::copy_nonoverlapping,
|
||||
};
|
||||
|
||||
use log::trace;
|
||||
|
||||
use crate::{asan_load, asan_panic, asan_store, size_t};
|
||||
|
||||
/// # Safety
|
||||
/// See man pages
|
||||
#[unsafe(export_name = "patch_mempcpy")]
|
||||
pub unsafe extern "C" fn mempcpy(dest: *mut c_void, src: *const c_void, n: size_t) -> *mut c_void {
|
||||
unsafe {
|
||||
trace!("mempcpy - dest: {:p}, src: {:p}, n: {:#x}", dest, src, n);
|
||||
|
||||
if n == 0 {
|
||||
return dest;
|
||||
}
|
||||
|
||||
if dest.is_null() {
|
||||
asan_panic(c"mempcpy - dest is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
if src.is_null() {
|
||||
asan_panic(c"mempcpy - src is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
let src_end = src.add(n);
|
||||
let dest_end = dest.add(n) as *const c_void;
|
||||
if src_end > dest && dest_end > src {
|
||||
asan_panic(c"memcpy - overlap".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
asan_load(src, n);
|
||||
asan_store(dest, n);
|
||||
copy_nonoverlapping(src, dest, n);
|
||||
dest.add(n)
|
||||
}
|
||||
}
|
34
libafl_qemu/librasan/asan/src/hooks/memrchr.rs
Normal file
34
libafl_qemu/librasan/asan/src/hooks/memrchr.rs
Normal file
@ -0,0 +1,34 @@
|
||||
use core::{
|
||||
ffi::{c_char, c_int, c_void},
|
||||
ptr::null_mut,
|
||||
slice::from_raw_parts,
|
||||
};
|
||||
|
||||
use log::trace;
|
||||
|
||||
use crate::{asan_load, asan_panic, size_t};
|
||||
|
||||
/// # Safety
|
||||
/// See man pages
|
||||
#[unsafe(export_name = "patch_memrchr")]
|
||||
pub unsafe extern "C" fn memrchr(cx: *const c_void, c: c_int, n: size_t) -> *mut c_void {
|
||||
unsafe {
|
||||
trace!("memrchr - cx: {:p}, c: {:#x}, n: {:#x}", cx, c, n);
|
||||
|
||||
if n == 0 {
|
||||
return null_mut();
|
||||
}
|
||||
|
||||
if cx.is_null() {
|
||||
asan_panic(c"memrchr - cx is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
asan_load(cx, n);
|
||||
let slice = from_raw_parts(cx as *const u8, n);
|
||||
let pos = slice.iter().rev().position(|&x| x as c_int == c);
|
||||
match pos {
|
||||
Some(pos) => cx.add(n - pos - 1) as *mut c_void,
|
||||
None => null_mut(),
|
||||
}
|
||||
}
|
||||
}
|
29
libafl_qemu/librasan/asan/src/hooks/memset.rs
Normal file
29
libafl_qemu/librasan/asan/src/hooks/memset.rs
Normal file
@ -0,0 +1,29 @@
|
||||
use core::{
|
||||
ffi::{c_char, c_int, c_void},
|
||||
ptr::write_bytes,
|
||||
};
|
||||
|
||||
use log::trace;
|
||||
|
||||
use crate::{asan_panic, asan_store, size_t};
|
||||
|
||||
/// # Safety
|
||||
/// See man pages
|
||||
#[unsafe(export_name = "patch_memset")]
|
||||
pub unsafe extern "C" fn memset(dest: *mut c_void, c: c_int, n: size_t) -> *mut c_void {
|
||||
unsafe {
|
||||
trace!("memset - dest: {:p}, c: {:#x}, n: {:#x}", dest, c, n);
|
||||
|
||||
if n == 0 {
|
||||
return dest;
|
||||
}
|
||||
|
||||
if dest.is_null() {
|
||||
asan_panic(c"memset - dest is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
asan_store(dest, n);
|
||||
write_bytes(dest, c as u8, n);
|
||||
dest
|
||||
}
|
||||
}
|
58
libafl_qemu/librasan/asan/src/hooks/mmap/libc.rs
Normal file
58
libafl_qemu/librasan/asan/src/hooks/mmap/libc.rs
Normal file
@ -0,0 +1,58 @@
|
||||
use core::ffi::{CStr, c_char};
|
||||
|
||||
use libc::{c_int, c_void};
|
||||
use log::trace;
|
||||
|
||||
use crate::{
|
||||
asan_swap, asan_sym, asan_track, asan_unpoison, off_t, size_t,
|
||||
symbols::{AtomicGuestAddr, Function, FunctionPointer},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
struct FunctionMmap;
|
||||
|
||||
impl Function for FunctionMmap {
|
||||
type Func = unsafe extern "C" fn(
|
||||
addr: *mut c_void,
|
||||
len: size_t,
|
||||
prot: c_int,
|
||||
flags: c_int,
|
||||
fd: c_int,
|
||||
offset: off_t,
|
||||
) -> *mut c_void;
|
||||
const NAME: &'static CStr = c"mmap";
|
||||
}
|
||||
|
||||
static MMAP_ADDR: AtomicGuestAddr = AtomicGuestAddr::new();
|
||||
|
||||
/// # Safety
|
||||
/// See man pages
|
||||
#[unsafe(export_name = "patch_mmap")]
|
||||
pub unsafe extern "C" fn mmap(
|
||||
addr: *mut c_void,
|
||||
len: size_t,
|
||||
prot: c_int,
|
||||
flags: c_int,
|
||||
fd: c_int,
|
||||
offset: off_t,
|
||||
) -> *mut c_void {
|
||||
unsafe {
|
||||
trace!(
|
||||
"mmap - addr: {:p}, len: {:#x}, prot: {:#x}, flags: {:#x}, fd: {:#x}, offset: {:#x}",
|
||||
addr, len, prot, flags, fd, offset
|
||||
);
|
||||
let mmap_addr =
|
||||
MMAP_ADDR.get_or_insert_with(|| asan_sym(FunctionMmap::NAME.as_ptr() as *const c_char));
|
||||
asan_swap(false);
|
||||
let fn_mmap = FunctionMmap::as_ptr(mmap_addr).unwrap();
|
||||
asan_swap(true);
|
||||
let map = fn_mmap(addr, len, prot, flags, fd, offset);
|
||||
if map == libc::MAP_FAILED {
|
||||
return libc::MAP_FAILED;
|
||||
}
|
||||
|
||||
asan_unpoison(map, len);
|
||||
asan_track(map, len);
|
||||
map
|
||||
}
|
||||
}
|
38
libafl_qemu/librasan/asan/src/hooks/mmap/linux.rs
Normal file
38
libafl_qemu/librasan/asan/src/hooks/mmap/linux.rs
Normal file
@ -0,0 +1,38 @@
|
||||
use core::ffi::{c_int, c_void};
|
||||
|
||||
use log::trace;
|
||||
use rustix::{
|
||||
fd::BorrowedFd,
|
||||
mm::{MapFlags, ProtFlags, mmap as rmmap},
|
||||
};
|
||||
|
||||
use crate::{GuestAddr, asan_track, asan_unpoison, off_t, size_t};
|
||||
|
||||
/// # Safety
|
||||
/// See man pages
|
||||
#[unsafe(export_name = "patch_mmap")]
|
||||
pub unsafe extern "C" fn mmap(
|
||||
addr: *mut c_void,
|
||||
len: size_t,
|
||||
prot: c_int,
|
||||
flags: c_int,
|
||||
fd: c_int,
|
||||
offset: off_t,
|
||||
) -> *mut c_void {
|
||||
unsafe {
|
||||
trace!(
|
||||
"mmap - addr: {:p}, len: {:#x}, prot: {:#x}, flags: {:#x}, fd: {:#x}, offset: {:#x}",
|
||||
addr, len, prot, flags, fd, offset
|
||||
);
|
||||
let file = BorrowedFd::borrow_raw(fd);
|
||||
let mmap_prot = ProtFlags::from_bits_retain(prot as u32);
|
||||
let mmap_flags = MapFlags::from_bits_retain(flags as u32);
|
||||
if let Ok(map) = rmmap(addr, len, mmap_prot, mmap_flags, file, offset as u64) {
|
||||
asan_unpoison(map, len);
|
||||
asan_track(map, len);
|
||||
map
|
||||
} else {
|
||||
GuestAddr::MAX as *mut c_void
|
||||
}
|
||||
}
|
||||
}
|
5
libafl_qemu/librasan/asan/src/hooks/mmap/mod.rs
Normal file
5
libafl_qemu/librasan/asan/src/hooks/mmap/mod.rs
Normal file
@ -0,0 +1,5 @@
|
||||
#[cfg(feature = "libc")]
|
||||
pub mod libc;
|
||||
|
||||
#[cfg(all(feature = "linux", not(feature = "libc")))]
|
||||
pub mod linux;
|
208
libafl_qemu/librasan/asan/src/hooks/mod.rs
Normal file
208
libafl_qemu/librasan/asan/src/hooks/mod.rs
Normal file
@ -0,0 +1,208 @@
|
||||
//! # hooks
|
||||
//!
|
||||
//! This module provides the implementation of various functions implemented by
|
||||
//! the standard C library which are used by applications. These functions are
|
||||
//! are modified to provide the additional memory safety checks provided by
|
||||
//! `asan`.
|
||||
pub mod aligned_alloc;
|
||||
pub mod atoi;
|
||||
pub mod atol;
|
||||
pub mod atoll;
|
||||
pub mod bcmp;
|
||||
pub mod bzero;
|
||||
pub mod calloc;
|
||||
pub mod explicit_bzero;
|
||||
pub mod free;
|
||||
pub mod malloc;
|
||||
pub mod malloc_usable_size;
|
||||
pub mod memalign;
|
||||
pub mod memchr;
|
||||
pub mod memcmp;
|
||||
pub mod memcpy;
|
||||
pub mod memmem;
|
||||
pub mod memmove;
|
||||
pub mod mempcpy;
|
||||
pub mod memrchr;
|
||||
pub mod memset;
|
||||
pub mod mmap;
|
||||
pub mod munmap;
|
||||
pub mod posix_memalign;
|
||||
pub mod pvalloc;
|
||||
pub mod read;
|
||||
pub mod realloc;
|
||||
pub mod reallocarray;
|
||||
pub mod stpcpy;
|
||||
pub mod strcasecmp;
|
||||
pub mod strcasestr;
|
||||
pub mod strcat;
|
||||
pub mod strchr;
|
||||
pub mod strcmp;
|
||||
pub mod strcpy;
|
||||
pub mod strdup;
|
||||
pub mod strlen;
|
||||
pub mod strncasecmp;
|
||||
pub mod strncmp;
|
||||
pub mod strncpy;
|
||||
pub mod strndup;
|
||||
pub mod strnlen;
|
||||
pub mod strrchr;
|
||||
pub mod strstr;
|
||||
pub mod valloc;
|
||||
pub mod wcscmp;
|
||||
pub mod wcscpy;
|
||||
pub mod wcslen;
|
||||
pub mod write;
|
||||
|
||||
#[cfg(feature = "libc")]
|
||||
pub mod fgets;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use core::ffi::{CStr, c_char, c_int, c_void};
|
||||
|
||||
use crate::{GuestAddr, hooks, size_t, wchar_t};
|
||||
|
||||
unsafe extern "C" {
|
||||
pub fn asprintf(strp: *mut *mut c_char, fmt: *const c_char, ...) -> c_int;
|
||||
pub fn vasprintf(strp: *mut *mut c_char, fmt: *const c_char, va: *const c_void) -> c_int;
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PatchedHook {
|
||||
pub name: &'static CStr,
|
||||
pub destination: GuestAddr,
|
||||
}
|
||||
|
||||
impl PatchedHook {
|
||||
const fn new<F: Copy>(name: &'static CStr, func: F) -> Self {
|
||||
let pf = (&func) as *const F as *const GuestAddr;
|
||||
let destination = unsafe { *pf };
|
||||
Self { name, destination }
|
||||
}
|
||||
|
||||
pub fn all() -> Vec<Self> {
|
||||
[
|
||||
PatchedHook::new::<unsafe extern "C" fn(size_t, size_t) -> *mut c_void>(
|
||||
c"aligned_alloc",
|
||||
hooks::aligned_alloc::aligned_alloc,
|
||||
),
|
||||
PatchedHook::new::<unsafe extern "C" fn(*mut *mut c_char, *const c_char, ...) -> c_int>(
|
||||
c"asprintf",
|
||||
hooks::asprintf,
|
||||
),
|
||||
PatchedHook::new::<
|
||||
unsafe extern "C" fn(*const c_void, *const c_void, n: size_t) -> c_int,
|
||||
>(c"bcmp", hooks::bcmp::bcmp),
|
||||
PatchedHook::new::<unsafe extern "C" fn(*mut c_void, size_t)>(
|
||||
c"bzero",
|
||||
hooks::bzero::bzero,
|
||||
),
|
||||
PatchedHook::new::<unsafe extern "C" fn(*mut c_void, size_t)>(
|
||||
c"explicit_bzero",
|
||||
hooks::explicit_bzero::explicit_bzero,
|
||||
),
|
||||
PatchedHook::new::<unsafe extern "C" fn(*const c_void, c_int, size_t) -> *mut c_void>(
|
||||
c"memchr",
|
||||
hooks::memchr::memchr,
|
||||
),
|
||||
PatchedHook::new::<unsafe extern "C" fn(*const c_void, *const c_void, size_t) -> c_int>(
|
||||
c"memcmp",
|
||||
hooks::memcmp::memcmp,
|
||||
),
|
||||
PatchedHook::new::<
|
||||
unsafe extern "C" fn(*mut c_void, *const c_void, size_t) -> *mut c_void,
|
||||
>(c"memcpy", hooks::memcpy::memcpy),
|
||||
PatchedHook::new::<
|
||||
unsafe extern "C" fn(*const c_void, size_t, *const c_void, size_t) -> *mut c_void,
|
||||
>(c"memmem", hooks::memmem::memmem),
|
||||
PatchedHook::new::<
|
||||
unsafe extern "C" fn(*mut c_void, *const c_void, size_t) -> *mut c_void,
|
||||
>(c"memmove", hooks::memmove::memmove),
|
||||
PatchedHook::new::<
|
||||
unsafe extern "C" fn(*mut c_void, *const c_void, size_t) -> *mut c_void,
|
||||
>(c"mempcpy", hooks::mempcpy::mempcpy),
|
||||
PatchedHook::new::<unsafe extern "C" fn(*const c_void, c_int, size_t) -> *mut c_void>(
|
||||
c"memrchr",
|
||||
hooks::memrchr::memrchr,
|
||||
),
|
||||
PatchedHook::new::<unsafe extern "C" fn(*mut c_char, *const c_char) -> *mut c_char>(
|
||||
c"stpcpy",
|
||||
hooks::stpcpy::stpcpy,
|
||||
),
|
||||
PatchedHook::new::<unsafe extern "C" fn(*const c_char, *const c_char) -> c_int>(
|
||||
c"strcasecmp",
|
||||
hooks::strcasecmp::strcasecmp,
|
||||
),
|
||||
PatchedHook::new::<unsafe extern "C" fn(*const c_char, *const c_char) -> *mut c_char>(
|
||||
c"strcasestr",
|
||||
hooks::strcasestr::strcasestr,
|
||||
),
|
||||
PatchedHook::new::<unsafe extern "C" fn(*mut c_char, *const c_char) -> *mut c_char>(
|
||||
c"strcat",
|
||||
hooks::strcat::strcat,
|
||||
),
|
||||
PatchedHook::new::<unsafe extern "C" fn(*const c_char, c_int) -> *mut c_char>(
|
||||
c"strchr",
|
||||
hooks::strchr::strchr,
|
||||
),
|
||||
PatchedHook::new::<unsafe extern "C" fn(*const c_char, *const c_char) -> c_int>(
|
||||
c"strcmp",
|
||||
hooks::strcmp::strcmp,
|
||||
),
|
||||
PatchedHook::new::<unsafe extern "C" fn(*mut c_char, *const c_char) -> *mut c_char>(
|
||||
c"strcpy",
|
||||
hooks::strcpy::strcpy,
|
||||
),
|
||||
PatchedHook::new::<unsafe extern "C" fn(*const c_char) -> *mut c_char>(
|
||||
c"strdup",
|
||||
hooks::strdup::strdup,
|
||||
),
|
||||
PatchedHook::new::<unsafe extern "C" fn(*const c_char) -> size_t>(
|
||||
c"strlen",
|
||||
hooks::strlen::strlen,
|
||||
),
|
||||
PatchedHook::new::<unsafe extern "C" fn(*const c_char, *const c_char, size_t) -> c_int>(
|
||||
c"strncasecmp",
|
||||
hooks::strncasecmp::strncasecmp,
|
||||
),
|
||||
PatchedHook::new::<unsafe extern "C" fn(*const c_char, *const c_char, size_t) -> c_int>(
|
||||
c"strncmp",
|
||||
hooks::strncmp::strncmp,
|
||||
),
|
||||
PatchedHook::new::<
|
||||
unsafe extern "C" fn(*mut c_char, *const c_char, size_t) -> *mut c_char,
|
||||
>(c"strncpy", hooks::strncpy::strncpy),
|
||||
PatchedHook::new::<unsafe extern "C" fn(*const c_char, size_t) -> *mut c_char>(
|
||||
c"strndup",
|
||||
hooks::strndup::strndup,
|
||||
),
|
||||
PatchedHook::new::<unsafe extern "C" fn(*const c_char, size_t) -> size_t>(
|
||||
c"strnlen",
|
||||
hooks::strnlen::strnlen,
|
||||
),
|
||||
PatchedHook::new::<unsafe extern "C" fn(*const c_char, c_int) -> *mut c_char>(
|
||||
c"strrchr",
|
||||
hooks::strrchr::strrchr,
|
||||
),
|
||||
PatchedHook::new::<unsafe extern "C" fn(*const c_char, *const c_char) -> *mut c_char>(
|
||||
c"strstr",
|
||||
hooks::strstr::strstr,
|
||||
),
|
||||
PatchedHook::new::<
|
||||
unsafe extern "C" fn(*mut *mut c_char, *const c_char, *const c_void) -> c_int,
|
||||
>(c"vasprintf", hooks::vasprintf),
|
||||
PatchedHook::new::<unsafe extern "C" fn(*const wchar_t, *const wchar_t) -> c_int>(
|
||||
c"wcscmp",
|
||||
hooks::wcscmp::wcscmp,
|
||||
),
|
||||
PatchedHook::new::<unsafe extern "C" fn(*mut wchar_t, *const wchar_t) -> *mut wchar_t>(
|
||||
c"wcscpy",
|
||||
hooks::wcscpy::wcscpy,
|
||||
),
|
||||
PatchedHook::new::<unsafe extern "C" fn(*const wchar_t) -> size_t>(
|
||||
c"wcslen",
|
||||
hooks::wcslen::wcslen,
|
||||
),
|
||||
]
|
||||
.to_vec()
|
||||
}
|
||||
}
|
40
libafl_qemu/librasan/asan/src/hooks/munmap/libc.rs
Normal file
40
libafl_qemu/librasan/asan/src/hooks/munmap/libc.rs
Normal file
@ -0,0 +1,40 @@
|
||||
use core::ffi::{CStr, c_char};
|
||||
|
||||
use libc::{c_int, c_void};
|
||||
use log::trace;
|
||||
|
||||
use crate::{
|
||||
asan_swap, asan_sym, asan_untrack, size_t,
|
||||
symbols::{AtomicGuestAddr, Function, FunctionPointer},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
struct FunctionMunmap;
|
||||
|
||||
impl Function for FunctionMunmap {
|
||||
type Func = unsafe extern "C" fn(addr: *mut c_void, len: size_t) -> c_int;
|
||||
const NAME: &'static CStr = c"munmap";
|
||||
}
|
||||
|
||||
static MUNMAP_ADDR: AtomicGuestAddr = AtomicGuestAddr::new();
|
||||
|
||||
/// # Safety
|
||||
/// See man pages
|
||||
#[unsafe(export_name = "patch_munmap")]
|
||||
pub unsafe extern "C" fn munmap(addr: *mut c_void, len: size_t) -> c_int {
|
||||
unsafe {
|
||||
trace!("munmap - addr: {:p}, len: {:#x}", addr, len);
|
||||
let mmap_addr = MUNMAP_ADDR
|
||||
.get_or_insert_with(|| asan_sym(FunctionMunmap::NAME.as_ptr() as *const c_char));
|
||||
asan_swap(false);
|
||||
let fn_munmap = FunctionMunmap::as_ptr(mmap_addr).unwrap();
|
||||
asan_swap(true);
|
||||
let ret = fn_munmap(addr, len);
|
||||
if ret < 0 {
|
||||
return ret;
|
||||
}
|
||||
|
||||
asan_untrack(addr);
|
||||
ret
|
||||
}
|
||||
}
|
22
libafl_qemu/librasan/asan/src/hooks/munmap/linux.rs
Normal file
22
libafl_qemu/librasan/asan/src/hooks/munmap/linux.rs
Normal file
@ -0,0 +1,22 @@
|
||||
use core::ffi::{c_int, c_void};
|
||||
|
||||
use log::trace;
|
||||
use rustix::mm::munmap as rmunmap;
|
||||
|
||||
use crate::{asan_untrack, hooks::size_t};
|
||||
|
||||
/// # Safety
|
||||
/// See man pages
|
||||
#[unsafe(export_name = "patch_munmap")]
|
||||
pub unsafe extern "C" fn munmap(addr: *mut c_void, len: size_t) -> c_int {
|
||||
unsafe {
|
||||
trace!("munmap - addr: {:p}, len: {:#x}", addr, len);
|
||||
|
||||
if rmunmap(addr, len).is_ok() {
|
||||
asan_untrack(addr);
|
||||
0
|
||||
} else {
|
||||
-1
|
||||
}
|
||||
}
|
||||
}
|
5
libafl_qemu/librasan/asan/src/hooks/munmap/mod.rs
Normal file
5
libafl_qemu/librasan/asan/src/hooks/munmap/mod.rs
Normal file
@ -0,0 +1,5 @@
|
||||
#[cfg(feature = "libc")]
|
||||
pub mod libc;
|
||||
|
||||
#[cfg(all(feature = "linux", not(feature = "libc")))]
|
||||
pub mod linux;
|
49
libafl_qemu/librasan/asan/src/hooks/posix_memalign.rs
Normal file
49
libafl_qemu/librasan/asan/src/hooks/posix_memalign.rs
Normal file
@ -0,0 +1,49 @@
|
||||
use core::{
|
||||
ffi::{c_char, c_int, c_void},
|
||||
mem::size_of,
|
||||
ptr::null_mut,
|
||||
};
|
||||
|
||||
use log::trace;
|
||||
|
||||
use crate::{GuestAddr, asan_alloc, asan_panic, size_t};
|
||||
|
||||
/// # Safety
|
||||
/// See man pages
|
||||
#[unsafe(export_name = "patch_posix_memalign")]
|
||||
pub unsafe extern "C" fn posix_memalign(
|
||||
memptr: *mut *mut c_void,
|
||||
align: size_t,
|
||||
size: size_t,
|
||||
) -> c_int {
|
||||
unsafe {
|
||||
trace!(
|
||||
"posix_memalign - memptr: {:p}, align: {:#x}, size: {:#x}",
|
||||
memptr, align, size
|
||||
);
|
||||
|
||||
if memptr.is_null() {
|
||||
asan_panic(c"posix_memalign - memptr is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
fn is_power_of_two(n: size_t) -> bool {
|
||||
n != 0 && (n & (n - 1)) == 0
|
||||
}
|
||||
|
||||
if align % size_of::<GuestAddr>() != 0 {
|
||||
asan_panic(
|
||||
c"posix_memalign - align is not a multiple of pointer size".as_ptr()
|
||||
as *const c_char,
|
||||
);
|
||||
} else if !is_power_of_two(align) {
|
||||
asan_panic(c"posix_memalign - align is not a power of two".as_ptr() as *const c_char);
|
||||
} else if size == 0 {
|
||||
*memptr = null_mut();
|
||||
0
|
||||
} else {
|
||||
let p = asan_alloc(size, align);
|
||||
*memptr = p;
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
22
libafl_qemu/librasan/asan/src/hooks/pvalloc.rs
Normal file
22
libafl_qemu/librasan/asan/src/hooks/pvalloc.rs
Normal file
@ -0,0 +1,22 @@
|
||||
use core::ffi::c_void;
|
||||
|
||||
use log::trace;
|
||||
|
||||
use crate::{asan_alloc, asan_page_size, size_t};
|
||||
|
||||
/// # Safety
|
||||
/// See man pages
|
||||
#[unsafe(export_name = "patch_pvalloc")]
|
||||
pub unsafe extern "C" fn pvalloc(size: size_t) -> *mut c_void {
|
||||
unsafe {
|
||||
trace!("pvalloc - size: {:#x}", size);
|
||||
let page_size = asan_page_size();
|
||||
let aligned_size = if size == 0 {
|
||||
page_size
|
||||
} else {
|
||||
(size + page_size - 1) & !(page_size - 1)
|
||||
};
|
||||
assert_ne!(aligned_size, 0);
|
||||
asan_alloc(aligned_size, page_size)
|
||||
}
|
||||
}
|
41
libafl_qemu/librasan/asan/src/hooks/read/libc.rs
Normal file
41
libafl_qemu/librasan/asan/src/hooks/read/libc.rs
Normal file
@ -0,0 +1,41 @@
|
||||
use core::ffi::{CStr, c_char, c_long};
|
||||
|
||||
use libc::{SYS_read, c_int, c_void};
|
||||
use log::trace;
|
||||
|
||||
use crate::{
|
||||
asan_panic, asan_store, asan_swap, asan_sym, size_t, ssize_t,
|
||||
symbols::{AtomicGuestAddr, Function, FunctionPointer},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
struct FunctionSyscall;
|
||||
|
||||
impl Function for FunctionSyscall {
|
||||
type Func = unsafe extern "C" fn(num: c_long, ...) -> c_long;
|
||||
const NAME: &'static CStr = c"syscall";
|
||||
}
|
||||
|
||||
static SYSCALL_ADDR: AtomicGuestAddr = AtomicGuestAddr::new();
|
||||
|
||||
/// # Safety
|
||||
/// See man pages
|
||||
#[unsafe(export_name = "patch_read")]
|
||||
pub unsafe extern "C" fn read(fd: c_int, buf: *mut c_void, count: size_t) -> ssize_t {
|
||||
unsafe {
|
||||
trace!("read - fd: {:#x}, buf: {:p}, count: {:#x}", fd, buf, count);
|
||||
|
||||
if buf.is_null() && count != 0 {
|
||||
asan_panic(c"read - buf is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
asan_store(buf, count);
|
||||
let addr = SYSCALL_ADDR
|
||||
.get_or_insert_with(|| asan_sym(FunctionSyscall::NAME.as_ptr() as *const c_char));
|
||||
let fn_syscall = FunctionSyscall::as_ptr(addr).unwrap();
|
||||
asan_swap(false);
|
||||
let ret = fn_syscall(SYS_read, fd, buf, count);
|
||||
asan_swap(true);
|
||||
ret as ssize_t
|
||||
}
|
||||
}
|
31
libafl_qemu/librasan/asan/src/hooks/read/linux.rs
Normal file
31
libafl_qemu/librasan/asan/src/hooks/read/linux.rs
Normal file
@ -0,0 +1,31 @@
|
||||
use core::{
|
||||
ffi::{c_char, c_int, c_void},
|
||||
slice::from_raw_parts_mut,
|
||||
};
|
||||
|
||||
use log::trace;
|
||||
use rustix::{fd::BorrowedFd, io};
|
||||
|
||||
use crate::{asan_panic, asan_store, size_t, ssize_t};
|
||||
|
||||
/// # Safety
|
||||
/// See man pages
|
||||
#[unsafe(export_name = "patch_read")]
|
||||
pub unsafe extern "C" fn read(fd: c_int, buf: *mut c_void, count: size_t) -> ssize_t {
|
||||
unsafe {
|
||||
trace!("read - fd: {:#x}, buf: {:p}, count: {:#x}", fd, buf, count);
|
||||
|
||||
if buf.is_null() && count != 0 {
|
||||
asan_panic(c"read - buf is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
asan_store(buf, count);
|
||||
let file = BorrowedFd::borrow_raw(fd);
|
||||
let data = from_raw_parts_mut(buf as *mut u8, count as usize);
|
||||
if let Ok(ret) = io::read(file, data) {
|
||||
return ret as ssize_t;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
5
libafl_qemu/librasan/asan/src/hooks/read/mod.rs
Normal file
5
libafl_qemu/librasan/asan/src/hooks/read/mod.rs
Normal file
@ -0,0 +1,5 @@
|
||||
#[cfg(feature = "libc")]
|
||||
pub mod libc;
|
||||
|
||||
#[cfg(all(feature = "linux", not(feature = "libc")))]
|
||||
pub mod linux;
|
33
libafl_qemu/librasan/asan/src/hooks/realloc.rs
Normal file
33
libafl_qemu/librasan/asan/src/hooks/realloc.rs
Normal file
@ -0,0 +1,33 @@
|
||||
use core::{
|
||||
ffi::c_void,
|
||||
ptr::{copy_nonoverlapping, null_mut},
|
||||
};
|
||||
|
||||
use log::trace;
|
||||
|
||||
use crate::{asan_alloc, asan_dealloc, asan_get_size, asan_load, size_t};
|
||||
|
||||
/// # Safety
|
||||
/// See man pages
|
||||
#[unsafe(export_name = "patch_realloc")]
|
||||
pub unsafe extern "C" fn realloc(p: *mut c_void, size: size_t) -> *mut c_void {
|
||||
unsafe {
|
||||
trace!("realloc - p: {:p}, size: {:#x}", p, size);
|
||||
if p.is_null() && size == 0 {
|
||||
null_mut()
|
||||
} else if p.is_null() {
|
||||
asan_alloc(size, 0)
|
||||
} else if size == 0 {
|
||||
asan_dealloc(p);
|
||||
null_mut()
|
||||
} else {
|
||||
let old_size = asan_get_size(p);
|
||||
asan_load(p, old_size);
|
||||
let q = asan_alloc(size, 0);
|
||||
let min = old_size.min(size);
|
||||
copy_nonoverlapping(p as *const u8, q as *mut u8, min);
|
||||
asan_dealloc(p);
|
||||
q
|
||||
}
|
||||
}
|
||||
}
|
45
libafl_qemu/librasan/asan/src/hooks/reallocarray.rs
Normal file
45
libafl_qemu/librasan/asan/src/hooks/reallocarray.rs
Normal file
@ -0,0 +1,45 @@
|
||||
use core::{
|
||||
ffi::{c_char, c_void},
|
||||
ptr::{copy_nonoverlapping, null_mut},
|
||||
};
|
||||
|
||||
use log::trace;
|
||||
|
||||
use crate::{asan_alloc, asan_dealloc, asan_get_size, asan_load, asan_panic, size_t};
|
||||
|
||||
/// # Safety
|
||||
/// See man pages
|
||||
#[unsafe(export_name = "patch_reallocarray")]
|
||||
pub unsafe extern "C" fn reallocarray(
|
||||
ptr: *mut c_void,
|
||||
nmemb: size_t,
|
||||
size: size_t,
|
||||
) -> *mut c_void {
|
||||
unsafe {
|
||||
trace!(
|
||||
"reallocarray - ptr: {:p}, nmemb: {:#x}, size: {:#x}",
|
||||
ptr, nmemb, size
|
||||
);
|
||||
match nmemb.checked_mul(size) {
|
||||
Some(size) => {
|
||||
if ptr.is_null() && size == 0 {
|
||||
null_mut()
|
||||
} else if ptr.is_null() {
|
||||
asan_alloc(size, 0)
|
||||
} else if size == 0 {
|
||||
asan_dealloc(ptr);
|
||||
null_mut()
|
||||
} else {
|
||||
let old_size = asan_get_size(ptr);
|
||||
asan_load(ptr, old_size);
|
||||
let q = asan_alloc(size, 0);
|
||||
let min = old_size.min(size);
|
||||
copy_nonoverlapping(ptr as *const u8, q as *mut u8, min);
|
||||
asan_dealloc(ptr);
|
||||
q
|
||||
}
|
||||
}
|
||||
None => asan_panic(c"reallocarray - size would overflow".as_ptr() as *const c_char),
|
||||
}
|
||||
}
|
||||
}
|
34
libafl_qemu/librasan/asan/src/hooks/stpcpy.rs
Normal file
34
libafl_qemu/librasan/asan/src/hooks/stpcpy.rs
Normal file
@ -0,0 +1,34 @@
|
||||
use core::{
|
||||
ffi::{c_char, c_void},
|
||||
ptr::copy,
|
||||
};
|
||||
|
||||
use log::trace;
|
||||
|
||||
use crate::{asan_load, asan_panic, asan_store};
|
||||
|
||||
/// # Safety
|
||||
/// See man pages
|
||||
#[unsafe(export_name = "patch_stpcpy")]
|
||||
pub unsafe extern "C" fn stpcpy(dst: *mut c_char, src: *const c_char) -> *mut c_char {
|
||||
unsafe {
|
||||
trace!("stpcpy - dst: {:p}, src: {:p}", dst, src);
|
||||
|
||||
if dst.is_null() {
|
||||
asan_panic(c"stpcpy - dst is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
if src.is_null() {
|
||||
asan_panic(c"stpcpy - src is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
let mut len = 0;
|
||||
while *src.add(len) != 0 {
|
||||
len += 1;
|
||||
}
|
||||
asan_load(src as *const c_void, len + 1);
|
||||
asan_store(dst as *const c_void, len + 1);
|
||||
copy(src, dst, len + 1);
|
||||
dst.add(len)
|
||||
}
|
||||
}
|
70
libafl_qemu/librasan/asan/src/hooks/strcasecmp.rs
Normal file
70
libafl_qemu/librasan/asan/src/hooks/strcasecmp.rs
Normal file
@ -0,0 +1,70 @@
|
||||
use core::{
|
||||
ffi::{c_char, c_int, c_void},
|
||||
slice::from_raw_parts,
|
||||
};
|
||||
|
||||
use log::trace;
|
||||
|
||||
use crate::{asan_load, asan_panic};
|
||||
|
||||
/// # Safety
|
||||
/// See man pages
|
||||
#[unsafe(export_name = "patch_strcasecmp")]
|
||||
pub unsafe extern "C" fn strcasecmp(s1: *const c_char, s2: *const c_char) -> c_int {
|
||||
unsafe {
|
||||
trace!("strcasecmp - s1: {:p}, s2: {:p}", s1, s2);
|
||||
|
||||
if s1.is_null() {
|
||||
asan_panic(c"strcasecmp - s1 is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
if s2.is_null() {
|
||||
asan_panic(c"strcasecmp - s2 is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
let mut s1_len = 0;
|
||||
while *s1.add(s1_len) != 0 {
|
||||
s1_len += 1;
|
||||
}
|
||||
let mut s2_len = 0;
|
||||
while *s2.add(s2_len) != 0 {
|
||||
s2_len += 1;
|
||||
}
|
||||
asan_load(s1 as *const c_void, s1_len + 1);
|
||||
asan_load(s2 as *const c_void, s2_len + 1);
|
||||
|
||||
let to_upper = |c: c_char| -> c_char {
|
||||
if ('a' as c_char..='z' as c_char).contains(&c) {
|
||||
c - 'a' as c_char + 'A' as c_char
|
||||
} else {
|
||||
c
|
||||
}
|
||||
};
|
||||
|
||||
let s1_slice = from_raw_parts(s1, s1_len);
|
||||
let s2_slice = from_raw_parts(s2, s2_len);
|
||||
|
||||
for i in 0..s1_len.max(s2_len) {
|
||||
if i >= s1_len {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if i >= s2_len {
|
||||
return 1;
|
||||
}
|
||||
|
||||
let c1u = to_upper(s1_slice[i]);
|
||||
let c2u = to_upper(s2_slice[i]);
|
||||
|
||||
if c1u < c2u {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if c1u > c2u {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
0
|
||||
}
|
||||
}
|
72
libafl_qemu/librasan/asan/src/hooks/strcasestr.rs
Normal file
72
libafl_qemu/librasan/asan/src/hooks/strcasestr.rs
Normal file
@ -0,0 +1,72 @@
|
||||
use alloc::vec::Vec;
|
||||
use core::{
|
||||
ffi::{c_char, c_void},
|
||||
ptr::null_mut,
|
||||
slice::from_raw_parts,
|
||||
};
|
||||
|
||||
use log::trace;
|
||||
|
||||
use crate::{asan_load, asan_panic};
|
||||
|
||||
/// # Safety
|
||||
/// See man pages
|
||||
#[unsafe(export_name = "patch_strcasestr")]
|
||||
pub unsafe extern "C" fn strcasestr(cs: *const c_char, ct: *const c_char) -> *mut c_char {
|
||||
unsafe {
|
||||
trace!("strcasestr - cs: {:p}, ct: {:p}", cs, ct);
|
||||
|
||||
if cs.is_null() {
|
||||
asan_panic(c"strcasestr - cs is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
if ct.is_null() {
|
||||
asan_panic(c"strcasestr - ct is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
let mut cs_len = 0;
|
||||
while *cs.add(cs_len) != 0 {
|
||||
cs_len += 1;
|
||||
}
|
||||
let mut ct_len = 0;
|
||||
while *ct.add(ct_len) != 0 {
|
||||
ct_len += 1;
|
||||
}
|
||||
asan_load(cs as *const c_void, cs_len + 1);
|
||||
asan_load(ct as *const c_void, ct_len + 1);
|
||||
|
||||
if ct_len == 0 {
|
||||
return cs as *mut c_char;
|
||||
}
|
||||
|
||||
if ct_len > cs_len {
|
||||
return null_mut();
|
||||
}
|
||||
|
||||
let to_upper = |c: c_char| -> c_char {
|
||||
if ('a' as c_char..='z' as c_char).contains(&c) {
|
||||
c - 'a' as c_char + 'A' as c_char
|
||||
} else {
|
||||
c
|
||||
}
|
||||
};
|
||||
|
||||
let cs_slice = from_raw_parts(cs, cs_len)
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(to_upper)
|
||||
.collect::<Vec<c_char>>();
|
||||
let ct_slice = from_raw_parts(ct, ct_len)
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(to_upper)
|
||||
.collect::<Vec<c_char>>();
|
||||
for i in 0..(cs_len - ct_len + 1) {
|
||||
if cs_slice[i..i + ct_len] == ct_slice {
|
||||
return cs.add(i) as *mut c_char;
|
||||
}
|
||||
}
|
||||
|
||||
null_mut()
|
||||
}
|
||||
}
|
38
libafl_qemu/librasan/asan/src/hooks/strcat.rs
Normal file
38
libafl_qemu/librasan/asan/src/hooks/strcat.rs
Normal file
@ -0,0 +1,38 @@
|
||||
use core::{
|
||||
ffi::{c_char, c_void},
|
||||
ptr::copy,
|
||||
};
|
||||
|
||||
use log::trace;
|
||||
|
||||
use crate::{asan_load, asan_panic};
|
||||
|
||||
/// # Safety
|
||||
/// See man pages
|
||||
#[unsafe(export_name = "patch_strcat")]
|
||||
pub unsafe extern "C" fn strcat(s: *mut c_char, ct: *const c_char) -> *mut c_char {
|
||||
unsafe {
|
||||
trace!("strcat - s: {:p}, ct: {:p}", s, ct);
|
||||
|
||||
if s.is_null() {
|
||||
asan_panic(c"strcat - s is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
if ct.is_null() {
|
||||
asan_panic(c"strcat - ct is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
let mut s_len = 0;
|
||||
while *s.add(s_len) != 0 {
|
||||
s_len += 1;
|
||||
}
|
||||
let mut ct_len = 0;
|
||||
while *ct.add(ct_len) != 0 {
|
||||
ct_len += 1;
|
||||
}
|
||||
asan_load(s as *const c_void, s_len + 1);
|
||||
asan_load(ct as *const c_void, ct_len + 1);
|
||||
copy(ct, s.add(s_len), ct_len + 1);
|
||||
s
|
||||
}
|
||||
}
|
34
libafl_qemu/librasan/asan/src/hooks/strchr.rs
Normal file
34
libafl_qemu/librasan/asan/src/hooks/strchr.rs
Normal file
@ -0,0 +1,34 @@
|
||||
use core::{
|
||||
ffi::{c_char, c_int, c_void},
|
||||
ptr::null_mut,
|
||||
slice::from_raw_parts,
|
||||
};
|
||||
|
||||
use log::trace;
|
||||
|
||||
use crate::{asan_load, asan_panic};
|
||||
|
||||
/// # Safety
|
||||
/// See man pages
|
||||
#[unsafe(export_name = "patch_strchr")]
|
||||
pub unsafe extern "C" fn strchr(cs: *const c_char, c: c_int) -> *mut c_char {
|
||||
unsafe {
|
||||
trace!("strchr - cs: {:p}, c: {:#x}", cs, c);
|
||||
|
||||
if cs.is_null() {
|
||||
asan_panic(c"strchr - cs is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
let mut len = 0;
|
||||
while *cs.add(len) != 0 {
|
||||
len += 1;
|
||||
}
|
||||
asan_load(cs as *const c_void, len + 1);
|
||||
let cs_slice = from_raw_parts(cs, len);
|
||||
let pos = cs_slice.iter().position(|&x| x as c_int == c);
|
||||
match pos {
|
||||
Some(pos) => cs.add(pos) as *mut c_char,
|
||||
None => null_mut(),
|
||||
}
|
||||
}
|
||||
}
|
58
libafl_qemu/librasan/asan/src/hooks/strcmp.rs
Normal file
58
libafl_qemu/librasan/asan/src/hooks/strcmp.rs
Normal file
@ -0,0 +1,58 @@
|
||||
use core::{
|
||||
cmp::Ordering,
|
||||
ffi::{c_char, c_int, c_void},
|
||||
slice::from_raw_parts,
|
||||
};
|
||||
|
||||
use log::trace;
|
||||
|
||||
use crate::{asan_load, asan_panic};
|
||||
|
||||
/// # Safety
|
||||
/// See man pages
|
||||
#[unsafe(export_name = "patch_strcmp")]
|
||||
pub unsafe extern "C" fn strcmp(cs: *const c_char, ct: *const c_char) -> c_int {
|
||||
unsafe {
|
||||
trace!("strcmp - cs: {:p}, ct: {:p}", cs, ct);
|
||||
|
||||
if cs.is_null() {
|
||||
asan_panic(c"strcmp - cs is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
if ct.is_null() {
|
||||
asan_panic(c"strcmp - ct is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
let mut cs_len = 0;
|
||||
while *cs.add(cs_len) != 0 {
|
||||
cs_len += 1;
|
||||
}
|
||||
let mut ct_len = 0;
|
||||
while *ct.add(ct_len) != 0 {
|
||||
ct_len += 1;
|
||||
}
|
||||
asan_load(cs as *const c_void, cs_len + 1);
|
||||
asan_load(ct as *const c_void, ct_len + 1);
|
||||
|
||||
let slice1 = from_raw_parts(cs as *const u8, cs_len);
|
||||
let slice2 = from_raw_parts(ct as *const u8, ct_len);
|
||||
|
||||
for i in 0..cs_len.max(ct_len) {
|
||||
if i >= cs_len {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if i >= ct_len {
|
||||
return 1;
|
||||
}
|
||||
|
||||
match slice1[i].cmp(&slice2[i]) {
|
||||
Ordering::Equal => (),
|
||||
Ordering::Less => return -1,
|
||||
Ordering::Greater => return 1,
|
||||
}
|
||||
}
|
||||
|
||||
0
|
||||
}
|
||||
}
|
34
libafl_qemu/librasan/asan/src/hooks/strcpy.rs
Normal file
34
libafl_qemu/librasan/asan/src/hooks/strcpy.rs
Normal file
@ -0,0 +1,34 @@
|
||||
use core::{
|
||||
ffi::{c_char, c_void},
|
||||
ptr::copy,
|
||||
};
|
||||
|
||||
use log::trace;
|
||||
|
||||
use crate::{asan_load, asan_panic, asan_store};
|
||||
|
||||
/// # Safety
|
||||
/// See man pages
|
||||
#[unsafe(export_name = "patch_strcpy")]
|
||||
pub unsafe extern "C" fn strcpy(dst: *mut c_char, src: *const c_char) -> *mut c_char {
|
||||
unsafe {
|
||||
trace!("strcpy - dst: {:p}, src: {:p}", dst, src);
|
||||
|
||||
if dst.is_null() {
|
||||
asan_panic(c"strcpy - dst is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
if src.is_null() {
|
||||
asan_panic(c"strcpy - src is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
let mut len = 0;
|
||||
while *src.add(len) != 0 {
|
||||
len += 1;
|
||||
}
|
||||
asan_load(src as *const c_void, len + 1);
|
||||
asan_store(dst as *const c_void, len + 1);
|
||||
copy(src, dst, len + 1);
|
||||
dst
|
||||
}
|
||||
}
|
31
libafl_qemu/librasan/asan/src/hooks/strdup.rs
Normal file
31
libafl_qemu/librasan/asan/src/hooks/strdup.rs
Normal file
@ -0,0 +1,31 @@
|
||||
use core::{
|
||||
ffi::{c_char, c_void},
|
||||
ptr::copy,
|
||||
};
|
||||
|
||||
use log::trace;
|
||||
|
||||
use crate::{asan_alloc, asan_load, asan_panic};
|
||||
|
||||
/// # Safety
|
||||
/// See man pages
|
||||
#[unsafe(export_name = "patch_strdup")]
|
||||
pub unsafe extern "C" fn strdup(cs: *const c_char) -> *mut c_char {
|
||||
unsafe {
|
||||
trace!("strdup - cs: {:p}", cs);
|
||||
|
||||
if cs.is_null() {
|
||||
asan_panic(c"strdup - cs is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
let mut len = 0;
|
||||
while *cs.add(len) != 0 {
|
||||
len += 1;
|
||||
}
|
||||
asan_load(cs as *const c_void, len + 1);
|
||||
|
||||
let dest = asan_alloc(len + 1, 0) as *mut c_char;
|
||||
copy(cs, dest, len + 1);
|
||||
dest
|
||||
}
|
||||
}
|
25
libafl_qemu/librasan/asan/src/hooks/strlen.rs
Normal file
25
libafl_qemu/librasan/asan/src/hooks/strlen.rs
Normal file
@ -0,0 +1,25 @@
|
||||
use core::ffi::{c_char, c_void};
|
||||
|
||||
use log::trace;
|
||||
|
||||
use crate::{asan_load, asan_panic, size_t};
|
||||
|
||||
/// # Safety
|
||||
/// See man pages
|
||||
#[unsafe(export_name = "patch_strlen")]
|
||||
pub unsafe extern "C" fn strlen(cs: *const c_char) -> size_t {
|
||||
unsafe {
|
||||
trace!("strlen - cs: {:p}", cs);
|
||||
|
||||
if cs.is_null() {
|
||||
asan_panic(c"strlen - cs is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
let mut len = 0;
|
||||
while *cs.add(len) != 0 {
|
||||
len += 1;
|
||||
}
|
||||
asan_load(cs as *const c_void, len + 1);
|
||||
len
|
||||
}
|
||||
}
|
73
libafl_qemu/librasan/asan/src/hooks/strncasecmp.rs
Normal file
73
libafl_qemu/librasan/asan/src/hooks/strncasecmp.rs
Normal file
@ -0,0 +1,73 @@
|
||||
use core::{
|
||||
ffi::{c_char, c_int, c_void},
|
||||
slice::from_raw_parts,
|
||||
};
|
||||
|
||||
use log::trace;
|
||||
|
||||
use crate::{asan_load, asan_panic, size_t};
|
||||
|
||||
/// # Safety
|
||||
/// See man pages
|
||||
#[unsafe(export_name = "patch_strncasecmp")]
|
||||
pub unsafe extern "C" fn strncasecmp(s1: *const c_char, s2: *const c_char, n: size_t) -> c_int {
|
||||
unsafe {
|
||||
trace!("strncasecmp - s1: {:p}, s2: {:p}, n: {:#x}", s1, s2, n);
|
||||
|
||||
if n == 0 {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if s1.is_null() {
|
||||
asan_panic(c"strncasecmp - s1 is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
if s2.is_null() {
|
||||
asan_panic(c"strncasecmp - s2 is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
let mut s1_len = 0;
|
||||
while s1_len < n && *s1.add(s1_len) != 0 {
|
||||
s1_len += 1;
|
||||
}
|
||||
let mut s2_len = 0;
|
||||
while s2_len < n && *s2.add(s2_len) != 0 {
|
||||
s2_len += 1;
|
||||
}
|
||||
asan_load(s1 as *const c_void, s1_len + 1);
|
||||
asan_load(s2 as *const c_void, s2_len + 1);
|
||||
|
||||
let to_upper = |c: c_char| -> c_char {
|
||||
if ('a' as c_char..='z' as c_char).contains(&c) {
|
||||
c - 'a' as c_char + 'A' as c_char
|
||||
} else {
|
||||
c
|
||||
}
|
||||
};
|
||||
|
||||
let s1_slice = from_raw_parts(s1, s1_len);
|
||||
let s2_slice = from_raw_parts(s2, s2_len);
|
||||
for i in 0..s1_len.max(s2_len) {
|
||||
if i >= s1_len {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if i >= s2_len {
|
||||
return 1;
|
||||
}
|
||||
|
||||
let c1u = to_upper(s1_slice[i]);
|
||||
let c2u = to_upper(s2_slice[i]);
|
||||
|
||||
if c1u < c2u {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if c1u > c2u {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
0
|
||||
}
|
||||
}
|
62
libafl_qemu/librasan/asan/src/hooks/strncmp.rs
Normal file
62
libafl_qemu/librasan/asan/src/hooks/strncmp.rs
Normal file
@ -0,0 +1,62 @@
|
||||
use core::{
|
||||
cmp::Ordering,
|
||||
ffi::{c_char, c_int, c_void},
|
||||
slice::from_raw_parts,
|
||||
};
|
||||
|
||||
use log::trace;
|
||||
|
||||
use crate::{asan_load, asan_panic, size_t};
|
||||
|
||||
/// # Safety
|
||||
/// See man pages
|
||||
#[unsafe(export_name = "patch_strncmp")]
|
||||
pub unsafe extern "C" fn strncmp(cs: *const c_char, ct: *const c_char, n: size_t) -> c_int {
|
||||
unsafe {
|
||||
trace!("strncmp - cs: {:p}, ct: {:p}, n: {:#x}", cs, ct, n);
|
||||
|
||||
if n == 0 {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if cs.is_null() {
|
||||
asan_panic(c"strncmp - cs is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
if ct.is_null() {
|
||||
asan_panic(c"strncmp - ct is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
let mut cs_len = 0;
|
||||
while cs_len < n && *cs.add(cs_len) != 0 {
|
||||
cs_len += 1;
|
||||
}
|
||||
let mut ct_len = 0;
|
||||
while ct_len < n && *ct.add(ct_len) != 0 {
|
||||
ct_len += 1;
|
||||
}
|
||||
asan_load(cs as *const c_void, cs_len + 1);
|
||||
asan_load(ct as *const c_void, ct_len + 1);
|
||||
|
||||
let slice1 = from_raw_parts(cs as *const u8, cs_len);
|
||||
let slice2 = from_raw_parts(ct as *const u8, ct_len);
|
||||
|
||||
for i in 0..cs_len.max(ct_len) {
|
||||
if i >= cs_len {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if i >= ct_len {
|
||||
return 1;
|
||||
}
|
||||
|
||||
match slice1[i].cmp(&slice2[i]) {
|
||||
Ordering::Equal => (),
|
||||
Ordering::Less => return -1,
|
||||
Ordering::Greater => return 1,
|
||||
}
|
||||
}
|
||||
|
||||
0
|
||||
}
|
||||
}
|
40
libafl_qemu/librasan/asan/src/hooks/strncpy.rs
Normal file
40
libafl_qemu/librasan/asan/src/hooks/strncpy.rs
Normal file
@ -0,0 +1,40 @@
|
||||
use core::{
|
||||
ffi::{c_char, c_void},
|
||||
ptr::copy,
|
||||
};
|
||||
|
||||
use log::trace;
|
||||
|
||||
use crate::{asan_load, asan_panic, asan_store, size_t};
|
||||
|
||||
/// # Safety
|
||||
/// See man pages
|
||||
#[unsafe(export_name = "patch_strncpy")]
|
||||
pub unsafe extern "C" fn strncpy(dst: *mut c_char, src: *const c_char, n: size_t) -> *mut c_char {
|
||||
unsafe {
|
||||
trace!("strncpy - dst: {:p}, src: {:p}, n: {:#x}", dst, src, n);
|
||||
|
||||
if n == 0 {
|
||||
return dst;
|
||||
}
|
||||
|
||||
if dst.is_null() {
|
||||
asan_panic(c"strncpy - dst is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
if src.is_null() {
|
||||
asan_panic(c"strncpy - src is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
let mut len = 0;
|
||||
while len < n && *src.add(len) != 0 {
|
||||
len += 1;
|
||||
}
|
||||
asan_store(dst as *const c_void, len);
|
||||
|
||||
asan_load(src as *const c_void, len);
|
||||
copy(src, dst, len);
|
||||
|
||||
dst
|
||||
}
|
||||
}
|
38
libafl_qemu/librasan/asan/src/hooks/strndup.rs
Normal file
38
libafl_qemu/librasan/asan/src/hooks/strndup.rs
Normal file
@ -0,0 +1,38 @@
|
||||
use core::{
|
||||
ffi::{c_char, c_void},
|
||||
ptr::copy,
|
||||
};
|
||||
|
||||
use log::trace;
|
||||
|
||||
use crate::{asan_alloc, asan_load, asan_panic, size_t};
|
||||
|
||||
/// # Safety
|
||||
/// See man pages
|
||||
#[unsafe(export_name = "patch_strndup")]
|
||||
pub unsafe extern "C" fn strndup(cs: *const c_char, n: size_t) -> *mut c_char {
|
||||
unsafe {
|
||||
trace!("strndup - cs: {:p}, n: {:#x}", cs, n);
|
||||
|
||||
if cs.is_null() {
|
||||
if n == 0 {
|
||||
let dest = asan_alloc(1, 0) as *mut c_char;
|
||||
*dest = 0;
|
||||
return dest;
|
||||
} else {
|
||||
asan_panic(c"strndup - cs is null".as_ptr() as *const c_char);
|
||||
}
|
||||
}
|
||||
|
||||
let mut len = 0;
|
||||
while len < n && *cs.add(len) != 0 {
|
||||
len += 1;
|
||||
}
|
||||
asan_load(cs as *const c_void, len + 1);
|
||||
|
||||
let dest = asan_alloc(len + 1, 0) as *mut c_char;
|
||||
copy(cs, dest, len + 1);
|
||||
*dest.add(len) = 0;
|
||||
dest
|
||||
}
|
||||
}
|
35
libafl_qemu/librasan/asan/src/hooks/strnlen.rs
Normal file
35
libafl_qemu/librasan/asan/src/hooks/strnlen.rs
Normal file
@ -0,0 +1,35 @@
|
||||
use core::ffi::{c_char, c_void};
|
||||
|
||||
use log::trace;
|
||||
|
||||
use crate::{asan_load, asan_panic, size_t};
|
||||
|
||||
/// # Safety
|
||||
/// See man pages
|
||||
#[unsafe(export_name = "patch_strnlen")]
|
||||
pub unsafe extern "C" fn strnlen(cs: *const c_char, maxlen: size_t) -> size_t {
|
||||
unsafe {
|
||||
trace!("strnlen - cs: {:p}, maxlen: {:#x}", cs, maxlen);
|
||||
|
||||
if maxlen == 0 {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if cs.is_null() {
|
||||
asan_panic(c"strnlen - cs is null".as_ptr() as *const c_char);
|
||||
}
|
||||
|
||||
let mut len = 0;
|
||||
while *cs.add(len) != 0 {
|
||||
len += 1;
|
||||
}
|
||||
|
||||
if len < maxlen {
|
||||
asan_load(cs as *const c_void, len + 1);
|
||||
len
|
||||
} else {
|
||||
asan_load(cs as *const c_void, maxlen);
|
||||
maxlen
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user