Home | History | Annotate | Line # | Download | only in Checkers
      1      1.1  joerg //=== Taint.cpp - Taint tracking and basic propagation rules. ------*- C++ -*-//
      2      1.1  joerg //
      3      1.1  joerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      4      1.1  joerg // See https://llvm.org/LICENSE.txt for license information.
      5      1.1  joerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      6      1.1  joerg //
      7      1.1  joerg //===----------------------------------------------------------------------===//
      8      1.1  joerg //
      9      1.1  joerg // Defines basic, non-domain-specific mechanisms for tracking tainted values.
     10      1.1  joerg //
     11      1.1  joerg //===----------------------------------------------------------------------===//
     12      1.1  joerg 
     13      1.1  joerg #include "Taint.h"
     14      1.1  joerg #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
     15      1.1  joerg #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
     16      1.1  joerg 
     17      1.1  joerg using namespace clang;
     18      1.1  joerg using namespace ento;
     19      1.1  joerg using namespace taint;
     20      1.1  joerg 
     21      1.1  joerg // Fully tainted symbols.
     22      1.1  joerg REGISTER_MAP_WITH_PROGRAMSTATE(TaintMap, SymbolRef, TaintTagType)
     23      1.1  joerg 
     24      1.1  joerg // Partially tainted symbols.
     25      1.1  joerg REGISTER_MAP_FACTORY_WITH_PROGRAMSTATE(TaintedSubRegions, const SubRegion *,
     26      1.1  joerg                                        TaintTagType)
     27      1.1  joerg REGISTER_MAP_WITH_PROGRAMSTATE(DerivedSymTaint, SymbolRef, TaintedSubRegions)
     28      1.1  joerg 
     29      1.1  joerg void taint::printTaint(ProgramStateRef State, raw_ostream &Out, const char *NL,
     30      1.1  joerg                        const char *Sep) {
     31      1.1  joerg   TaintMapTy TM = State->get<TaintMap>();
     32      1.1  joerg 
     33      1.1  joerg   if (!TM.isEmpty())
     34      1.1  joerg     Out << "Tainted symbols:" << NL;
     35      1.1  joerg 
     36      1.1  joerg   for (const auto &I : TM)
     37      1.1  joerg     Out << I.first << " : " << I.second << NL;
     38      1.1  joerg }
     39      1.1  joerg 
     40  1.1.1.2  joerg void dumpTaint(ProgramStateRef State) { printTaint(State, llvm::errs()); }
     41      1.1  joerg 
     42      1.1  joerg ProgramStateRef taint::addTaint(ProgramStateRef State, const Stmt *S,
     43      1.1  joerg                                 const LocationContext *LCtx,
     44      1.1  joerg                                 TaintTagType Kind) {
     45      1.1  joerg   return addTaint(State, State->getSVal(S, LCtx), Kind);
     46      1.1  joerg }
     47      1.1  joerg 
     48      1.1  joerg ProgramStateRef taint::addTaint(ProgramStateRef State, SVal V,
     49      1.1  joerg                                 TaintTagType Kind) {
     50      1.1  joerg   SymbolRef Sym = V.getAsSymbol();
     51      1.1  joerg   if (Sym)
     52      1.1  joerg     return addTaint(State, Sym, Kind);
     53      1.1  joerg 
     54      1.1  joerg   // If the SVal represents a structure, try to mass-taint all values within the
     55      1.1  joerg   // structure. For now it only works efficiently on lazy compound values that
     56      1.1  joerg   // were conjured during a conservative evaluation of a function - either as
     57      1.1  joerg   // return values of functions that return structures or arrays by value, or as
     58      1.1  joerg   // values of structures or arrays passed into the function by reference,
     59      1.1  joerg   // directly or through pointer aliasing. Such lazy compound values are
     60      1.1  joerg   // characterized by having exactly one binding in their captured store within
     61      1.1  joerg   // their parent region, which is a conjured symbol default-bound to the base
     62      1.1  joerg   // region of the parent region.
     63      1.1  joerg   if (auto LCV = V.getAs<nonloc::LazyCompoundVal>()) {
     64      1.1  joerg     if (Optional<SVal> binding =
     65  1.1.1.2  joerg             State->getStateManager().getStoreManager().getDefaultBinding(
     66  1.1.1.2  joerg                 *LCV)) {
     67      1.1  joerg       if (SymbolRef Sym = binding->getAsSymbol())
     68      1.1  joerg         return addPartialTaint(State, Sym, LCV->getRegion(), Kind);
     69      1.1  joerg     }
     70      1.1  joerg   }
     71      1.1  joerg 
     72      1.1  joerg   const MemRegion *R = V.getAsRegion();
     73      1.1  joerg   return addTaint(State, R, Kind);
     74      1.1  joerg }
     75      1.1  joerg 
     76      1.1  joerg ProgramStateRef taint::addTaint(ProgramStateRef State, const MemRegion *R,
     77      1.1  joerg                                 TaintTagType Kind) {
     78      1.1  joerg   if (const SymbolicRegion *SR = dyn_cast_or_null<SymbolicRegion>(R))
     79      1.1  joerg     return addTaint(State, SR->getSymbol(), Kind);
     80      1.1  joerg   return State;
     81      1.1  joerg }
     82      1.1  joerg 
     83      1.1  joerg ProgramStateRef taint::addTaint(ProgramStateRef State, SymbolRef Sym,
     84      1.1  joerg                                 TaintTagType Kind) {
     85      1.1  joerg   // If this is a symbol cast, remove the cast before adding the taint. Taint
     86      1.1  joerg   // is cast agnostic.
     87      1.1  joerg   while (const SymbolCast *SC = dyn_cast<SymbolCast>(Sym))
     88      1.1  joerg     Sym = SC->getOperand();
     89      1.1  joerg 
     90      1.1  joerg   ProgramStateRef NewState = State->set<TaintMap>(Sym, Kind);
     91      1.1  joerg   assert(NewState);
     92      1.1  joerg   return NewState;
     93      1.1  joerg }
     94      1.1  joerg 
     95  1.1.1.2  joerg ProgramStateRef taint::removeTaint(ProgramStateRef State, SVal V) {
     96  1.1.1.2  joerg   SymbolRef Sym = V.getAsSymbol();
     97  1.1.1.2  joerg   if (Sym)
     98  1.1.1.2  joerg     return removeTaint(State, Sym);
     99  1.1.1.2  joerg 
    100  1.1.1.2  joerg   const MemRegion *R = V.getAsRegion();
    101  1.1.1.2  joerg   return removeTaint(State, R);
    102  1.1.1.2  joerg }
    103  1.1.1.2  joerg 
    104  1.1.1.2  joerg ProgramStateRef taint::removeTaint(ProgramStateRef State, const MemRegion *R) {
    105  1.1.1.2  joerg   if (const SymbolicRegion *SR = dyn_cast_or_null<SymbolicRegion>(R))
    106  1.1.1.2  joerg     return removeTaint(State, SR->getSymbol());
    107  1.1.1.2  joerg   return State;
    108  1.1.1.2  joerg }
    109  1.1.1.2  joerg 
    110  1.1.1.2  joerg ProgramStateRef taint::removeTaint(ProgramStateRef State, SymbolRef Sym) {
    111  1.1.1.2  joerg   // If this is a symbol cast, remove the cast before adding the taint. Taint
    112  1.1.1.2  joerg   // is cast agnostic.
    113  1.1.1.2  joerg   while (const SymbolCast *SC = dyn_cast<SymbolCast>(Sym))
    114  1.1.1.2  joerg     Sym = SC->getOperand();
    115  1.1.1.2  joerg 
    116  1.1.1.2  joerg   ProgramStateRef NewState = State->remove<TaintMap>(Sym);
    117  1.1.1.2  joerg   assert(NewState);
    118  1.1.1.2  joerg   return NewState;
    119  1.1.1.2  joerg }
    120  1.1.1.2  joerg 
    121      1.1  joerg ProgramStateRef taint::addPartialTaint(ProgramStateRef State,
    122      1.1  joerg                                        SymbolRef ParentSym,
    123      1.1  joerg                                        const SubRegion *SubRegion,
    124      1.1  joerg                                        TaintTagType Kind) {
    125      1.1  joerg   // Ignore partial taint if the entire parent symbol is already tainted.
    126      1.1  joerg   if (const TaintTagType *T = State->get<TaintMap>(ParentSym))
    127      1.1  joerg     if (*T == Kind)
    128      1.1  joerg       return State;
    129      1.1  joerg 
    130      1.1  joerg   // Partial taint applies if only a portion of the symbol is tainted.
    131      1.1  joerg   if (SubRegion == SubRegion->getBaseRegion())
    132      1.1  joerg     return addTaint(State, ParentSym, Kind);
    133      1.1  joerg 
    134      1.1  joerg   const TaintedSubRegions *SavedRegs = State->get<DerivedSymTaint>(ParentSym);
    135      1.1  joerg   TaintedSubRegions::Factory &F = State->get_context<TaintedSubRegions>();
    136      1.1  joerg   TaintedSubRegions Regs = SavedRegs ? *SavedRegs : F.getEmptyMap();
    137      1.1  joerg 
    138      1.1  joerg   Regs = F.add(Regs, SubRegion, Kind);
    139      1.1  joerg   ProgramStateRef NewState = State->set<DerivedSymTaint>(ParentSym, Regs);
    140      1.1  joerg   assert(NewState);
    141      1.1  joerg   return NewState;
    142      1.1  joerg }
    143      1.1  joerg 
    144      1.1  joerg bool taint::isTainted(ProgramStateRef State, const Stmt *S,
    145      1.1  joerg                       const LocationContext *LCtx, TaintTagType Kind) {
    146      1.1  joerg   SVal val = State->getSVal(S, LCtx);
    147      1.1  joerg   return isTainted(State, val, Kind);
    148      1.1  joerg }
    149      1.1  joerg 
    150      1.1  joerg bool taint::isTainted(ProgramStateRef State, SVal V, TaintTagType Kind) {
    151  1.1.1.2  joerg   if (SymbolRef Sym = V.getAsSymbol())
    152      1.1  joerg     return isTainted(State, Sym, Kind);
    153      1.1  joerg   if (const MemRegion *Reg = V.getAsRegion())
    154      1.1  joerg     return isTainted(State, Reg, Kind);
    155      1.1  joerg   return false;
    156      1.1  joerg }
    157      1.1  joerg 
    158      1.1  joerg bool taint::isTainted(ProgramStateRef State, const MemRegion *Reg,
    159      1.1  joerg                       TaintTagType K) {
    160      1.1  joerg   if (!Reg)
    161      1.1  joerg     return false;
    162      1.1  joerg 
    163      1.1  joerg   // Element region (array element) is tainted if either the base or the offset
    164      1.1  joerg   // are tainted.
    165      1.1  joerg   if (const ElementRegion *ER = dyn_cast<ElementRegion>(Reg))
    166      1.1  joerg     return isTainted(State, ER->getSuperRegion(), K) ||
    167      1.1  joerg            isTainted(State, ER->getIndex(), K);
    168      1.1  joerg 
    169      1.1  joerg   if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(Reg))
    170      1.1  joerg     return isTainted(State, SR->getSymbol(), K);
    171      1.1  joerg 
    172      1.1  joerg   if (const SubRegion *ER = dyn_cast<SubRegion>(Reg))
    173      1.1  joerg     return isTainted(State, ER->getSuperRegion(), K);
    174      1.1  joerg 
    175      1.1  joerg   return false;
    176      1.1  joerg }
    177      1.1  joerg 
    178      1.1  joerg bool taint::isTainted(ProgramStateRef State, SymbolRef Sym, TaintTagType Kind) {
    179      1.1  joerg   if (!Sym)
    180      1.1  joerg     return false;
    181      1.1  joerg 
    182      1.1  joerg   // Traverse all the symbols this symbol depends on to see if any are tainted.
    183      1.1  joerg   for (SymExpr::symbol_iterator SI = Sym->symbol_begin(),
    184  1.1.1.2  joerg                                 SE = Sym->symbol_end();
    185  1.1.1.2  joerg        SI != SE; ++SI) {
    186      1.1  joerg     if (!isa<SymbolData>(*SI))
    187      1.1  joerg       continue;
    188      1.1  joerg 
    189      1.1  joerg     if (const TaintTagType *Tag = State->get<TaintMap>(*SI)) {
    190      1.1  joerg       if (*Tag == Kind)
    191      1.1  joerg         return true;
    192      1.1  joerg     }
    193      1.1  joerg 
    194      1.1  joerg     if (const auto *SD = dyn_cast<SymbolDerived>(*SI)) {
    195      1.1  joerg       // If this is a SymbolDerived with a tainted parent, it's also tainted.
    196      1.1  joerg       if (isTainted(State, SD->getParentSymbol(), Kind))
    197      1.1  joerg         return true;
    198      1.1  joerg 
    199      1.1  joerg       // If this is a SymbolDerived with the same parent symbol as another
    200      1.1  joerg       // tainted SymbolDerived and a region that's a sub-region of that tainted
    201      1.1  joerg       // symbol, it's also tainted.
    202      1.1  joerg       if (const TaintedSubRegions *Regs =
    203      1.1  joerg               State->get<DerivedSymTaint>(SD->getParentSymbol())) {
    204      1.1  joerg         const TypedValueRegion *R = SD->getRegion();
    205      1.1  joerg         for (auto I : *Regs) {
    206      1.1  joerg           // FIXME: The logic to identify tainted regions could be more
    207      1.1  joerg           // complete. For example, this would not currently identify
    208      1.1  joerg           // overlapping fields in a union as tainted. To identify this we can
    209      1.1  joerg           // check for overlapping/nested byte offsets.
    210      1.1  joerg           if (Kind == I.second && R->isSubRegionOf(I.first))
    211      1.1  joerg             return true;
    212      1.1  joerg         }
    213      1.1  joerg       }
    214      1.1  joerg     }
    215      1.1  joerg 
    216      1.1  joerg     // If memory region is tainted, data is also tainted.
    217      1.1  joerg     if (const auto *SRV = dyn_cast<SymbolRegionValue>(*SI)) {
    218      1.1  joerg       if (isTainted(State, SRV->getRegion(), Kind))
    219      1.1  joerg         return true;
    220      1.1  joerg     }
    221      1.1  joerg 
    222      1.1  joerg     // If this is a SymbolCast from a tainted value, it's also tainted.
    223      1.1  joerg     if (const auto *SC = dyn_cast<SymbolCast>(*SI)) {
    224      1.1  joerg       if (isTainted(State, SC->getOperand(), Kind))
    225      1.1  joerg         return true;
    226      1.1  joerg     }
    227      1.1  joerg   }
    228      1.1  joerg 
    229      1.1  joerg   return false;
    230      1.1  joerg }
    231      1.1  joerg 
    232      1.1  joerg PathDiagnosticPieceRef TaintBugVisitor::VisitNode(const ExplodedNode *N,
    233      1.1  joerg                                                   BugReporterContext &BRC,
    234      1.1  joerg                                                   PathSensitiveBugReport &BR) {
    235      1.1  joerg 
    236      1.1  joerg   // Find the ExplodedNode where the taint was first introduced
    237      1.1  joerg   if (!isTainted(N->getState(), V) ||
    238      1.1  joerg       isTainted(N->getFirstPred()->getState(), V))
    239      1.1  joerg     return nullptr;
    240      1.1  joerg 
    241      1.1  joerg   const Stmt *S = N->getStmtForDiagnostics();
    242      1.1  joerg   if (!S)
    243      1.1  joerg     return nullptr;
    244      1.1  joerg 
    245      1.1  joerg   const LocationContext *NCtx = N->getLocationContext();
    246      1.1  joerg   PathDiagnosticLocation L =
    247      1.1  joerg       PathDiagnosticLocation::createBegin(S, BRC.getSourceManager(), NCtx);
    248      1.1  joerg   if (!L.isValid() || !L.asLocation().isValid())
    249      1.1  joerg     return nullptr;
    250      1.1  joerg 
    251      1.1  joerg   return std::make_shared<PathDiagnosticEventPiece>(L, "Taint originated here");
    252      1.1  joerg }
    253