AFLplusplus / AFLplusplus/LibAFL

[libafl-targets] Value profile guidance for strcmp/memcmp interceptor and friends

Đang mở
#3,042 0 bình luận 1 reaction 1 người được giao Được @addisoncrump nhận Xem trên GitHub
enhancement
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

Mở hướng dẫn đóng góp

Đánh giá

Issue này chưa được đánh giá.

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.