Compare commits

...

7 Commits

Author SHA1 Message Date
0e8324d4b1 add output warning 2024-02-13 14:00:14 +01:00
5f5d848964 add output warning 2024-02-13 13:58:27 +01:00
4309e48085 enhancement 2024-02-12 09:18:07 +01:00
bf06b7e897 enhancement 2024-02-12 09:17:52 +01:00
6316994857 try ramp up for colorless 2024-02-11 23:12:24 +01:00
30c91e46af Merge pull request #1992 from ndrewh/dev
redqueen: time limit for colorization
2024-02-11 22:23:37 +01:00
c0b667178b redqueen: time limit for colorization
For nondeterministic inputs, or inputs where a large portion of the
input bytes break the path (e.g., bytes protected by a checksum),
colorization will split the range n times, once for every byte.

This is bad: for a 10k input that runs in 100ms, colorization
will take 15 minutes. For larger/slower inputs, it can easily
take hours.

This places a upper-bound on the runtime of colorization.
2024-02-11 12:17:55 -05:00
3 changed files with 59 additions and 2 deletions

View File

@ -605,6 +605,9 @@ typedef struct afl_state {
#define N_FUZZ_SIZE (1 << 21)
u32 *n_fuzz;
/* CMPLOG colorless feature */
u64 cmplog_color_items, cmplog_color_fail, cmplog_color_depth;
volatile u8 stop_soon, /* Ctrl-C pressed? */
clear_screen; /* Window resized? */

View File

@ -85,6 +85,11 @@
/* Maximum allowed fails per CMP value. Default: 96 */
#define CMPLOG_FAIL_MAX 96
/* Starting timeout (in seconds) for the CMPLOG colorization phase. Upon
multiple timeouts this value will be doubled 4 times each.
So: 60 seconds => 960 seconds max. Good values are 30-120 seconds. */
#define CMPLOG_COLORIZATION_TIME_MAX_START 60ULL
/* -------------------------------------*/
/* Now non-cmplog configuration options */
/* -------------------------------------*/

View File

@ -107,11 +107,12 @@ static struct range *add_range(struct range *ranges, u32 start, u32 end) {
}
static struct range *pop_biggest_range(struct range **ranges) {
static struct range *pop_biggest_range(struct range **ranges, int *num_ranges) {
struct range *r = *ranges;
struct range *rmax = NULL;
u32 max_size = 0;
u32 count = 0;
while (r) {
@ -129,9 +130,11 @@ static struct range *pop_biggest_range(struct range **ranges) {
}
r = r->next;
++count;
}
*num_ranges = count;
return rmax;
}
@ -311,6 +314,7 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len,
afl->stage_short = "colorization";
afl->stage_max = (len << 1);
afl->stage_cur = 0;
++(afl->cmplog_color_items);
// in colorization we do not classify counts, hence we have to calculate
// the original checksum.
@ -332,7 +336,8 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len,
}
while ((rng = pop_biggest_range(&ranges)) != NULL &&
u32 range_count = 0;
while ((rng = pop_biggest_range(&ranges, &range_count)) != NULL &&
afl->stage_cur < afl->stage_max) {
u32 s = 1 + rng->end - rng->start;
@ -363,6 +368,50 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len,
ranges = add_range(ranges, rng->start, rng->start - 1 + s / 2);
ranges = add_range(ranges, rng->start + s / 2, rng->end);
/* Check the number of *remaining* execs for colorization; since
each represents a previously split range, and may be split
again, we break when emptying the queue would consume *half*
the timeout */
if ((range_count * afl->queue_cur->exec_us) >
((CMPLOG_COLORIZATION_TIME_MAX_START << afl->cmplog_color_depth) /
2 * 1000000)) {
if (afl->afl_env.afl_no_ui) {
WARNF(
"Colorization took too long, skipping (%llu/%llu, depth %llu).",
afl->cmplog_color_fail + 1, afl->cmplog_color_items,
afl->cmplog_color_depth);
}
if (unlikely(afl->cmplog_color_depth < 4)) {
++(afl->cmplog_color_fail);
if (likely(afl->cmplog_color_items > 4) &&
unlikely(afl->cmplog_color_items / afl->cmplog_color_fail) <
2) {
++(afl->cmplog_color_depth);
afl->cmplog_color_items = 0;
afl->cmplog_color_fail = 0;
if (afl->afl_env.afl_no_ui) {
WARNF("Increasing colorization time depth to %llu.",
afl->cmplog_color_depth);
}
}
}
goto checksum_fail;
}
}
if (ranges == rng) {