new rtn cmplog: instrumentation side + supporting functions

This commit is contained in:
vanhauser-thc
2021-10-17 13:05:33 +02:00
parent 34f1074ba3
commit ed10f3783b
9 changed files with 551 additions and 26 deletions

View File

@ -1136,6 +1136,7 @@ void setup_signal_handlers(void);
void save_cmdline(afl_state_t *, u32, char **); void save_cmdline(afl_state_t *, u32, char **);
void read_foreign_testcases(afl_state_t *, int); void read_foreign_testcases(afl_state_t *, int);
void write_crash_readme(afl_state_t *afl); void write_crash_readme(afl_state_t *afl);
u8 check_if_text_buf(u8 *buf, u32 len);
/* CmpLog */ /* CmpLog */

View File

@ -33,7 +33,7 @@
#define CMPLOG_LVL_MAX 3 #define CMPLOG_LVL_MAX 3
#define CMP_MAP_W 65536 #define CMP_MAP_W 65536
#define CMP_MAP_H 32 #define CMP_MAP_H 64
#define CMP_MAP_RTN_H (CMP_MAP_H / 4) #define CMP_MAP_RTN_H (CMP_MAP_H / 4)
#define SHAPE_BYTES(x) (x + 1) #define SHAPE_BYTES(x) (x + 1)
@ -59,14 +59,16 @@ struct cmp_operands {
u64 v0_128; u64 v0_128;
u64 v1_128; u64 v1_128;
}; } __attribute__((packed));
struct cmpfn_operands { struct cmpfn_operands {
u8 v0[32]; u8 v0[31];
u8 v1[32]; u8 v0_len;
u8 v1[31];
u8 v1_len;
}; } __attribute__((packed));
typedef struct cmp_operands cmp_map_list[CMP_MAP_H]; typedef struct cmp_operands cmp_map_list[CMP_MAP_H];

View File

