Skip to content

Commit c63bb30

Browse files
author
Kaipeng Zeng
committed
Attach kernel instument code
1 parent 5e57b9d commit c63bb30

File tree

5 files changed

+264
-2
lines changed

5 files changed

+264
-2
lines changed
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
#include <llvm/IR/LegacyPassManager.h>
2+
#include <llvm/Transforms/IPO/PassManagerBuilder.h>
3+
#include <llvm/IR/Module.h>
4+
#include <llvm/IR/Value.h>
5+
#include <llvm/IR/Type.h>
6+
#include <llvm/IR/Operator.h>
7+
#include <llvm/IR/Instructions.h>
8+
#include <llvm/IR/InstrTypes.h>
9+
#include <llvm/Bitcode/BitcodeWriter.h>
10+
11+
#include "llvm/IR/LegacyPassManager.h"
12+
#include "llvm/IR/CallSite.h"
13+
#include "llvm/IR/IRBuilder.h"
14+
#include "llvm/IR/InlineAsm.h"
15+
#include "llvm/ADT/Statistic.h"
16+
#include "llvm/IR/Function.h"
17+
#include "llvm/Pass.h"
18+
#include "llvm/Support/raw_ostream.h"
19+
20+
21+
using namespace llvm;
22+
using namespace legacy;
23+
24+
static const char *const SanCovTraceSrt1Name = "__sanitizer_cov_trace_srt1";
25+
static const char *const SanCovTraceSrt2Name = "__sanitizer_cov_trace_srt2";
26+
static const char *const SanCovTraceSrt4Name = "__sanitizer_cov_trace_srt4";
27+
static const char *const SanCovTraceSrt8Name = "__sanitizer_cov_trace_srt8";
28+
29+
namespace {
30+
struct AssignTracker : public ModulePass {
31+
static char ID; // Pass identification, replacement for typeid
32+
FunctionCallee SanCovTraceSrt1;
33+
FunctionCallee SanCovTraceSrt2;
34+
FunctionCallee SanCovTraceSrt4;
35+
FunctionCallee SanCovTraceSrt8;
36+
Type *VoidTy;
37+
Type *Int8Ty;
38+
Type *Int16Ty;
39+
Type *Int32Ty;
40+
Type *Int64Ty;
41+
std::hash<std::string> hashSrt;
42+
std::map<std::string, unsigned> StructIDMap;
43+
44+
LLVMContext *C;
45+
AssignTracker() : ModulePass(ID) {}
46+
47+
bool runOnModule(Module &M) override {
48+
C = &M.getContext();
49+
IRBuilder<> IRB(*C);
50+
51+
VoidTy = IRB.getVoidTy();
52+
Int8Ty = IRB.getInt8Ty();
53+
Int16Ty = IRB.getInt16Ty();
54+
Int32Ty = IRB.getInt32Ty();
55+
Int64Ty = IRB.getInt64Ty();
56+
57+
SanCovTraceSrt1 = M.getOrInsertFunction(SanCovTraceSrt1Name, VoidTy, Int32Ty, Int8Ty);
58+
SanCovTraceSrt2 = M.getOrInsertFunction(SanCovTraceSrt2Name, VoidTy, Int32Ty, Int16Ty);
59+
SanCovTraceSrt4 = M.getOrInsertFunction(SanCovTraceSrt4Name, VoidTy, Int32Ty, Int32Ty);
60+
SanCovTraceSrt8 = M.getOrInsertFunction(SanCovTraceSrt8Name, VoidTy, Int32Ty, Int64Ty);
61+
62+
for (Function &F : M)
63+
instrumentFieldAssign(F);
64+
for (auto i : StructIDMap) {
65+
errs() << i.first << ": " << std::to_string(i.second) << "\n";
66+
}
67+
return true;
68+
}
69+
void injectFieldAssignTracker(Instruction *I, unsigned id);
70+
void instrumentFieldAssign(Function &func);
71+
};
72+
}
73+
74+
std::string stripNum(std::string name) {
75+
size_t len = name.size();
76+
char tmp[len];
77+
strncpy(tmp, name.c_str(), len);
78+
if (len < 1)
79+
return name;
80+
while ((tmp[len-1] <= '9' && tmp[len-1] >= '0' && len > 1)
81+
|| (tmp[len-1] == 'i' && tmp[len-2] == '.' && len > 2)
82+
|| (tmp[len-1] == '.' && len > 1)) {
83+
if (tmp[len-1] == 'i' && tmp[len-2] == '.') {
84+
tmp[len-1] = 0;
85+
tmp[len-2] = 0;
86+
len -= 2;
87+
continue;
88+
}
89+
tmp[len-1] = 0;
90+
len--;
91+
}
92+
name = name.substr(0, len);
93+
return name;
94+
95+
;
96+
}
97+
98+
void AssignTracker::instrumentFieldAssign(Function &func) {
99+
if (!func.size())
100+
return;
101+
for (BasicBlock &bb : func) {
102+
for (Instruction &i : bb) {
103+
if (StoreInst *si = dyn_cast<StoreInst>(&i)) {
104+
const Value *val_op = si->getOperand(0);
105+
const Value *var_op = si->getPointerOperand();
106+
if (!val_op->getType()->isIntegerTy())
107+
continue;
108+
if (const GEPOperator *gep = dyn_cast<GEPOperator>(var_op)) {
109+
const Value *intPtr = gep->getPointerOperand();
110+
if (Type *gepOpTy = dyn_cast<PointerType>(intPtr->getType())->getElementType()) {
111+
if (gepOpTy->isStructTy()) {
112+
std::string srtName = gepOpTy->getStructName();
113+
std::string fieldName = var_op->getName();
114+
std::string key = stripNum(srtName) + "->" + stripNum(fieldName);
115+
if (StructIDMap.find(key) == StructIDMap.end())
116+
StructIDMap[key] = hashSrt(key);
117+
injectFieldAssignTracker(si, StructIDMap[key]);
118+
}
119+
}
120+
}
121+
}
122+
}
123+
}
124+
}
125+
126+
void AssignTracker::injectFieldAssignTracker(Instruction *I, unsigned id) {
127+
IRBuilder<> IRB(I);
128+
Value *val = I->getOperand(0);
129+
unsigned bitWidth = val->getType()->getIntegerBitWidth();
130+
switch (bitWidth) {
131+
case 8: {
132+
IRB.CreateCall(SanCovTraceSrt1, {IRB.getInt32(id), IRB.CreateIntCast(val, Int8Ty, true)});
133+
break;
134+
}
135+
case 16: {
136+
IRB.CreateCall(SanCovTraceSrt2, {IRB.getInt32(id), IRB.CreateIntCast(val, Int16Ty, true)});
137+
break;
138+
}
139+
case 32: {
140+
IRB.CreateCall(SanCovTraceSrt4, {IRB.getInt32(id), IRB.CreateIntCast(val, Int32Ty, true)});
141+
break;
142+
}
143+
case 64: {
144+
IRB.CreateCall(SanCovTraceSrt8, {IRB.getInt32(id), IRB.CreateIntCast(val, Int64Ty, true)});
145+
break;
146+
}
147+
}
148+
}
149+
150+
char AssignTracker::ID = 0;
151+
static RegisterPass<AssignTracker> X("AssignTracker", "AssignTracker Pass", false, false);
152+
153+
static void registerAssignTrackerPass(const PassManagerBuilder &, legacy::PassManagerBase &PM)
154+
{
155+
PM.add(new AssignTracker());
156+
}
157+
158+
static RegisterStandardPasses RegisterAPass(PassManagerBuilder::EP_OptimizerLast, registerAssignTrackerPass);

