19fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com// MallocOverflowSecurityChecker.cpp - Check for malloc overflows -*- C++ -*-=// 29fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com// 39fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com// The LLVM Compiler Infrastructure 49fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com// 59fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com// This file is distributed under the University of Illinois Open Source 69fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com// License. See LICENSE.TXT for details. 79fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com// 89fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com//===----------------------------------------------------------------------===// 99fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com// 109fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com// This checker detects a common memory allocation security flaw. 119fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com// Suppose 'unsigned int n' comes from an untrusted source. If the 129fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com// code looks like 'malloc (n * 4)', and an attacker can make 'n' be 139fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com// say MAX_UINT/4+2, then instead of allocating the correct 'n' 4-byte 144b32bd53c63b245707822ae83e3215863303bf43commit-bot@chromium.org// elements, this will actually allocate only two because of overflow. 159fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com// Then when the rest of the program attempts to store values past the 16773f8e24214991332eaf903e72c13dca7d78d40dcommit-bot@chromium.org// second element, these values will actually overwrite other items in 17773f8e24214991332eaf903e72c13dca7d78d40dcommit-bot@chromium.org// the heap, probably allowing the attacker to execute arbitrary code. 18773f8e24214991332eaf903e72c13dca7d78d40dcommit-bot@chromium.org// 19773f8e24214991332eaf903e72c13dca7d78d40dcommit-bot@chromium.org//===----------------------------------------------------------------------===// 20773f8e24214991332eaf903e72c13dca7d78d40dcommit-bot@chromium.org 21773f8e24214991332eaf903e72c13dca7d78d40dcommit-bot@chromium.org#include "ClangSACheckers.h" 22773f8e24214991332eaf903e72c13dca7d78d40dcommit-bot@chromium.org#include "clang/AST/EvaluatedExprVisitor.h" 23773f8e24214991332eaf903e72c13dca7d78d40dcommit-bot@chromium.org#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" 249fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com#include "clang/StaticAnalyzer/Core/Checker.h" 259fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" 269fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com#include "llvm/ADT/SmallVector.h" 279fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com 289fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.comusing namespace clang; 299fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.comusing namespace ento; 306fcd28ba1de83b72f4c8343ccec27d26c127de32reed@google.com 319fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.comnamespace { 329fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.comstruct MallocOverflowCheck { 336fcd28ba1de83b72f4c8343ccec27d26c127de32reed@google.com const BinaryOperator *mulop; 349fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com const Expr *variable; 359fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com 369fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com MallocOverflowCheck (const BinaryOperator *m, const Expr *v) 379fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com : mulop(m), variable (v) 389fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com {} 399fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com}; 409fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com 419fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.comclass MallocOverflowSecurityChecker : public Checker<check::ASTCodeBody> { 426fcd28ba1de83b72f4c8343ccec27d26c127de32reed@google.compublic: 439fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com void checkASTCodeBody(const Decl *D, AnalysisManager &mgr, 449fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com BugReporter &BR) const; 459fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com 469fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com void CheckMallocArgument( 479fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com SmallVectorImpl<MallocOverflowCheck> &PossibleMallocOverflows, 484b32bd53c63b245707822ae83e3215863303bf43commit-bot@chromium.org const Expr *TheArgument, ASTContext &Context) const; 494b32bd53c63b245707822ae83e3215863303bf43commit-bot@chromium.org 504b32bd53c63b245707822ae83e3215863303bf43commit-bot@chromium.org void OutputPossibleOverflows( 514b32bd53c63b245707822ae83e3215863303bf43commit-bot@chromium.org SmallVectorImpl<MallocOverflowCheck> &PossibleMallocOverflows, 524b32bd53c63b245707822ae83e3215863303bf43commit-bot@chromium.org const Decl *D, BugReporter &BR, AnalysisManager &mgr) const; 534b32bd53c63b245707822ae83e3215863303bf43commit-bot@chromium.org 544b32bd53c63b245707822ae83e3215863303bf43commit-bot@chromium.org}; 554b32bd53c63b245707822ae83e3215863303bf43commit-bot@chromium.org} // end anonymous namespace 564b32bd53c63b245707822ae83e3215863303bf43commit-bot@chromium.org 574b32bd53c63b245707822ae83e3215863303bf43commit-bot@chromium.orgvoid MallocOverflowSecurityChecker::CheckMallocArgument( 584b32bd53c63b245707822ae83e3215863303bf43commit-bot@chromium.org SmallVectorImpl<MallocOverflowCheck> &PossibleMallocOverflows, 594b32bd53c63b245707822ae83e3215863303bf43commit-bot@chromium.org const Expr *TheArgument, 609fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com ASTContext &Context) const { 614b32bd53c63b245707822ae83e3215863303bf43commit-bot@chromium.org 629fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com /* Look for a linear combination with a single variable, and at least 639fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com one multiplication. 649fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com Reject anything that applies to the variable: an explicit cast, 659fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com conditional expression, an operation that could reduce the range 669fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com of the result, or anything too complicated :-). */ 679fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com const Expr * e = TheArgument; 689fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com const BinaryOperator * mulop = nullptr; 699fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com 709fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com for (;;) { 719fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com e = e->IgnoreParenImpCasts(); 726fcd28ba1de83b72f4c8343ccec27d26c127de32reed@google.com if (isa<BinaryOperator>(e)) { 739fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com const BinaryOperator * binop = dyn_cast<BinaryOperator>(e); 749fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com BinaryOperatorKind opc = binop->getOpcode(); 759fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com // TODO: ignore multiplications by 1, reject if multiplied by 0. 76a9279f0749f7641d946517be44a1b74fa64ebbc2skia.committer@gmail.com if (mulop == nullptr && opc == BO_Mul) 779fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com mulop = binop; 78773f8e24214991332eaf903e72c13dca7d78d40dcommit-bot@chromium.org if (opc != BO_Mul && opc != BO_Add && opc != BO_Sub && opc != BO_Shl) 799fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com return; 809fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com 816fcd28ba1de83b72f4c8343ccec27d26c127de32reed@google.com const Expr *lhs = binop->getLHS(); 829fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com const Expr *rhs = binop->getRHS(); 836fcd28ba1de83b72f4c8343ccec27d26c127de32reed@google.com if (rhs->isEvaluatable(Context)) 849fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com e = lhs; 859fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com else if ((opc == BO_Add || opc == BO_Mul) 869fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com && lhs->isEvaluatable(Context)) 879fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com e = rhs; 889fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com else 899fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com return; 909fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com } 919fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com else if (isa<DeclRefExpr>(e) || isa<MemberExpr>(e)) 928515e79a7699922e0f95f93e8cc11d4c88657c58rileya@google.com break; 939fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com else 949fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com return; 95178a267a6cb1405805caf23fe074d68b509f76d3robertphillips@google.com } 969fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com 979fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com if (mulop == nullptr) 988515e79a7699922e0f95f93e8cc11d4c88657c58rileya@google.com return; 998515e79a7699922e0f95f93e8cc11d4c88657c58rileya@google.com 1009fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com // We've found the right structure of malloc argument, now save 1019fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com // the data so when the body of the function is completely available 102a31eacb22e12a4223740e53ff5a11bd08340106ecommit-bot@chromium.org // we can check for comparisons. 103a31eacb22e12a4223740e53ff5a11bd08340106ecommit-bot@chromium.org 104a31eacb22e12a4223740e53ff5a11bd08340106ecommit-bot@chromium.org // TODO: Could push this into the innermost scope where 'e' is 105a31eacb22e12a4223740e53ff5a11bd08340106ecommit-bot@chromium.org // defined, rather than the whole function. 106a31eacb22e12a4223740e53ff5a11bd08340106ecommit-bot@chromium.org PossibleMallocOverflows.push_back(MallocOverflowCheck(mulop, e)); 107a31eacb22e12a4223740e53ff5a11bd08340106ecommit-bot@chromium.org} 108a31eacb22e12a4223740e53ff5a11bd08340106ecommit-bot@chromium.org 109a31eacb22e12a4223740e53ff5a11bd08340106ecommit-bot@chromium.orgnamespace { 110a31eacb22e12a4223740e53ff5a11bd08340106ecommit-bot@chromium.org// A worker class for OutputPossibleOverflows. 111a31eacb22e12a4223740e53ff5a11bd08340106ecommit-bot@chromium.orgclass CheckOverflowOps : 112a31eacb22e12a4223740e53ff5a11bd08340106ecommit-bot@chromium.org public EvaluatedExprVisitor<CheckOverflowOps> { 113a31eacb22e12a4223740e53ff5a11bd08340106ecommit-bot@chromium.orgpublic: 114a31eacb22e12a4223740e53ff5a11bd08340106ecommit-bot@chromium.org typedef SmallVectorImpl<MallocOverflowCheck> theVecType; 115a31eacb22e12a4223740e53ff5a11bd08340106ecommit-bot@chromium.org 116a31eacb22e12a4223740e53ff5a11bd08340106ecommit-bot@chromium.orgprivate: 117beb1af2f34b5c538fc08d849b132355160b4c93frobertphillips@google.com theVecType &toScanFor; 118beb1af2f34b5c538fc08d849b132355160b4c93frobertphillips@google.com ASTContext &Context; 119beb1af2f34b5c538fc08d849b132355160b4c93frobertphillips@google.com 120beb1af2f34b5c538fc08d849b132355160b4c93frobertphillips@google.com bool isIntZeroExpr(const Expr *E) const { 121beb1af2f34b5c538fc08d849b132355160b4c93frobertphillips@google.com if (!E->getType()->isIntegralOrEnumerationType()) 122beb1af2f34b5c538fc08d849b132355160b4c93frobertphillips@google.com return false; 123beb1af2f34b5c538fc08d849b132355160b4c93frobertphillips@google.com llvm::APSInt Result; 124beb1af2f34b5c538fc08d849b132355160b4c93frobertphillips@google.com if (E->EvaluateAsInt(Result, Context)) 125beb1af2f34b5c538fc08d849b132355160b4c93frobertphillips@google.com return Result == 0; 126beb1af2f34b5c538fc08d849b132355160b4c93frobertphillips@google.com return false; 127beb1af2f34b5c538fc08d849b132355160b4c93frobertphillips@google.com } 128db35dab49e0e6bf16ccad5052bf6e6826daad27dskia.committer@gmail.com 129db35dab49e0e6bf16ccad5052bf6e6826daad27dskia.committer@gmail.com void CheckExpr(const Expr *E_p) { 1302b290cec9825da11d8e09074727cfaac5eca6453commit-bot@chromium.org const Expr *E = E_p->IgnoreParenImpCasts(); 131beb1af2f34b5c538fc08d849b132355160b4c93frobertphillips@google.com 132a31eacb22e12a4223740e53ff5a11bd08340106ecommit-bot@chromium.org theVecType::iterator i = toScanFor.end(); 133beb1af2f34b5c538fc08d849b132355160b4c93frobertphillips@google.com theVecType::iterator e = toScanFor.begin(); 134beb1af2f34b5c538fc08d849b132355160b4c93frobertphillips@google.com 135beb1af2f34b5c538fc08d849b132355160b4c93frobertphillips@google.com if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E)) { 136beb1af2f34b5c538fc08d849b132355160b4c93frobertphillips@google.com const Decl * EdreD = DR->getDecl(); 137a31eacb22e12a4223740e53ff5a11bd08340106ecommit-bot@chromium.org while (i != e) { 138beb1af2f34b5c538fc08d849b132355160b4c93frobertphillips@google.com --i; 139beb1af2f34b5c538fc08d849b132355160b4c93frobertphillips@google.com if (const DeclRefExpr *DR_i = dyn_cast<DeclRefExpr>(i->variable)) { 140beb1af2f34b5c538fc08d849b132355160b4c93frobertphillips@google.com if (DR_i->getDecl() == EdreD) 141beb1af2f34b5c538fc08d849b132355160b4c93frobertphillips@google.com i = toScanFor.erase(i); 1429fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com } 1439fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com } 1448515e79a7699922e0f95f93e8cc11d4c88657c58rileya@google.com } 1459fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com else if (isa<MemberExpr>(E)) { 1469fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com // No points-to analysis, just look at the member 1479fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com const Decl * EmeMD = dyn_cast<MemberExpr>(E)->getMemberDecl(); 148a31eacb22e12a4223740e53ff5a11bd08340106ecommit-bot@chromium.org while (i != e) { 1499fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com --i; 1509fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com if (isa<MemberExpr>(i->variable)) { 1519fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com if (dyn_cast<MemberExpr>(i->variable)->getMemberDecl() == EmeMD) 1529fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com i = toScanFor.erase (i); 1539fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com } 1549fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com } 1559fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com } 1569fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com } 1579fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com 1589fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com public: 1599fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com void VisitBinaryOperator(BinaryOperator *E) { 1609fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com if (E->isComparisonOp()) { 1619fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com const Expr * lhs = E->getLHS(); 1629fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com const Expr * rhs = E->getRHS(); 1639fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com // Ignore comparisons against zero, since they generally don't 1649fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com // protect against an overflow. 1659fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com if (!isIntZeroExpr(lhs) && ! isIntZeroExpr(rhs)) { 1669fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com CheckExpr(lhs); 167db35dab49e0e6bf16ccad5052bf6e6826daad27dskia.committer@gmail.com CheckExpr(rhs); 168db35dab49e0e6bf16ccad5052bf6e6826daad27dskia.committer@gmail.com } 169a31eacb22e12a4223740e53ff5a11bd08340106ecommit-bot@chromium.org } 170a31eacb22e12a4223740e53ff5a11bd08340106ecommit-bot@chromium.org EvaluatedExprVisitor<CheckOverflowOps>::VisitBinaryOperator(E); 1712b290cec9825da11d8e09074727cfaac5eca6453commit-bot@chromium.org } 172db35dab49e0e6bf16ccad5052bf6e6826daad27dskia.committer@gmail.com 173db35dab49e0e6bf16ccad5052bf6e6826daad27dskia.committer@gmail.com /* We specifically ignore loop conditions, because they're typically 174a31eacb22e12a4223740e53ff5a11bd08340106ecommit-bot@chromium.org not error checks. */ 175a31eacb22e12a4223740e53ff5a11bd08340106ecommit-bot@chromium.org void VisitWhileStmt(WhileStmt *S) { 1762b290cec9825da11d8e09074727cfaac5eca6453commit-bot@chromium.org return this->Visit(S->getBody()); 1779fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com } 1789fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com void VisitForStmt(ForStmt *S) { 1799fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com return this->Visit(S->getBody()); 1809fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com } 1819fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com void VisitDoStmt(DoStmt *S) { 1829fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com return this->Visit(S->getBody()); 1839fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com } 1849fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com 1859fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com CheckOverflowOps(theVecType &v, ASTContext &ctx) 186db35dab49e0e6bf16ccad5052bf6e6826daad27dskia.committer@gmail.com : EvaluatedExprVisitor<CheckOverflowOps>(ctx), 187db35dab49e0e6bf16ccad5052bf6e6826daad27dskia.committer@gmail.com toScanFor(v), Context(ctx) 188a31eacb22e12a4223740e53ff5a11bd08340106ecommit-bot@chromium.org { } 189a31eacb22e12a4223740e53ff5a11bd08340106ecommit-bot@chromium.org }; 1902b290cec9825da11d8e09074727cfaac5eca6453commit-bot@chromium.org} 191db35dab49e0e6bf16ccad5052bf6e6826daad27dskia.committer@gmail.com 192a31eacb22e12a4223740e53ff5a11bd08340106ecommit-bot@chromium.org// OutputPossibleOverflows - We've found a possible overflow earlier, 1932b290cec9825da11d8e09074727cfaac5eca6453commit-bot@chromium.org// now check whether Body might contain a comparison which might be 1949fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com// preventing the overflow. 1959fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com// This doesn't do flow analysis, range analysis, or points-to analysis; it's 1969fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com// just a dumb "is there a comparison" scan. The aim here is to 1979fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com// detect the most blatent cases of overflow and educate the 1989fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com// programmer. 1999fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.comvoid MallocOverflowSecurityChecker::OutputPossibleOverflows( 2009fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com SmallVectorImpl<MallocOverflowCheck> &PossibleMallocOverflows, 2019fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com const Decl *D, BugReporter &BR, AnalysisManager &mgr) const { 2029fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com // By far the most common case: nothing to check. 2039fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com if (PossibleMallocOverflows.empty()) 2049fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com return; 205a31eacb22e12a4223740e53ff5a11bd08340106ecommit-bot@chromium.org 2069fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com // Delete any possible overflows which have a comparison. 2079fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com CheckOverflowOps c(PossibleMallocOverflows, BR.getContext()); 2089fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com c.Visit(mgr.getAnalysisDeclContext(D)->getBody()); 2099fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com 2109fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com // Output warnings for all overflows that are left. 2119fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com for (CheckOverflowOps::theVecType::iterator 212a31eacb22e12a4223740e53ff5a11bd08340106ecommit-bot@chromium.org i = PossibleMallocOverflows.begin(), 2139fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com e = PossibleMallocOverflows.end(); 2149fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com i != e; 2159fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com ++i) { 2169fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com BR.EmitBasicReport( 217 D, this, "malloc() size overflow", categories::UnixAPI, 218 "the computation of the size of the memory allocation may overflow", 219 PathDiagnosticLocation::createOperatorLoc(i->mulop, 220 BR.getSourceManager()), 221 i->mulop->getSourceRange()); 222 } 223} 224 225void MallocOverflowSecurityChecker::checkASTCodeBody(const Decl *D, 226 AnalysisManager &mgr, 227 BugReporter &BR) const { 228 229 CFG *cfg = mgr.getCFG(D); 230 if (!cfg) 231 return; 232 233 // A list of variables referenced in possibly overflowing malloc operands. 234 SmallVector<MallocOverflowCheck, 2> PossibleMallocOverflows; 235 236 for (CFG::iterator it = cfg->begin(), ei = cfg->end(); it != ei; ++it) { 237 CFGBlock *block = *it; 238 for (CFGBlock::iterator bi = block->begin(), be = block->end(); 239 bi != be; ++bi) { 240 if (Optional<CFGStmt> CS = bi->getAs<CFGStmt>()) { 241 if (const CallExpr *TheCall = dyn_cast<CallExpr>(CS->getStmt())) { 242 // Get the callee. 243 const FunctionDecl *FD = TheCall->getDirectCallee(); 244 245 if (!FD) 246 return; 247 248 // Get the name of the callee. If it's a builtin, strip off the prefix. 249 IdentifierInfo *FnInfo = FD->getIdentifier(); 250 if (!FnInfo) 251 return; 252 253 if (FnInfo->isStr ("malloc") || FnInfo->isStr ("_MALLOC")) { 254 if (TheCall->getNumArgs() == 1) 255 CheckMallocArgument(PossibleMallocOverflows, TheCall->getArg(0), 256 mgr.getASTContext()); 257 } 258 } 259 } 260 } 261 } 262 263 OutputPossibleOverflows(PossibleMallocOverflows, D, BR, mgr); 264} 265 266void 267ento::registerMallocOverflowSecurityChecker(CheckerManager &mgr) { 268 mgr.registerChecker<MallocOverflowSecurityChecker>(); 269} 270