Skip to content

Commit dbeeb6f

Browse files
authored
Fix taint analysis with sret (#810)
* Prevent summary-FF to be generated for arbitrary calls with sret * Add unittest to catch fixed issue
1 parent ed815a2 commit dbeeb6f

4 files changed

Lines changed: 58 additions & 10 deletions

File tree

lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.cpp

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,11 @@ transferAndKillTwoFlows(d_t To, d_t From1, d_t From2) {
266266
auto IFDSTaintAnalysis::getNormalFlowFunction(n_t Curr,
267267
[[maybe_unused]] n_t Succ)
268268
-> FlowFunctionPtrType {
269+
PHASAR_LOG_LEVEL_CAT(DEBUG, "IFDSTaintAnalysis",
270+
"getNormalFlowFunction: " << llvmIRToString(Curr)
271+
<< " --> "
272+
<< llvmIRToString(Succ));
273+
269274
// If a tainted value is stored, the store location must be tainted too
270275
if (const auto *Store = llvm::dyn_cast<llvm::StoreInst>(Curr)) {
271276
container_type Gen;
@@ -396,14 +401,6 @@ auto IFDSTaintAnalysis::getSummaryFlowFunction([[maybe_unused]] n_t CallSite,
396401
// populateWithMayAliases(Leak, CallSite);
397402
populateWithMustAliases(Kill, CallSite);
398403

399-
if (CS->hasStructRetAttr()) {
400-
const auto *SRet = CS->getArgOperand(0);
401-
if (!Gen.count(SRet)) {
402-
// SRet is guaranteed to be written to by the call. If it does not
403-
// generate it, we can freely kill it
404-
Kill.insert(SRet);
405-
}
406-
}
407404
if (Gen.empty() && Leak.empty() && Kill.empty()) {
408405
if (Llvmfdff.contains(DestFun)) {
409406
// Note: The LLVMfdff is constant during the lifetime of the analysis, so
@@ -437,6 +434,15 @@ auto IFDSTaintAnalysis::getSummaryFlowFunction([[maybe_unused]] n_t CallSite,
437434
// not found
438435
return nullptr;
439436
}
437+
438+
if (CS->hasStructRetAttr()) {
439+
const auto *SRet = CS->getArgOperand(0);
440+
if (!Gen.count(SRet)) {
441+
// SRet is guaranteed to be written to by the call. If it does not
442+
// generate it, we can freely kill it
443+
Kill.insert(SRet);
444+
}
445+
}
440446
if (Gen.empty()) {
441447
if (!Leak.empty() || !Kill.empty()) {
442448
return lambdaFlow([Leak{std::move(Leak)}, Kill{std::move(Kill)}, this,

test/llvm_test_code/taint_analysis/dummy_source_sink/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ set(taint_tests
1515
taint_exception_09.cpp
1616
taint_exception_10.cpp
1717
taint_lib_sum_01.cpp
18+
sret.c
1819
)
1920

2021
set(taint_tests_mem2reg
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#include <stdio.h>
2+
3+
extern char *source(void); // dummy source
4+
extern void sink(char c); // dummy sink
5+
6+
typedef struct {
7+
char data[64];
8+
int x;
9+
} BigStruct;
10+
11+
BigStruct get_data(char *input) {
12+
BigStruct s;
13+
s.data[0] = input[0];
14+
s.x = 42;
15+
return s;
16+
}
17+
18+
int main() {
19+
char *tainted = source();
20+
BigStruct bs = get_data(tainted); // sret call
21+
sink(bs.data[0]); // Should be flagged as leak!
22+
return 0;
23+
}

unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysisTest.cpp

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,18 @@ class IFDSTaintAnalysisTest : public ::testing::Test {
3434
std::optional<IFDSTaintAnalysis> TaintProblem;
3535
std::optional<LLVMTaintConfig> TSF;
3636

37+
static bool isDummySrcFun(llvm::StringRef Name) {
38+
return Name == "_Z6sourcev" || Name == "source";
39+
}
40+
static bool isDummySinkFun(llvm::StringRef Name) {
41+
return Name == "_Z4sinki" || Name == "sink";
42+
}
3743
static LLVMTaintConfig getDefaultConfig() {
3844
auto SourceCB = [](const llvm::Instruction *Inst) {
3945
std::set<const llvm::Value *> Ret;
4046
if (const auto *Call = llvm::dyn_cast<llvm::CallBase>(Inst);
4147
Call && Call->getCalledFunction() &&
42-
Call->getCalledFunction()->getName() == "_Z6sourcev") {
48+
isDummySrcFun(Call->getCalledFunction()->getName())) {
4349
Ret.insert(Call);
4450
}
4551
return Ret;
@@ -48,7 +54,7 @@ class IFDSTaintAnalysisTest : public ::testing::Test {
4854
std::set<const llvm::Value *> Ret;
4955
if (const auto *Call = llvm::dyn_cast<llvm::CallBase>(Inst);
5056
Call && Call->getCalledFunction() &&
51-
Call->getCalledFunction()->getName() == "_Z4sinki") {
57+
isDummySinkFun(Call->getCalledFunction()->getName())) {
5258
assert(Call->arg_size() > 0);
5359
Ret.insert(Call->getArgOperand(0));
5460
}
@@ -193,6 +199,18 @@ TEST_F(IFDSTaintAnalysisTest, TaintTest_06) {
193199
compare(TaintProblem->Leaks, GroundTruth);
194200
}
195201

202+
TEST_F(IFDSTaintAnalysisTest, SRetTest_01) {
203+
initialize({PathToLlFiles + "dummy_source_sink/sret_c_dbg.ll"});
204+
IFDSSolver TaintSolver(*TaintProblem, &HA->getICFG());
205+
TaintSolver.solve();
206+
207+
auto SinkCall = LineColFun{21, 3, "main"};
208+
auto BsdataAt0 = LineColFunOp{21, 8, "main", llvm::Instruction::Load};
209+
GroundTruthTy GroundTruth{{SinkCall, {BsdataAt0}}};
210+
211+
compare(TaintProblem->Leaks, GroundTruth);
212+
}
213+
196214
TEST_F(IFDSTaintAnalysisTest, TaintTest_ExceptionHandling_01) {
197215
initialize(
198216
{PathToLlFiles + "dummy_source_sink/taint_exception_01_cpp_dbg.ll"});

0 commit comments

Comments
 (0)