cmplog routines update & fix (#1592)

* update

* runtime

* Update cmplog-routines-pass.cc (#1589)

* rtm

* fix

* no link rt

* fmt

* let's change script in another pr

* colon

* adjust the checks

* fix

* more fixes

* FMT
This commit is contained in:
Dongjia "toka" Zhang 2023-10-02 06:06:34 +02:00 committed by GitHub
parent 5854fd0c5b
commit 583c84ab4e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 339 additions and 22 deletions

View File

@ -170,14 +170,17 @@ llvmGetPassPluginInfo() {
#else
char CmpLogRoutines::ID = 0;
#endif
#include <iostream>
bool CmpLogRoutines::hookRtns(Module &M) {
std::vector<CallInst *> calls, llvmStdStd, llvmStdC, gccStdStd, gccStdC;
LLVMContext &C = M.getContext();
std::vector<CallInst *> calls, llvmStdStd, llvmStdC, gccStdStd, gccStdC,
Memcmp, Strcmp, Strncmp;
LLVMContext &C = M.getContext();
Type *VoidTy = Type::getVoidTy(C);
// PointerType *VoidPtrTy = PointerType::get(VoidTy, 0);
IntegerType *Int8Ty = IntegerType::getInt8Ty(C);
IntegerType *Int64Ty = IntegerType::getInt64Ty(C);
PointerType *i8PtrTy = PointerType::get(Int8Ty, 0);
#if LLVM_VERSION_MAJOR < 9
@ -269,6 +272,60 @@ bool CmpLogRoutines::hookRtns(Module &M) {
FunctionCallee cmplogGccStdC = c4;
#endif
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee
#else
Constant *
#endif
c5 = M.getOrInsertFunction("__cmplog_rtn_hook_n", VoidTy, i8PtrTy,
i8PtrTy, Int64Ty
#if LLVM_VERSION_MAJOR < 5
,
NULL
#endif
);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee cmplogHookFnN = c5;
#else
Function *cmplogHookFnN = cast<Function>(c5);
#endif
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee
#else
Constant *
#endif
c6 = M.getOrInsertFunction("__cmplog_rtn_hook_strn", VoidTy, i8PtrTy,
i8PtrTy, Int64Ty
#if LLVM_VERSION_MAJOR < 5
,
NULL
#endif
);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee cmplogHookFnStrN = c6;
#else
Function *cmplogHookFnStrN = cast<Function>(c6);
#endif
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee
#else
Constant *
#endif
c7 = M.getOrInsertFunction("__cmplog_rtn_hook_str", VoidTy, i8PtrTy,
i8PtrTy
#if LLVM_VERSION_MAJOR < 5
,
NULL
#endif
);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee cmplogHookFnStr = c7;
#else
Function *cmplogHookFnStr = cast<Function>(c7);
#endif
/* iterate over all functions, bbs and instruction and add suitable calls */
for (auto &F : M) {
if (isIgnoreFunction(&F)) { continue; }
@ -283,12 +340,87 @@ bool CmpLogRoutines::hookRtns(Module &M) {
if (callInst->getCallingConv() != llvm::CallingConv::C) { continue; }
FunctionType *FT = Callee->getFunctionType();
std::string FuncName = Callee->getName().str();
bool isPtrRtn = FT->getNumParams() >= 2 &&
!FT->getReturnType()->isVoidTy() &&
FT->getParamType(0) == FT->getParamType(1) &&
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();
if (isPtrRtnN) {
auto intTyOp =
dyn_cast<IntegerType>(callInst->getArgOperand(2)->getType());
if (intTyOp) {
if (intTyOp->getBitWidth() != 32 &&
intTyOp->getBitWidth() != 64) {
isPtrRtnN = false;
}
}
}
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 =
Callee->getName().find("__is_charIT_EE7__value") !=
std::string::npos &&
@ -336,11 +468,17 @@ bool CmpLogRoutines::hookRtns(Module &M) {
*/
if (isGccStdStringCString || isGccStdStringStdString ||
isLlvmStdStringStdString || isLlvmStdStringCString) {
isPtrRtn = false;
isLlvmStdStringStdString || isLlvmStdStringCString || isMemcmp ||
isStrcmp || isStrncmp) {
isPtrRtnN = isPtrRtn = false;
}
if (isPtrRtnN) { isPtrRtn = false; }
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 (isGccStdStringCString) { gccStdC.push_back(callInst); }
if (isLlvmStdStringStdString) { llvmStdStd.push_back(callInst); }
@ -351,9 +489,9 @@ bool CmpLogRoutines::hookRtns(Module &M) {
}
if (!calls.size() && !gccStdStd.size() && !gccStdC.size() &&
!llvmStdStd.size() && !llvmStdC.size()) {
!llvmStdStd.size() && !llvmStdC.size() && !Memcmp.size() &&
Strcmp.size() && Strncmp.size())
return false;
}
for (auto &callInst : calls) {
Value *v1P = callInst->getArgOperand(0), *v2P = callInst->getArgOperand(1);
@ -372,6 +510,67 @@ bool CmpLogRoutines::hookRtns(Module &M) {
// errs() << callInst->getCalledFunction()->getName() << "\n";
}
for (auto &callInst : Memcmp) {
Value *v1P = callInst->getArgOperand(0), *v2P = callInst->getArgOperand(1),
*v3P = callInst->getArgOperand(2);
IRBuilder<> IRB(callInst->getParent());
IRB.SetInsertPoint(callInst);
std::vector<Value *> args;
Value *v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
Value *v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
Value *v3Pbitcast = IRB.CreateBitCast(
v3P, IntegerType::get(C, v3P->getType()->getPrimitiveSizeInBits()));
Value *v3Pcasted =
IRB.CreateIntCast(v3Pbitcast, IntegerType::get(C, 64), false);
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);
IRBuilder<> IRB(callInst->getParent());
IRB.SetInsertPoint(callInst);
std::vector<Value *> args;
Value *v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
Value *v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
args.push_back(v1Pcasted);
args.push_back(v2Pcasted);
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<> IRB(callInst->getParent());
IRB.SetInsertPoint(callInst);
std::vector<Value *> args;
Value *v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
Value *v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
Value *v3Pbitcast = IRB.CreateBitCast(
v3P, IntegerType::get(C, v3P->getType()->getPrimitiveSizeInBits()));
Value *v3Pcasted =
IRB.CreateIntCast(v3Pbitcast, IntegerType::get(C, 64), false);
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) {
Value *v1P = callInst->getArgOperand(0), *v2P = callInst->getArgOperand(1);

View File

@ -16,6 +16,24 @@ void __cmplog_rtn_hook(uint8_t *ptr1, uint8_t *ptr2) {
(void)ptr2;
}
void __cmplog_rtn_hook_n(const uint8_t *ptr1, const uint8_t *ptr2,
uint64_t len) {
(void)ptr1;
(void)ptr2;
(void)len;
}
void __cmplog_rtn_hook_str(const uint8_t *ptr1, uint8_t *ptr2) {
(void)ptr1;
(void)ptr2;
}
void __cmplog_rtn_hook_strn(uint8_t *ptr1, uint8_t *ptr2, uint64_t len) {
(void)ptr1;
(void)ptr2;
(void)len;
}
void __cmplog_rtn_gcc_stdstring_cstring(uint8_t *stdstring, uint8_t *cstring) {
(void)stdstring;
(void)cstring;

View File

@ -3,6 +3,7 @@
#define CMPLOG_MODULE
#include "common.h"
#include "cmplog.h"
#include <string.h>
#if defined(_WIN32)
@ -92,6 +93,7 @@ static long area_is_valid(const void *ptr, size_t len) {
}
}
// cmplog routines after area check
void __libafl_targets_cmplog_routines_checked(uintptr_t k, const uint8_t *ptr1,
const uint8_t *ptr2, size_t len) {
libafl_cmplog_enabled = false;
@ -105,7 +107,8 @@ void __libafl_targets_cmplog_routines_checked(uintptr_t k, const uint8_t *ptr1,
} else {
hits = libafl_cmplog_map_ptr->headers[k].hits++;
if (libafl_cmplog_map_ptr->headers[k].shape < len) {
libafl_cmplog_map_ptr->headers[k].shape = len;
libafl_cmplog_map_ptr->headers[k].shape =
len; // TODO; adjust len for AFL++'s cmplog protocol
}
}
@ -115,6 +118,7 @@ void __libafl_targets_cmplog_routines_checked(uintptr_t k, const uint8_t *ptr1,
libafl_cmplog_enabled = true;
}
// Very generic cmplog routines callback
void __libafl_targets_cmplog_routines(uintptr_t k, const uint8_t *ptr1,
const uint8_t *ptr2) {
if (!libafl_cmplog_enabled) { return; }
@ -129,6 +133,7 @@ void __libafl_targets_cmplog_routines(uintptr_t k, const uint8_t *ptr1,
__libafl_targets_cmplog_routines_checked(k, ptr1, ptr2, len);
}
// cmplog routines but with len specified
void __libafl_targets_cmplog_routines_len(uintptr_t k, const uint8_t *ptr1,
const uint8_t *ptr2, size_t len) {
if (!libafl_cmplog_enabled) { return; }
@ -149,6 +154,58 @@ void __cmplog_rtn_hook(const uint8_t *ptr1, const uint8_t *ptr2) {
__libafl_targets_cmplog_routines(k, ptr1, ptr2);
}
void __cmplog_rtn_hook_n(const uint8_t *ptr1, const uint8_t *ptr2,
uint64_t len) {
(void)(len);
__cmplog_rtn_hook(ptr1, ptr2);
}
/* hook for string functions, eg. strcmp, strcasecmp etc. */
void __cmplog_rtn_hook_str(const uint8_t *ptr1, uint8_t *ptr2) {
if (!libafl_cmplog_enabled) { return; }
if (unlikely(!ptr1 || !ptr2)) return;
// these strnlen could indeed fail. but if it fails here it will sigsegv in the following hooked function call anyways
int len1 = strnlen(ptr1, 30) + 1;
int len2 = strnlen(ptr2, 30) + 1;
int l = MAX(len1, len2);
l = MIN(l, area_is_valid(ptr1, l + 1)); // can we really access it? check
l = MIN(l, area_is_valid(ptr2, l + 1)); // can we really access it? check
if (l < 2) return;
intptr_t k = RETADDR;
k = (k >> 4) ^ (k << 8);
k &= CMPLOG_MAP_W - 1;
__libafl_targets_cmplog_routines_checked(k, ptr1, ptr2, l);
}
/* hook for string with length functions, eg. strncmp, strncasecmp etc.
Note that we ignore the len parameter and take longer strings if present. */
void __cmplog_rtn_hook_strn(uint8_t *ptr1, uint8_t *ptr2, uint64_t len) {
if (!libafl_cmplog_enabled) { return; }
if (unlikely(!ptr1 || !ptr2)) return;
int len0 = MIN(len, 31); // cap by 31
// these strnlen could indeed fail. but if it fails here it will sigsegv in the following hooked function call anyways
int len1 = strnlen(ptr1, len0);
int len2 = strnlen(ptr2, len0);
int l = MAX(len1, len2);
l = MIN(l, area_is_valid(ptr1, l + 1)); // can we really access it? check
l = MIN(l, area_is_valid(ptr2, l + 1)); // can we really access it? check
if (l < 2) return;
intptr_t k = RETADDR;
k = (k >> 4) ^ (k << 8);
k &= CMPLOG_MAP_W - 1;
__libafl_targets_cmplog_routines_checked(k, ptr1, ptr2, l);
}
// gcc libstdc++
// _ZNKSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE7compareEPKc
static const uint8_t *get_gcc_stdstring(const uint8_t *string) {
@ -179,39 +236,66 @@ static const uint8_t *get_llvm_stdstring(const uint8_t *string) {
void __cmplog_rtn_gcc_stdstring_cstring(const uint8_t *stdstring,
const uint8_t *cstring) {
if (!libafl_cmplog_enabled) { return; }
if (area_is_valid(stdstring, 32) <= 0) { return; }
int l1 = area_is_valid(stdstring, 32);
if (l1 <= 0) { return; }
int l2 = area_is_valid(cstring, 32);
if (l2 <= 0) { return; }
__cmplog_rtn_hook(get_gcc_stdstring(stdstring), cstring);
int len = MIN(31, MIN(l1, l2));
uintptr_t k = RETADDR;
k = (k >> 4) ^ (k << 8);
k &= CMPLOG_MAP_W - 1;
__libafl_targets_cmplog_routines_checked(k, get_gcc_stdstring(stdstring),
cstring, len);
}
void __cmplog_rtn_gcc_stdstring_stdstring(const uint8_t *stdstring1,
const uint8_t *stdstring2) {
if (!libafl_cmplog_enabled) { return; }
if (area_is_valid(stdstring1, 32) <= 0 ||
area_is_valid(stdstring2, 32) <= 0) {
return;
}
int l1 = area_is_valid(stdstring1, 32);
if (l1 <= 0) { return; }
int l2 = area_is_valid(stdstring2, 32);
if (l2 <= 0) { return; }
__cmplog_rtn_hook(get_gcc_stdstring(stdstring1),
get_gcc_stdstring(stdstring2));
int len = MIN(31, MIN(l1, l2));
uintptr_t k = RETADDR;
k = (k >> 4) ^ (k << 8);
k &= CMPLOG_MAP_W - 1;
__libafl_targets_cmplog_routines_checked(k, get_gcc_stdstring(stdstring1),
get_gcc_stdstring(stdstring2), len);
}
void __cmplog_rtn_llvm_stdstring_cstring(const uint8_t *stdstring,
const uint8_t *cstring) {
if (!libafl_cmplog_enabled) { return; }
if (area_is_valid(stdstring, 32) <= 0) { return; }
int l1 = area_is_valid(stdstring, 32);
if (l1 <= 0) { return; }
int l2 = area_is_valid(cstring, 32);
if (l2 <= 0) { return; }
__cmplog_rtn_hook(get_llvm_stdstring(stdstring), cstring);
int len = MIN(31, MIN(l1, l2));
uintptr_t k = RETADDR;
k = (k >> 4) ^ (k << 8);
k &= CMPLOG_MAP_W - 1;
__libafl_targets_cmplog_routines_checked(k, get_llvm_stdstring(stdstring),
cstring, len);
}
void __cmplog_rtn_llvm_stdstring_stdstring(const uint8_t *stdstring1,
const uint8_t *stdstring2) {
if (!libafl_cmplog_enabled) { return; }
if (area_is_valid(stdstring1, 32) <= 0 ||
area_is_valid(stdstring2, 32) <= 0) {
return;
}
int l1 = area_is_valid(stdstring1, 32);
if (l1 <= 0) { return; }
int l2 = area_is_valid(stdstring2, 32);
if (l2 <= 0) { return; }
__cmplog_rtn_hook(get_llvm_stdstring(stdstring1),
get_llvm_stdstring(stdstring2));
int len = MIN(31, MIN(l1, l2));
uintptr_t k = RETADDR;
k = (k >> 4) ^ (k << 8);
k &= CMPLOG_MAP_W - 1;
__libafl_targets_cmplog_routines_checked(k, get_llvm_stdstring(stdstring1),
get_llvm_stdstring(stdstring2), len);
}

View File

@ -46,6 +46,22 @@
#define EXPORT_FN
#endif
#if __GNUC__ < 6
#ifndef likely
#define likely(_x) (_x)
#endif
#ifndef unlikely
#define unlikely(_x) (_x)
#endif
#else
#ifndef likely
#define likely(_x) __builtin_expect(!!(_x), 1)
#endif
#ifndef unlikely
#define unlikely(_x) __builtin_expect(!!(_x), 0)
#endif
#endif
#ifdef __GNUC__
#define MAX(a, b) \
({ \