static_analysis_tools/kern_instrument/AssignTrackerPass/AssignTracker.exports

Whitespace-only changes.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# If we don't need RTTI or EH, there's no reason to export anything
2+
# from the hello plugin.
3+
if( NOT LLVM_REQUIRES_RTTI )
4+
if( NOT LLVM_REQUIRES_EH )
5+
set(LLVM_EXPORTED_SYMBOL_FILE ${CMAKE_CURRENT_SOURCE_DIR}/AssignTracker.exports)
6+
endif()
7+
endif()
8+
9+
if(WIN32 OR CYGWIN)
10+
set(LLVM_LINK_COMPONENTS Core Support)
11+
endif()
12+
13+
add_llvm_library( LLVMAssignTracker MODULE BUILDTREE_ONLY
14+
AssignTracker.cpp
15+
16+
DEPENDS
17+
intrinsics_gen
18+
PLUGIN_TOOL
19+
opt
20+
)
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
From a756fae764d6f6d316467ff9eeec7c4dfb4f22cc Mon Sep 17 00:00:00 2001
2+
From: bins <bins@kp-test>
3+
Date: Wed, 10 Jun 2020 02:48:56 -0400
4+
Subject: [PATCH] KCOV_SRT_TRACK ok
5+
6+
---
7+
kernel/kcov.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++
8+
1 file changed, 61 insertions(+)
9+
10+
diff --git a/kernel/kcov.c b/kernel/kcov.c
11+
index f50354202..e2fd7c405 100644
12+
--- a/kernel/kcov.c
13+
+++ b/kernel/kcov.c
14+
@@ -312,6 +312,67 @@ void notrace __sanitizer_cov_trace_switch(u64 val, u64 *cases)
15+
EXPORT_SYMBOL(__sanitizer_cov_trace_switch);
16+
#endif /* ifdef CONFIG_KCOV_ENABLE_COMPARISONS */
17+
18+
+static void notrace write_srt_data(u64 id, u64 val, u64 ip)
19+
+{
20+
+ struct task_struct *t;
21+
+ u64 *area;
22+
+ u64 count, start_index, end_pos, max_pos;
23+
+
24+
+ t = current;
25+
+
26+
+ if (!check_kcov_mode(KCOV_MODE_TRACE_PC, t))
27+
+ return;
28+
+
29+
+ ip = canonicalize_ip(ip);
30+
+
31+
+ area = (u64 *)t->kcov_area;
32+
+ max_pos = t->kcov_size * sizeof(unsigned long);
33+
+
34+
+ count = READ_ONCE(area[0]);
35+
+
36+
+ /* Every record is KCOV_WORDS_PER_STRU 64-bit words. */
37+
+ start_index = 1 + count;
38+
+ end_pos = (start_index + 3) * sizeof(u64);
39+
+ if (likely(end_pos <= max_pos)) {
40+
+ area[start_index] = id;
41+
+ area[start_index + 1] = val;
42+
+ area[start_index + 2] = ip;
43+
+ WRITE_ONCE(area[0], count + 3);
44+
+ }
45+
+}
46+
+
47+
+void notrace __sanitizer_cov_trace_srt1(u32 id, u8 val)
48+
+{
49+
+ u64 id_64 = ((u64)0xfefe000f << 32) | (u64)id;
50+
+ u64 val_64 = (u64)val;
51+
+ write_srt_data(id_64, val_64, _RET_IP_);
52+
+}
53+
+EXPORT_SYMBOL(__sanitizer_cov_trace_srt1);
54+
+
55+
+void notrace __sanitizer_cov_trace_srt2(u32 id, u16 val)
56+
+{
57+
+ u64 id_64 = ((u64)0xfefe00f0 << 32) | (u64)id;
58+
+ u64 val_64 = (u64)val;
59+
+ write_srt_data(id_64, val_64, _RET_IP_);
60+
+}
61+
+EXPORT_SYMBOL(__sanitizer_cov_trace_srt2);
62+
+
63+
+void notrace __sanitizer_cov_trace_srt4(u32 id, u32 val)
64+
+{
65+
+ u64 id_64 = ((u64)0xfefe0f00 << 32)| (u64)id;
66+
+ u64 val_64 = (u64)val;
67+
+ write_srt_data(id_64, val_64, _RET_IP_);
68+
+}
69+
+EXPORT_SYMBOL(__sanitizer_cov_trace_srt4);
70+
+
71+
+void notrace __sanitizer_cov_trace_srt8(u32 id, u64 val)
72+
+{
73+
+ u64 id_64 = ((u64)0xfefef000 << 32) | (u64)id;
74+
+ u64 val_64 = (u64)val;
75+
+ write_srt_data(id_64, val_64, _RET_IP_);
76+
+}
77+
+EXPORT_SYMBOL(__sanitizer_cov_trace_srt8);
78+
+
79+
static void kcov_start(struct task_struct *t, unsigned int size,
80+
void *area, enum kcov_mode mode, int sequence)
81+
{
82+
--
83+
2.20.1
84+

syzkaller/kstate_resource.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,15 @@ To implement collect kernel states as syzkaller resource, we have to follow the
1616

1717
### Kernel instrument
1818

19-
First, we need to implement a LLVM pass to do instrument. While we already knew, lots of states of kernel are located in some field of structure. Tracking the store operation of a variable of GEPointer can detect states which may help to fuzzer. Then, refer to [this document](https://llvm.org/docs/WritingAnLLVMPass.html) to build you compiler with field assignment tracker. While building kernel, you have to add line such like:
19+
First, we need to implement a [LLVM pass](../static_analysis_tools/kern_instrument/AssignTrackerPass) to do instrument. While we already knew, lots of states of kernel are located in some field of structure. Tracking the store operation of a variable of GEPointer can detect states which may help to fuzzer. Then, refer to [this document](https://llvm.org/docs/WritingAnLLVMPass.html) to build you compiler with field assignment tracker. While building kernel, you have to add line such like:
2020
```
2121
CFLAGS_*.o = -Xclang -load -Xclang PATH_TO_YOUR_PASS.so -fno-discard-value-names
2222
```
2323
to Makefile for the object file you need to instrument it. The kernel state id is the hash of structure name and field name.
2424

2525
### Implement the instrument function in kernel
2626

27-
Refer to our [implement](../instrument/kcov_trace_srt.patch) of instrument to collect kernel state. Then, build your kernel as usual.
27+
Refer to our [implement](../static_analysis_tools/kern_instrument/kern_patch) of instrument to collect kernel state. Then, build your kernel as usual.
2828

2929
### Patch syzkaller
3030

0 commit comments

Comments
 (0)