Index: lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp +++ lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp @@ -65,6 +65,11 @@ /// and thus, is tainted. static bool isStdin(const Expr *E, CheckerContext &C); + /// \brief Given a LazyCompoundValue, get the symbol of the first FieldRegion/ + /// ElementRegion we can find a binding for. + static SymbolRef getLCVSymbol(CheckerContext &C, + nonloc::LazyCompoundVal &LCV); + /// \brief Given a pointer argument, get the symbol of the value it contains /// (points to). static SymbolRef getPointedToSymbol(CheckerContext &C, const Expr *Arg); @@ -423,6 +428,43 @@ return false; } +SymbolRef GenericTaintChecker::getLCVSymbol(CheckerContext &C, + nonloc::LazyCompoundVal &LCV) { + StoreManager &StoreMgr = C.getStoreManager(); + MemRegionManager &MrMgr = C.getSValBuilder().getRegionManager(); + + QualType T = LCV.getRegion()->getValueType(); + if (T->isStructureType() || T->isUnionType()) { + const RecordType *RT = T->getAsStructureType(); + if (!RT) + RT = T->getAsUnionType(); + + const RecordDecl *RD = RT->getDecl()->getDefinition(); + for (const auto *I : RD->fields()) { + const FieldRegion *FR = MrMgr.getFieldRegion(I, LCV.getRegion()); + const SVal &V = + StoreMgr.getBinding(LCV.getStore(), loc::MemRegionVal(FR)); + if (auto Sym = V.getAsSymbol()) + return Sym; + else if (auto _LCV = V.getAs()) { + if (auto Sym = getLCVSymbol(C, *_LCV)) + return Sym; + } + } + } else if (T->isArrayType()) { + const ArrayType *AT = T->getAsArrayTypeUnsafe(); + const ElementRegion *ER = + StoreMgr.GetElementZeroRegion(LCV.getRegion(), AT->getElementType()); + const SVal &V = StoreMgr.getBinding(LCV.getStore(), loc::MemRegionVal(ER)); + if (auto Sym = V.getAsSymbol()) + return Sym; + else if (auto _LCV = V.getAs()) + return getLCVSymbol(C, *_LCV); + } + + return nullptr; +} + SymbolRef GenericTaintChecker::getPointedToSymbol(CheckerContext &C, const Expr* Arg) { ProgramStateRef State = C.getState(); @@ -438,6 +480,10 @@ dyn_cast(Arg->getType().getCanonicalType().getTypePtr()); SVal Val = State->getSVal(*AddrLoc, ArgTy ? ArgTy->getPointeeType(): QualType()); + + if (auto LCV = Val.getAs()) + return getLCVSymbol(C, *LCV); + return Val.getAsSymbol(); } Index: lib/StaticAnalyzer/Core/ProgramState.cpp =================================================================== --- lib/StaticAnalyzer/Core/ProgramState.cpp +++ lib/StaticAnalyzer/Core/ProgramState.cpp @@ -664,6 +664,10 @@ while (const SymbolCast *SC = dyn_cast(Sym)) Sym = SC->getOperand(); + // If this a derived symbol, taint the parent symbol. + if (const SymbolDerived *SD = dyn_cast(Sym)) + Sym = SD->getParentSymbol(); + ProgramStateRef NewState = set(Sym, Kind); assert(NewState); return NewState; Index: test/Analysis/taint-generic.c =================================================================== --- test/Analysis/taint-generic.c +++ test/Analysis/taint-generic.c @@ -169,6 +169,26 @@ sock = socket(AF_LOCAL, SOCK_STREAM, 0); read(sock, buffer, 100); execl(buffer, "filename", 0); // no-warning + + sock = socket(AF_INET, SOCK_STREAM, 0); + // References to both buffer and &buffer as an argument should taint the argument + read(sock, &buffer, 100); + execl(buffer, "filename", 0); // expected-warning {{Untrusted data is passed to a system call}} +} + +void testStruct() { + struct { + struct {} st; + char buf[16]; + int length; + } tainted; + + char buffer[16]; + int sock; + + sock = socket(AF_INET, SOCK_STREAM, 0); + read(sock, &tainted, sizeof(tainted)); + __builtin_memcpy(buffer, tainted.buf, tainted.length); // expected-warning {{Untrusted data is used to specify the buffer size}} } int testDivByZero() { Index: test/Analysis/taint-tester.c =================================================================== --- test/Analysis/taint-tester.c +++ test/Analysis/taint-tester.c @@ -51,8 +51,9 @@ scanf("%d", &xy.y); scanf("%d", &xy.x); int tx = xy.x; // expected-warning + {{tainted}} - int ty = xy.y; // FIXME: This should be tainted as well. - char ntz = xy.z;// no warning + int ty = xy.y; // expected-warning + {{tainted}} + // FIXME: xy.z should not be tainted + char ntz = xy.z; // expected-warning + {{tainted}} // Now, scanf scans both. scanf("%d %d", &xy.y, &xy.x); int ttx = xy.x; // expected-warning + {{tainted}}