@ -267,8 +267,8 @@
(first value), and to keep in memory as candidates. The latter should be much (first value), and to keep in memory as candidates. The latter should be much
higher than the former. */ higher than the former. */
#define USE_AUTO_EXTRAS 128 #define USE_AUTO_EXTRAS 4096
#define MAX_AUTO_EXTRAS (USE_AUTO_EXTRAS * 64) #define MAX_AUTO_EXTRAS (USE_AUTO_EXTRAS * 8)
/* Scaling factor for the effector map used to skip some of the more /* Scaling factor for the effector map used to skip some of the more
expensive deterministic steps. The actual divisor is set to expensive deterministic steps. The actual divisor is set to

View File

@ -1880,6 +1880,191 @@ static int area_is_valid(void *ptr, size_t len) {
} }
void __cmplog_rtn_hook_n(u8 *ptr1, u8 *ptr2, u32 len) {
/*
u32 i;
if (area_is_valid(ptr1, 32) <= 0 || area_is_valid(ptr2, 32) <= 0) return;
fprintf(stderr, "rtn_n len=%u arg0=", len);
for (i = 0; i < len; i++)
fprintf(stderr, "%02x", ptr1[i]);
fprintf(stderr, " arg1=");
for (i = 0; i < len; i++)
fprintf(stderr, "%02x", ptr2[i]);
fprintf(stderr, "\n");
*/
if (likely(!__afl_cmp_map)) return;
// fprintf(stderr, "RTN1 %p %p %u\n", ptr1, ptr2, len);
if (unlikely(!len)) return;
int l = MIN(31, len);
// fprintf(stderr, "RTN2 %u\n", l);
uintptr_t k = (uintptr_t)__builtin_return_address(0);
k = (k >> 4) ^ (k << 8);
k &= CMP_MAP_W - 1;
u32 hits, reset = 1;
if (__afl_cmp_map->headers[k].type != CMP_TYPE_RTN) {
__afl_cmp_map->headers[k].type = CMP_TYPE_RTN;
__afl_cmp_map->headers[k].hits = 1;
__afl_cmp_map->headers[k].shape = l - 1;
reset = hits = 0;
} else {
hits = __afl_cmp_map->headers[k].hits++;
if (__afl_cmp_map->headers[k].shape < l) {
__afl_cmp_map->headers[k].shape = l - 1;
}
}
struct cmpfn_operands *cmpfn = (struct cmpfn_operands *)__afl_cmp_map->log[k];
hits &= CMP_MAP_RTN_H - 1;
if (unlikely(reset && !hits)) {
__builtin_memset(cmpfn, 0, sizeof(struct cmpfn_operands));
}
cmpfn[hits].v0_len = l;
cmpfn[hits].v1_len = l;
__builtin_memcpy(cmpfn[hits].v0, ptr1, l);
__builtin_memcpy(cmpfn[hits].v1, ptr2, l);
// fprintf(stderr, "RTN3\n");
}
void __cmplog_rtn_hook_strn(u8 *ptr1, u8 *ptr2, u32 len) {
/*
u32 i;
if (area_is_valid(ptr1, 32) <= 0 || area_is_valid(ptr2, 32) <= 0) return;
fprintf(stderr, "rtn_strn len=%u arg0=", len);
for (i = 0; i < len; i++)
fprintf(stderr, "%02x", ptr1[i]);
fprintf(stderr, " arg1=");
for (i = 0; i < len; i++)
fprintf(stderr, "%02x", ptr2[i]);
fprintf(stderr, "\n");
*/
if (likely(!__afl_cmp_map)) return;
// fprintf(stderr, "RTN1 %p %p %u\n", ptr1, ptr2, len);
if (unlikely(!len)) return;
int l = MIN(31, len + 1);
// fprintf(stderr, "RTN2 %u\n", l);
uintptr_t k = (uintptr_t)__builtin_return_address(0);
k = (k >> 4) ^ (k << 8);
k &= CMP_MAP_W - 1;
u32 hits, reset = 1;
if (__afl_cmp_map->headers[k].type != CMP_TYPE_RTN) {
__afl_cmp_map->headers[k].type = CMP_TYPE_RTN;
__afl_cmp_map->headers[k].hits = 1;
__afl_cmp_map->headers[k].shape = l - 1;
reset = hits = 0;
} else {
hits = __afl_cmp_map->headers[k].hits++;
if (__afl_cmp_map->headers[k].shape < l) {
__afl_cmp_map->headers[k].shape = l - 1;
}
}
struct cmpfn_operands *cmpfn = (struct cmpfn_operands *)__afl_cmp_map->log[k];
hits &= CMP_MAP_RTN_H - 1;
if (unlikely(reset && !hits)) {
__builtin_memset(cmpfn, 0, sizeof(struct cmpfn_operands));
}
cmpfn[hits].v0_len = 0x80 + l;
cmpfn[hits].v1_len = 0x80 + l;
__builtin_memcpy(cmpfn[hits].v0, ptr1, l);
__builtin_memcpy(cmpfn[hits].v1, ptr2, l);
// fprintf(stderr, "RTN3\n");
}
void __cmplog_rtn_hook_str(u8 *ptr1, u8 *ptr2) {
/*
u32 i;
if (area_is_valid(ptr1, 32) <= 0 || area_is_valid(ptr2, 32) <= 0) return;
fprintf(stderr, "rtn_str arg0=");
for (i = 0; i < len; i++)
fprintf(stderr, "%02x", ptr1[i]);
fprintf(stderr, " arg1=");
for (i = 0; i < len; i++)
fprintf(stderr, "%02x", ptr2[i]);
fprintf(stderr, "\n");
*/
if (likely(!__afl_cmp_map)) return;
// fprintf(stderr, "RTN1 %p %p\n", ptr1, ptr2);
if (unlikely(!ptr1 || !ptr2)) return;
int len1 = MIN(31, strlen(ptr1) + 1);
int len2 = MIN(31, strlen(ptr2) + 1);
int l = MIN(MAX(len1, len2), 31);
// fprintf(stderr, "RTN2 %u\n", l);
uintptr_t k = (uintptr_t)__builtin_return_address(0);
k = (k >> 4) ^ (k << 8);
k &= CMP_MAP_W - 1;
u32 hits, reset = 1;
if (__afl_cmp_map->headers[k].type != CMP_TYPE_RTN) {
__afl_cmp_map->headers[k].type = CMP_TYPE_RTN;
__afl_cmp_map->headers[k].hits = 1;
__afl_cmp_map->headers[k].shape = l - 1;
reset = hits = 0;
} else {
hits = __afl_cmp_map->headers[k].hits++;
if (__afl_cmp_map->headers[k].shape < l) {
__afl_cmp_map->headers[k].shape = l - 1;
}
}
struct cmpfn_operands *cmpfn = (struct cmpfn_operands *)__afl_cmp_map->log[k];
hits &= CMP_MAP_RTN_H - 1;
if (unlikely(reset && !hits)) {
__builtin_memset(cmpfn, 0, sizeof(struct cmpfn_operands));
}
cmpfn[hits].v0_len = 0x80 + len1;
cmpfn[hits].v1_len = 0x80 + len2;
__builtin_memcpy(cmpfn[hits].v0, ptr1, len1);
__builtin_memcpy(cmpfn[hits].v1, ptr2, len2);
// fprintf(stderr, "RTN3\n");
}
void __cmplog_rtn_hook(u8 *ptr1, u8 *ptr2) { void __cmplog_rtn_hook(u8 *ptr1, u8 *ptr2) {
/* /*
@ -1907,14 +2092,14 @@ void __cmplog_rtn_hook(u8 *ptr1, u8 *ptr2) {
k = (k >> 4) ^ (k << 8); k = (k >> 4) ^ (k << 8);
k &= CMP_MAP_W - 1; k &= CMP_MAP_W - 1;
u32 hits; u32 hits, reset = 1;
if (__afl_cmp_map->headers[k].type != CMP_TYPE_RTN) { if (__afl_cmp_map->headers[k].type != CMP_TYPE_RTN) {
__afl_cmp_map->headers[k].type = CMP_TYPE_RTN; __afl_cmp_map->headers[k].type = CMP_TYPE_RTN;
__afl_cmp_map->headers[k].hits = 1; __afl_cmp_map->headers[k].hits = 1;
__afl_cmp_map->headers[k].shape = len - 1; __afl_cmp_map->headers[k].shape = len - 1;
hits = 0; reset = hits = 0;
} else { } else {
@ -1928,11 +2113,16 @@ void __cmplog_rtn_hook(u8 *ptr1, u8 *ptr2) {
} }
struct cmpfn_operands *cmpfn = (struct cmpfn_operands *)__afl_cmp_map->log[k];
hits &= CMP_MAP_RTN_H - 1; hits &= CMP_MAP_RTN_H - 1;
__builtin_memcpy(((struct cmpfn_operands *)__afl_cmp_map->log[k])[hits].v0, if (unlikely(reset && !hits)) {
ptr1, len);
__builtin_memcpy(((struct cmpfn_operands *)__afl_cmp_map->log[k])[hits].v1, __builtin_memset(cmpfn, 0, sizeof(struct cmpfn_operands));
ptr2, len);
}
__builtin_memcpy(cmpfn[hits].v0, ptr1, len);
__builtin_memcpy(cmpfn[hits].v1, ptr2, len);
// fprintf(stderr, "RTN3\n"); // fprintf(stderr, "RTN3\n");
} }

View File

@ -87,12 +87,14 @@ char CmpLogRoutines::ID = 0;
bool CmpLogRoutines::hookRtns(Module &M) { bool CmpLogRoutines::hookRtns(Module &M) {
std::vector<CallInst *> calls, llvmStdStd, llvmStdC, gccStdStd, gccStdC; std::vector<CallInst *> calls, llvmStdStd, llvmStdC, gccStdStd, gccStdC,
LLVMContext & C = M.getContext(); Memcmp, Strcmp, Strncmp;
LLVMContext &C = M.getContext();
Type *VoidTy = Type::getVoidTy(C); Type *VoidTy = Type::getVoidTy(C);
// PointerType *VoidPtrTy = PointerType::get(VoidTy, 0); // PointerType *VoidPtrTy = PointerType::get(VoidTy, 0);
IntegerType *Int8Ty = IntegerType::getInt8Ty(C); IntegerType *Int8Ty = IntegerType::getInt8Ty(C);
IntegerType *Int32Ty = IntegerType::getInt32Ty(C);
PointerType *i8PtrTy = PointerType::get(Int8Ty, 0); PointerType *i8PtrTy = PointerType::get(Int8Ty, 0);
#if LLVM_VERSION_MAJOR < 9 #if LLVM_VERSION_MAJOR < 9
@ -184,6 +186,60 @@ bool CmpLogRoutines::hookRtns(Module &M) {
FunctionCallee cmplogGccStdC = c4; FunctionCallee cmplogGccStdC = c4;
#endif #endif
#if LLVM_VERSION_MAJOR < 9
Constant *
#else
FunctionCallee
#endif
c5 = M.getOrInsertFunction("__cmplog_rtn_hook_n", VoidTy, i8PtrTy,
i8PtrTy, Int32Ty
#if LLVM_VERSION_MAJOR < 5
,
NULL
#endif
);
#if LLVM_VERSION_MAJOR < 9
Function *cmplogHookFnN = cast<Function>(c5);
#else
FunctionCallee cmplogHookFnN = c5;
#endif
#if LLVM_VERSION_MAJOR < 9
Constant *
#else
FunctionCallee
#endif
c6 = M.getOrInsertFunction("__cmplog_rtn_hook_strn", VoidTy, i8PtrTy,
i8PtrTy, Int32Ty
#if LLVM_VERSION_MAJOR < 5
,
NULL
#endif
);
#if LLVM_VERSION_MAJOR < 9
Function *cmplogHookFnStrN = cast<Function>(c6);
#else
FunctionCallee cmplogHookFnStrN = c6;
#endif
#if LLVM_VERSION_MAJOR < 9
Constant *
#else
FunctionCallee
#endif
c7 = M.getOrInsertFunction("__cmplog_rtn_hook_str", VoidTy, i8PtrTy,
i8PtrTy
#if LLVM_VERSION_MAJOR < 5
,
NULL
#endif
);
#if LLVM_VERSION_MAJOR < 9
Function *cmplogHookFnStr = cast<Function>(c7);
#else
FunctionCallee cmplogHookFnStr = c7;
#endif
GlobalVariable *AFLCmplogPtr = M.getNamedGlobal("__afl_cmp_map"); GlobalVariable *AFLCmplogPtr = M.getNamedGlobal("__afl_cmp_map");
if (!AFLCmplogPtr) { if (!AFLCmplogPtr) {
@ -214,12 +270,77 @@ bool CmpLogRoutines::hookRtns(Module &M) {
if (callInst->getCallingConv() != llvm::CallingConv::C) continue; if (callInst->getCallingConv() != llvm::CallingConv::C) continue;
FunctionType *FT = Callee->getFunctionType(); FunctionType *FT = Callee->getFunctionType();
std::string FuncName = Callee->getName().str();
bool isPtrRtn = FT->getNumParams() >= 2 && bool isPtrRtn = FT->getNumParams() >= 2 &&
!FT->getReturnType()->isVoidTy() && !FT->getReturnType()->isVoidTy() &&
FT->getParamType(0) == FT->getParamType(1) && FT->getParamType(0) == FT->getParamType(1) &&
FT->getParamType(0)->isPointerTy(); FT->getParamType(0)->isPointerTy();
bool isPtrRtnN = FT->getNumParams() >= 3 &&
!FT->getReturnType()->isVoidTy() &&
FT->getParamType(0) == FT->getParamType(1) &&
FT->getParamType(0)->isPointerTy() &&
FT->getParamType(2)->isIntegerTy();
bool isMemcmp =
(!FuncName.compare("memcmp") || !FuncName.compare("bcmp") ||
!FuncName.compare("CRYPTO_memcmp") ||
!FuncName.compare("OPENSSL_memcmp") ||
!FuncName.compare("memcmp_const_time") ||
!FuncName.compare("memcmpct"));
isMemcmp &= FT->getNumParams() == 3 &&
FT->getReturnType()->isIntegerTy(32) &&
FT->getParamType(0)->isPointerTy() &&
FT->getParamType(1)->isPointerTy() &&
FT->getParamType(2)->isIntegerTy();
bool isStrcmp =
(!FuncName.compare("strcmp") || !FuncName.compare("xmlStrcmp") ||
!FuncName.compare("xmlStrEqual") ||
!FuncName.compare("g_strcmp0") ||
!FuncName.compare("curl_strequal") ||
!FuncName.compare("strcsequal") ||
!FuncName.compare("strcasecmp") ||
!FuncName.compare("stricmp") ||
!FuncName.compare("ap_cstr_casecmp") ||
!FuncName.compare("OPENSSL_strcasecmp") ||
!FuncName.compare("xmlStrcasecmp") ||
!FuncName.compare("g_strcasecmp") ||
!FuncName.compare("g_ascii_strcasecmp") ||
!FuncName.compare("Curl_strcasecompare") ||
!FuncName.compare("Curl_safe_strcasecompare") ||
!FuncName.compare("cmsstrcasecmp") ||
!FuncName.compare("strstr") ||
!FuncName.compare("g_strstr_len") ||
!FuncName.compare("ap_strcasestr") ||
!FuncName.compare("xmlStrstr") ||
!FuncName.compare("xmlStrcasestr") ||
!FuncName.compare("g_str_has_prefix") ||
!FuncName.compare("g_str_has_suffix"));
isStrcmp &=
FT->getNumParams() == 2 && FT->getReturnType()->isIntegerTy(32) &&
FT->getParamType(0) == FT->getParamType(1) &&
FT->getParamType(0) == IntegerType::getInt8PtrTy(M.getContext());
bool isStrncmp = (!FuncName.compare("strncmp") ||
!FuncName.compare("xmlStrncmp") ||
!FuncName.compare("curl_strnequal") ||
!FuncName.compare("strncasecmp") ||
!FuncName.compare("strnicmp") ||
!FuncName.compare("ap_cstr_casecmpn") ||
!FuncName.compare("OPENSSL_strncasecmp") ||
!FuncName.compare("xmlStrncasecmp") ||
!FuncName.compare("g_ascii_strncasecmp") ||
!FuncName.compare("Curl_strncasecompare") ||
!FuncName.compare("g_strncasecmp"));
isStrncmp &= FT->getNumParams() == 3 &&
FT->getReturnType()->isIntegerTy(32) &&
FT->getParamType(0) == FT->getParamType(1) &&
FT->getParamType(0) ==
IntegerType::getInt8PtrTy(M.getContext()) &&
FT->getParamType(2)->isIntegerTy();
bool isGccStdStringStdString = bool isGccStdStringStdString =
Callee->getName().find("__is_charIT_EE7__value") != Callee->getName().find("__is_charIT_EE7__value") !=
std::string::npos && std::string::npos &&
@ -267,13 +388,19 @@ bool CmpLogRoutines::hookRtns(Module &M) {
*/ */
if (isGccStdStringCString || isGccStdStringStdString || if (isGccStdStringCString || isGccStdStringStdString ||
isLlvmStdStringStdString || isLlvmStdStringCString) { isLlvmStdStringStdString || isLlvmStdStringCString || isMemcmp ||
isStrcmp || isStrncmp) {
isPtrRtn = false; isPtrRtnN = isPtrRtn = false;
} }
if (isPtrRtnN) { isPtrRtn = false; }
if (isPtrRtn) { calls.push_back(callInst); } if (isPtrRtn) { calls.push_back(callInst); }
if (isMemcmp || isPtrRtnN) { Memcmp.push_back(callInst); }
if (isStrcmp) { Strcmp.push_back(callInst); }
if (isStrncmp) { Strncmp.push_back(callInst); }
if (isGccStdStringStdString) { gccStdStd.push_back(callInst); } if (isGccStdStringStdString) { gccStdStd.push_back(callInst); }
if (isGccStdStringCString) { gccStdC.push_back(callInst); } if (isGccStdStringCString) { gccStdC.push_back(callInst); }
if (isLlvmStdStringStdString) { llvmStdStd.push_back(callInst); } if (isLlvmStdStringStdString) { llvmStdStd.push_back(callInst); }
@ -288,7 +415,8 @@ bool CmpLogRoutines::hookRtns(Module &M) {
} }
if (!calls.size() && !gccStdStd.size() && !gccStdC.size() && if (!calls.size() && !gccStdStd.size() && !gccStdC.size() &&
!llvmStdStd.size() && !llvmStdC.size()) !llvmStdStd.size() && !llvmStdC.size() && !Memcmp.size() &&
Strcmp.size() && Strncmp.size())
return false; return false;
/* /*
@ -323,6 +451,93 @@ bool CmpLogRoutines::hookRtns(Module &M) {
} }
for (auto &callInst : Memcmp) {
Value *v1P = callInst->getArgOperand(0), *v2P = callInst->getArgOperand(1),
*v3P = callInst->getArgOperand(2);
IRBuilder<> IRB2(callInst->getParent());
IRB2.SetInsertPoint(callInst);
LoadInst *CmpPtr = IRB2.CreateLoad(AFLCmplogPtr);
CmpPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
auto is_not_null = IRB2.CreateICmpNE(CmpPtr, Null);
auto ThenTerm = SplitBlockAndInsertIfThen(is_not_null, callInst, false);
IRBuilder<> IRB(ThenTerm);
std::vector<Value *> args;
Value * v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
Value * v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
Value * v3Pcasted = IRB.CreateZExtOrBitCast(v3P, Int32Ty);
args.push_back(v1Pcasted);
args.push_back(v2Pcasted);
args.push_back(v3Pcasted);
IRB.CreateCall(cmplogHookFnN, args);
// errs() << callInst->getCalledFunction()->getName() << "\n";
}
for (auto &callInst : Strcmp) {
Value *v1P = callInst->getArgOperand(0), *v2P = callInst->getArgOperand(1),
*v3P = callInst->getArgOperand(2);
IRBuilder<> IRB2(callInst->getParent());
IRB2.SetInsertPoint(callInst);
LoadInst *CmpPtr = IRB2.CreateLoad(AFLCmplogPtr);
CmpPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
auto is_not_null = IRB2.CreateICmpNE(CmpPtr, Null);
auto ThenTerm = SplitBlockAndInsertIfThen(is_not_null, callInst, false);
IRBuilder<> IRB(ThenTerm);
std::vector<Value *> args;
Value * v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
Value * v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
Value * v3Pcasted = IRB.CreateZExtOrBitCast(v3P, Int32Ty);
args.push_back(v1Pcasted);
args.push_back(v2Pcasted);
args.push_back(v3Pcasted);
IRB.CreateCall(cmplogHookFnStr, args);
// errs() << callInst->getCalledFunction()->getName() << "\n";
}
for (auto &callInst : Strncmp) {
Value *v1P = callInst->getArgOperand(0), *v2P = callInst->getArgOperand(1),
*v3P = callInst->getArgOperand(2);
IRBuilder<> IRB2(callInst->getParent());
IRB2.SetInsertPoint(callInst);
LoadInst *CmpPtr = IRB2.CreateLoad(AFLCmplogPtr);
CmpPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
auto is_not_null = IRB2.CreateICmpNE(CmpPtr, Null);
auto ThenTerm = SplitBlockAndInsertIfThen(is_not_null, callInst, false);
IRBuilder<> IRB(ThenTerm);
std::vector<Value *> args;
Value * v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
Value * v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
Value * v3Pcasted = IRB.CreateZExtOrBitCast(v3P, Int32Ty);
args.push_back(v1Pcasted);
args.push_back(v2Pcasted);
args.push_back(v3Pcasted);
IRB.CreateCall(cmplogHookFnStrN, args);
// errs() << callInst->getCalledFunction()->getName() << "\n";
}
for (auto &callInst : gccStdStd) { for (auto &callInst : gccStdStd) {
Value *v1P = callInst->getArgOperand(0), *v2P = callInst->getArgOperand(1); Value *v1P = callInst->getArgOperand(0), *v2P = callInst->getArgOperand(1);

View File

@ -448,11 +448,11 @@ u8 fuzz_one_original(afl_state_t *afl) {
ACTF( ACTF(
"Fuzzing test case #%u (%u total, %llu uniq crashes found, " "Fuzzing test case #%u (%u total, %llu uniq crashes found, "
"perf_score=%0.0f, exec_us=%llu, hits=%u, map=%u)...", "perf_score=%0.0f, exec_us=%llu, hits=%u, map=%u, ascii=%u)...",
afl->current_entry, afl->queued_paths, afl->unique_crashes, afl->current_entry, afl->queued_paths, afl->unique_crashes,
afl->queue_cur->perf_score, afl->queue_cur->exec_us, afl->queue_cur->perf_score, afl->queue_cur->exec_us,
likely(afl->n_fuzz) ? afl->n_fuzz[afl->queue_cur->n_fuzz_entry] : 0, likely(afl->n_fuzz) ? afl->n_fuzz[afl->queue_cur->n_fuzz_entry] : 0,
afl->queue_cur->bitmap_size); afl->queue_cur->bitmap_size, afl->queue_cur->is_ascii);
fflush(stdout); fflush(stdout);
} }
@ -2003,11 +2003,16 @@ havoc_stage:
where we take the input file and make random stacked tweaks. */ where we take the input file and make random stacked tweaks. */
#define MAX_HAVOC_ENTRY 59 /* 55 to 60 */ #define MAX_HAVOC_ENTRY 59 /* 55 to 60 */
#define MUTATE_ASCII_DICT 64
u32 r_max, r; u32 r_max, r;
r_max = (MAX_HAVOC_ENTRY + 1) + (afl->extras_cnt ? 4 : 0) + r_max = (MAX_HAVOC_ENTRY + 1) + (afl->extras_cnt ? 4 : 0) +
(afl->a_extras_cnt ? 4 : 0); (afl->a_extras_cnt
? (unlikely(afl->cmplog_binary && afl->queue_cur->is_ascii)
? MUTATE_ASCII_DICT
: 4)
: 0);
if (unlikely(afl->expand_havoc && afl->ready_for_splicing_count > 1)) { if (unlikely(afl->expand_havoc && afl->ready_for_splicing_count > 1)) {
@ -2592,7 +2597,15 @@ havoc_stage:
if (afl->a_extras_cnt) { if (afl->a_extras_cnt) {
if (r < 2) { u32 r_cmp = 2;
if (unlikely(afl->cmplog_binary && afl->queue_cur->is_ascii)) {
r_cmp = MUTATE_ASCII_DICT >> 1;
}
if (r < r_cmp) {
/* Use the dictionary. */ /* Use the dictionary. */
@ -2612,7 +2625,7 @@ havoc_stage:
break; break;
} else if (r < 4) { } else if (r < (r_cmp << 1)) {
u32 use_extra = rand_below(afl, afl->a_extras_cnt); u32 use_extra = rand_below(afl, afl->a_extras_cnt);
u32 extra_len = afl->a_extras[use_extra].len; u32 extra_len = afl->a_extras[use_extra].len;
@ -2641,7 +2654,7 @@ havoc_stage:
} else { } else {
r -= 4; r -= (r_cmp << 1);
} }

View File

@ -315,7 +315,96 @@ void mark_as_redundant(afl_state_t *afl, struct queue_entry *q, u8 state) {
} }
/* check if ascii or UTF-8 */ /* check if pointer is ascii or UTF-8 */
u8 check_if_text_buf(u8 *buf, u32 len) {
u32 offset = 0, ascii = 0, utf8 = 0;
while (offset < len) {
// ASCII: <= 0x7F to allow ASCII control characters
if ((buf[offset + 0] == 0x09 || buf[offset + 0] == 0x0A ||
buf[offset + 0] == 0x0D ||
(0x20 <= buf[offset + 0] && buf[offset + 0] <= 0x7E))) {
offset++;
utf8++;
ascii++;
continue;
}
if (isascii((int)buf[offset]) || isprint((int)buf[offset])) {
ascii++;
// we continue though as it can also be a valid utf8
}
// non-overlong 2-byte
if (len - offset > 1 &&
((0xC2 <= buf[offset + 0] && buf[offset + 0] <= 0xDF) &&
(0x80 <= buf[offset + 1] && buf[offset + 1] <= 0xBF))) {
offset += 2;
utf8++;
continue;
}
// excluding overlongs
if ((len - offset > 2) &&
((buf[offset + 0] == 0xE0 &&
(0xA0 <= buf[offset + 1] && buf[offset + 1] <= 0xBF) &&
(0x80 <= buf[offset + 2] &&
buf[offset + 2] <= 0xBF)) || // straight 3-byte
(((0xE1 <= buf[offset + 0] && buf[offset + 0] <= 0xEC) ||
buf[offset + 0] == 0xEE || buf[offset + 0] == 0xEF) &&
(0x80 <= buf[offset + 1] && buf[offset + 1] <= 0xBF) &&
(0x80 <= buf[offset + 2] &&
buf[offset + 2] <= 0xBF)) || // excluding surrogates
(buf[offset + 0] == 0xED &&
(0x80 <= buf[offset + 1] && buf[offset + 1] <= 0x9F) &&
(0x80 <= buf[offset + 2] && buf[offset + 2] <= 0xBF)))) {
offset += 3;
utf8++;
continue;
}
// planes 1-3
if ((len - offset > 3) &&
((buf[offset + 0] == 0xF0 &&
(0x90 <= buf[offset + 1] && buf[offset + 1] <= 0xBF) &&
(0x80 <= buf[offset + 2] && buf[offset + 2] <= 0xBF) &&
(0x80 <= buf[offset + 3] &&
buf[offset + 3] <= 0xBF)) || // planes 4-15
((0xF1 <= buf[offset + 0] && buf[offset + 0] <= 0xF3) &&
(0x80 <= buf[offset + 1] && buf[offset + 1] <= 0xBF) &&
(0x80 <= buf[offset + 2] && buf[offset + 2] <= 0xBF) &&
(0x80 <= buf[offset + 3] && buf[offset + 3] <= 0xBF)) || // plane 16
(buf[offset + 0] == 0xF4 &&
(0x80 <= buf[offset + 1] && buf[offset + 1] <= 0x8F) &&
(0x80 <= buf[offset + 2] && buf[offset + 2] <= 0xBF) &&
(0x80 <= buf[offset + 3] && buf[offset + 3] <= 0xBF)))) {
offset += 4;
utf8++;
continue;
}
offset++;
}
return (utf8 > ascii ? utf8 : ascii);
}
/* check if queue entry is ascii or UTF-8 */
static u8 check_if_text(afl_state_t *afl, struct queue_entry *q) { static u8 check_if_text(afl_state_t *afl, struct queue_entry *q) {

View File

@ -278,6 +278,7 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
"total_edges : %u\n" "total_edges : %u\n"
"var_byte_count : %u\n" "var_byte_count : %u\n"
"havoc_expansion : %u\n" "havoc_expansion : %u\n"
"auto_dict_entries : %u\n"
"testcache_size : %llu\n" "testcache_size : %llu\n"
"testcache_count : %u\n" "testcache_count : %u\n"
"testcache_evict : %u\n" "testcache_evict : %u\n"
@ -316,7 +317,7 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
-1, -1,
#endif #endif
t_bytes, afl->fsrv.real_map_size, afl->var_byte_count, t_bytes, afl->fsrv.real_map_size, afl->var_byte_count,
afl->expand_havoc, afl->q_testcase_cache_size, afl->expand_havoc, afl->a_extras_cnt, afl->q_testcase_cache_size,
afl->q_testcase_cache_count, afl->q_testcase_evictions, afl->q_testcase_cache_count, afl->q_testcase_evictions,
afl->use_banner, afl->unicorn_mode ? "unicorn" : "", afl->use_banner, afl->unicorn_mode ? "unicorn" : "",
afl->fsrv.qemu_mode ? "qemu " : "", afl->fsrv.qemu_mode ? "qemu " : "",

View File

@ -2261,6 +2261,20 @@ stop_fuzzing:
} }
if (afl->not_on_tty) {
u32 t_bytes = count_non_255_bytes(afl, afl->virgin_bits);
u8 time_tmp[64];
u_stringify_time_diff(time_tmp, get_cur_time(), afl->start_time);
ACTF(
"Statistics: %u new paths found, %.02f%% coverage achieved, %llu "
"crashes found, %llu timeouts found, total runtime %s",
afl->queued_discovered,
((double)t_bytes * 100) / afl->fsrv.real_map_size, afl->unique_crashes,
afl->unique_hangs, time_tmp);
}
#ifdef PROFILING #ifdef PROFILING
SAYF(cYEL "[!] " cRST SAYF(cYEL "[!] " cRST
"Profiling information: %llu ms total work, %llu ns/run\n", "Profiling information: %llu ms total work, %llu ns/run\n",