Skip to content

Commit b099e1e

Browse files
author
Balazs Benics
committed
[analyzer] Fix taint propagation by remembering to the location context
Fixes the issue D118987 by mapping the propagation to the callsite's LocationContext. This way we can keep track of the in-flight propagations. Note that empty propagation sets won't be inserted. Reviewed By: NoQ, Szelethus Differential Revision: https://reviews.llvm.org/D119128
1 parent 744745a commit b099e1e

File tree

2 files changed

+32
-22
lines changed

2 files changed

+32
-22
lines changed

clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ using namespace clang;
3838
using namespace ento;
3939
using namespace taint;
4040

41+
using llvm::ImmutableSet;
42+
4143
namespace {
4244

4345
class GenericTaintChecker;
@@ -434,7 +436,9 @@ template <> struct ScalarEnumerationTraits<TaintConfiguration::VariadicType> {
434436
/// to the call post-visit. The values are signed integers, which are either
435437
/// ReturnValueIndex, or indexes of the pointer/reference argument, which
436438
/// points to data, which should be tainted on return.
437-
REGISTER_SET_WITH_PROGRAMSTATE(TaintArgsOnPostVisit, ArgIdxTy)
439+
REGISTER_MAP_WITH_PROGRAMSTATE(TaintArgsOnPostVisit, const LocationContext *,
440+
ImmutableSet<ArgIdxTy>)
441+
REGISTER_SET_FACTORY_WITH_PROGRAMSTATE(ArgIdxFactory, ArgIdxTy)
438442

439443
void GenericTaintRuleParser::validateArgVector(const std::string &Option,
440444
const ArgVecTy &Args) const {
@@ -685,22 +689,26 @@ void GenericTaintChecker::checkPostCall(const CallEvent &Call,
685689
// Set the marked values as tainted. The return value only accessible from
686690
// checkPostStmt.
687691
ProgramStateRef State = C.getState();
692+
const StackFrameContext *CurrentFrame = C.getStackFrame();
688693

689694
// Depending on what was tainted at pre-visit, we determined a set of
690695
// arguments which should be tainted after the function returns. These are
691696
// stored in the state as TaintArgsOnPostVisit set.
692-
TaintArgsOnPostVisitTy TaintArgs = State->get<TaintArgsOnPostVisit>();
693-
if (TaintArgs.isEmpty())
697+
TaintArgsOnPostVisitTy TaintArgsMap = State->get<TaintArgsOnPostVisit>();
698+
699+
const ImmutableSet<ArgIdxTy> *TaintArgs = TaintArgsMap.lookup(CurrentFrame);
700+
if (!TaintArgs)
694701
return;
702+
assert(!TaintArgs->isEmpty());
695703

696704
LLVM_DEBUG(for (ArgIdxTy I
697-
: TaintArgs) {
705+
: *TaintArgs) {
698706
llvm::dbgs() << "PostCall<";
699707
Call.dump(llvm::dbgs());
700708
llvm::dbgs() << "> actually wants to taint arg index: " << I << '\n';
701709
});
702710

703-
for (ArgIdxTy ArgNum : TaintArgs) {
711+
for (ArgIdxTy ArgNum : *TaintArgs) {
704712
// Special handling for the tainted return value.
705713
if (ArgNum == ReturnValueIndex) {
706714
State = addTaint(State, Call.getReturnValue());
@@ -714,7 +722,7 @@ void GenericTaintChecker::checkPostCall(const CallEvent &Call,
714722
}
715723

716724
// Clear up the taint info from the state.
717-
State = State->remove<TaintArgsOnPostVisit>();
725+
State = State->remove<TaintArgsOnPostVisit>(CurrentFrame);
718726
C.addTransition(State);
719727
}
720728

@@ -776,28 +784,33 @@ void GenericTaintRule::process(const GenericTaintChecker &Checker,
776784
};
777785

778786
/// Propagate taint where it is necessary.
787+
auto &F = State->getStateManager().get_context<ArgIdxFactory>();
788+
ImmutableSet<ArgIdxTy> Result = F.getEmptySet();
779789
ForEachCallArg(
780-
[this, &State, WouldEscape, &Call](ArgIdxTy I, const Expr *E, SVal V) {
790+
[this, WouldEscape, &Call, &Result, &F](ArgIdxTy I, const Expr *E,
791+
SVal V) {
781792
if (PropDstArgs.contains(I)) {
782793
LLVM_DEBUG(llvm::dbgs() << "PreCall<"; Call.dump(llvm::dbgs());
783794
llvm::dbgs()
784795
<< "> prepares tainting arg index: " << I << '\n';);
785-
State = State->add<TaintArgsOnPostVisit>(I);
796+
Result = F.add(Result, I);
786797
}
787798

788799
// TODO: We should traverse all reachable memory regions via the
789800
// escaping parameter. Instead of doing that we simply mark only the
790801
// referred memory region as tainted.
791802
if (WouldEscape(V, E->getType())) {
792-
LLVM_DEBUG(if (!State->contains<TaintArgsOnPostVisit>(I)) {
803+
LLVM_DEBUG(if (!Result.contains(I)) {
793804
llvm::dbgs() << "PreCall<";
794805
Call.dump(llvm::dbgs());
795806
llvm::dbgs() << "> prepares tainting arg index: " << I << '\n';
796807
});
797-
State = State->add<TaintArgsOnPostVisit>(I);
808+
Result = F.add(Result, I);
798809
}
799810
});
800811

812+
if (!Result.isEmpty())
813+
State = State->set<TaintArgsOnPostVisit>(C.getStackFrame(), Result);
801814
C.addTransition(State);
802815
}
803816

@@ -888,7 +901,11 @@ void GenericTaintChecker::taintUnsafeSocketProtocol(const CallEvent &Call,
888901
if (SafeProtocol)
889902
return;
890903

891-
C.addTransition(C.getState()->add<TaintArgsOnPostVisit>(ReturnValueIndex));
904+
ProgramStateRef State = C.getState();
905+
auto &F = State->getStateManager().get_context<ArgIdxFactory>();
906+
ImmutableSet<ArgIdxTy> Result = F.add(F.getEmptySet(), ReturnValueIndex);
907+
State = State->set<TaintArgsOnPostVisit>(C.getStackFrame(), Result);
908+
C.addTransition(State);
892909
}
893910

894911
/// Checker registration

clang/test/Analysis/taint-checker-callback-order-has-definition.c

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,6 @@
33
// RUN: -mllvm -debug-only=taint-checker \
44
// RUN: 2>&1 | FileCheck %s
55

6-
// FIXME: We should not crash.
7-
// XFAIL: *
8-
96
struct _IO_FILE;
107
typedef struct _IO_FILE FILE;
118
FILE *fopen(const char *fname, const char *mode);
@@ -31,12 +28,8 @@ void top(const char *fname, char *buf) {
3128
// CHECK-NEXT: PreCall<fgets(buf, 42, fp)> prepares tainting arg index: 1
3229
// CHECK-NEXT: PreCall<fgets(buf, 42, fp)> prepares tainting arg index: 2
3330

34-
// FIXME: We should propagate taint from PreCall<fgets> -> PostCall<fgets>.
35-
// CHECK-NEXT: PostCall<nested_call()> actually wants to taint arg index: -1
36-
// CHECK-NEXT: PostCall<nested_call()> actually wants to taint arg index: 0
37-
// CHECK-NEXT: PostCall<nested_call()> actually wants to taint arg index: 1
38-
// CHECK-NEXT: PostCall<nested_call()> actually wants to taint arg index: 2
39-
40-
// FIXME: We should not crash.
41-
// CHECK: PLEASE submit a bug report
31+
// CHECK-NEXT: PostCall<fgets(buf, 42, fp)> actually wants to taint arg index: -1
32+
// CHECK-NEXT: PostCall<fgets(buf, 42, fp)> actually wants to taint arg index: 0
33+
// CHECK-NEXT: PostCall<fgets(buf, 42, fp)> actually wants to taint arg index: 1
34+
// CHECK-NEXT: PostCall<fgets(buf, 42, fp)> actually wants to taint arg index: 2
4235
}

0 commit comments

Comments
 (0)