AFLplusplus / AFLplusplus/LibAFL
[libafl-targets] Value profile guidance for strcmp/memcmp interceptor and friends
- Ngôn ngữ chính
- Rust
- Star
- 2.6k
- Fork
- 481
- Merge trung bình
- 2 ngày 30 phút
- Pull request đã merge (30 ngày)
- 16
Mô tả
Currently in libfuzzer, the hooks for strncmp, [`__sanitizer_weak_hook_strncmp`](https://github.com/llvm/llvm-project/blob/74df2032d467618a9aab085120539e306f21bcc0/compiler-rt/lib/fuzzer/FuzzerTracePC.cpp#L628-L639) calls into:
```c
fuzzer::TPC.AddValueForMemcmp(caller_pc, s1, s2, n, /*StopAtZero*/true);
```
and then `AddValueForMemcmp` in turn does [these two calls](https://github.com/llvm/llvm-project/blob/74df2032d467618a9aab085120539e306f21bcc0/compiler-rt/lib/fuzzer/FuzzerTracePC.cpp#L376-L377):
```c
ValueProfileMap.AddValue(Idx);
TORCW.Insert(Idx ^ Hash, Word(B1, Len), Word(B2, Len));
```
`TORCW` is the comparison logging mechanism but notice it also has `ValueProfileMap` guidance here.
(same code in [AFL++ here](https://github.com/AFLplusplus/AFLplusplus/blob/f590973387ee04d6c7ef016d5111313f9f4945b8/custom_mutators/libfuzzer/FuzzerTracePC.cpp#L432-L434))
---
In comparison, the hook for strncmp in `libafl-targets` does: https://github.com/AFLplusplus/LibAFL/blob/89342b22c2011f455566d1b5516177b9857dd3f2/libafl_targets/src/sancov_cmp.rs#L92
which in turn only adds the value to the cmplog map:
https://github.com/AFLplusplus/LibAFL/blob/89342b22c2011f455566d1b5516177b9857dd3f2/libafl_targets/src/cmplog.h#L190-L191
---
This prevents libafl-libfuzzer from being able to solve things like this little harness (full harness attached [harness.cpp.txt](https://github.com/user-attachments/files/19095581/harness.cpp.txt)):
```c
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
if (Size == 0) return 0;
char* encoded = (char*) malloc(Size * 3);
if (encoded == NULL) return 0;
int b64_length = b64_encode((unsigned char*) Data, Size, (unsigned char*) encoded);
// "Hello " in base64 so it's not visible to cmplog
if (strncmp(encoded, "SGVsbG8g", 8) == 0) {
// "World" in base64 so it's not visible to cmplog
if (b64_length > 8 && strncmp(encoded + b64_length - 8, "V29ybGQ=", 8) == 0) {
abort();
}
}
free(encoded);
return 0;
}
```
libfuzzer with value profiles can solve this rather easily because it breaks the strncmp into a brute-force of the base64 output:
```
$ time ./libfuzzer -use_value_profile=1
INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 3161432840
INFO: Loaded 1 modules (16 inline 8-bit counters): 16 [0x55a96f6e0fe1, 0x55a96f6e0ff1),
INFO: Loaded 1 PC tables (16 PCs): 16 [0x55a96f6e0ff8,0x55a96f6e10f8),
INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes
INFO: A corpus is not provided, starting from an empty corpus
#2 INITED cov: 7 ft: 24 corp: 1/1b exec/s: 0 rss: 26Mb
...
0x48,0x65,0x6c,0x6c,0x6f,0x20,0x57,0x6f,0x72,0x6c,0x64,
Hello World
artifact_prefix='./'; Test unit written to ./crash-0a4d55a8d778e5022fab701977c5d840bbc486d0
Base64: SGVsbG8gV29ybGQ=
real 0m20.850s
user 0m20.556s
sys 0m0.068s
...
```
but using libafl's libfuzzer shim for the same thing:
```
$ time ./libafl-libfuzzer -use_value_profile=1
WARNING: cowardly refusing to use grimoire since we cannot determine if the input is primarily text; set -grimoire=1 or provide a corpus directory.
[UserStats #0] (GLOBAL) run time: 0h-0m-0s, clients: 1, corpus: 0, objectives: 0, executions: 0, exec/sec: 0.000, edges: 43.750%
(CLIENT) corpus: 0, objectives: 0, executions: 0, exec/sec: 0.000, edges: 7/16 (43%)
[UserStats #0] (GLOBAL) run time: 0h-0m-0s, clients: 1, corpus: 0, objectives: 0, executions: 0, exec/sec: 0.000, edges: 43.750%, size_edges: 43.750%
...
[Client Heartbeat #0] (GLOBAL) run time: 0h-4m-30s, clients: 1, corpus: 10, objectives: 0, executions: 2015729, exec/sec: 7.459k, cmps: 0.011%, edges: 68.750%, size_edges: 68.750%, stability: 100.000%
(CLIENT) corpus: 10, objectives: 0, executions: 2015729, exec/sec: 7.459k, cmps: 7/65536 (0%), edges: 11/16 (68%), size_edges: 11/16 (68%), stability: 11/11 (100%)
[Client Heartbeat #0] (GLOBAL) run time: 0h-4m-45s, clients: 1, corpus: 10, objectives: 0, executions: 2126692, exec/sec: 7.455k, cmps: 0.011%, edges: 68.750%, size_edges: 68.750%, stability: 100.000%
(CLIENT) corpus: 10, objectives: 0, executions: 2126692, exec/sec: 7.455k, cmps: 7/65536 (0%), edges: 11/16 (68%), size_edges: 11/16 (68%), stability: 11/11 (100%)
[Client Heartbeat #0] (GLOBAL) run time: 0h-5m-0s, clients: 1, corpus: 10, objectives: 0, executions: 2240750, exec/sec: 7.463k, cmps: 0.011%, edges: 68.750%, size_edges: 68.750%, stability: 100.000%
(CLIENT) corpus: 10, objectives: 0, executions: 2240750, exec/sec: 7.463k, cmps: 7/65536 (0%), edges: 11/16 (68%), size_edges: 11/16 (68%), stability: 11/11 (100%)
^C
real 5m2.676s
user 4m59.504s
sys 0m3.055s
```
Notice there isn't an increase in `cmps`.
Hướng dẫn đóng góp
Đánh giá
Issue này chưa được đánh giá.