1 // MmapWriteExecChecker.cpp - Check for the prot argument -----------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This checker tests the 3rd argument of mmap's calls to check if 11 // it is writable and executable in the same time. It's somehow 12 // an optional checker since for example in JIT libraries it is pretty common. 13 // 14 //===----------------------------------------------------------------------===// 15 16 #include "ClangSACheckers.h" 17 18 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 19 #include "clang/StaticAnalyzer/Core/Checker.h" 20 #include "clang/StaticAnalyzer/Core/CheckerManager.h" 21 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 22 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 23 24 using namespace clang; 25 using namespace ento; 26 using llvm::APSInt; 27 28 namespace { 29 class MmapWriteExecChecker : public Checker<check::PreCall> { 30 CallDescription MmapFn; 31 static int ProtWrite; 32 static int ProtExec; 33 mutable std::unique_ptr<BugType> BT; 34 public: 35 MmapWriteExecChecker() : MmapFn("mmap", 6) {} 36 void checkPreCall(const CallEvent &Call, CheckerContext &C) const; 37 }; 38 } 39 40 int MmapWriteExecChecker::ProtWrite = 0x02; 41 int MmapWriteExecChecker::ProtExec = 0x04; 42 43 void MmapWriteExecChecker::checkPreCall(const CallEvent &Call, 44 CheckerContext &C) const { 45 if (Call.isCalled(MmapFn)) { 46 llvm::Triple Triple = C.getASTContext().getTargetInfo().getTriple(); 47 48 if (Triple.isOSGlibc()) 49 ProtExec = 0x01; 50 51 SVal ProtVal = Call.getArgSVal(2); 52 Optional<nonloc::ConcreteInt> ProtLoc = ProtVal.getAs<nonloc::ConcreteInt>(); 53 int64_t Prot = ProtLoc->getValue().getSExtValue(); 54 55 if ((Prot & (ProtWrite | ProtExec)) == (ProtWrite | ProtExec)) { 56 if (!BT) 57 BT.reset(new BugType(this, "W^X check fails, Write Exec prot flags set", "Security")); 58 59 ExplodedNode *N = C.generateNonFatalErrorNode(); 60 if (!N) 61 return; 62 63 auto Report = llvm::make_unique<BugReport>( 64 *BT, "Both PROT_WRITE and PROT_EXEC flags had been set. It can " 65 "lead to exploitable memory regions, overwritten with malicious code" 66 , N); 67 Report->addRange(Call.getArgSourceRange(2)); 68 C.emitReport(std::move(Report)); 69 } 70 } 71 } 72 73 void ento::registerMmapWriteExecChecker(CheckerManager &mgr) { 74 mgr.registerChecker<MmapWriteExecChecker>(); 75 } 76