-
-
Notifications
You must be signed in to change notification settings - Fork 412
Description
Currently in libfuzzer, the hooks for strncmp, __sanitizer_weak_hook_strncmp calls into:
fuzzer::TPC.AddValueForMemcmp(caller_pc, s1, s2, n, /*StopAtZero*/true);and then AddValueForMemcmp in turn does these two calls:
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)
In comparison, the hook for strncmp in libafl-targets does:
LibAFL/libafl_targets/src/sancov_cmp.rs
Line 92 in 89342b2
| __libafl_targets_cmplog_routines_len(k, s1 as *const u8, s2 as *const u8, actual_len); |
which in turn only adds the value to the cmplog map:
LibAFL/libafl_targets/src/cmplog.h
Lines 190 to 191 in 89342b2
| MEMCPY(libafl_cmplog_map_ptr->vals.routines[k][hits].v0, ptr1, len); | |
| MEMCPY(libafl_cmplog_map_ptr->vals.routines[k][hits].v1, ptr2, len); |
This prevents libafl-libfuzzer from being able to solve things like this little harness (full harness attached harness.cpp.txt):
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.