devnexen updated this revision to Diff 132873.

Repository:
  rC Clang

https://reviews.llvm.org/D42645

Files:
  include/clang/StaticAnalyzer/Checkers/Checkers.td
  lib/StaticAnalyzer/Checkers/CMakeLists.txt
  lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp
  test/Analysis/mmap-writeexec.c

Index: test/Analysis/mmap-writeexec.c
===================================================================
--- test/Analysis/mmap-writeexec.c
+++ test/Analysis/mmap-writeexec.c
@@ -0,0 +1,31 @@
+// RUN: %clang_analyze_cc1 -triple i686-unknown-linux -analyzer-checker=security.MmapWriteExec -verify %s
+// RUN: %clang_analyze_cc1 -triple x86_64-unknown-apple-darwin10 -analyzer-checker=security.MmapWriteExec -verify %s
+
+#define PROT_READ   0x01
+#define PROT_WRITE  0x02
+#define PROT_EXEC   0x04
+#define MAP_PRIVATE 0x0002
+#define MAP_ANON    0x1000
+#define MAP_FIXED   0x0010
+#define NULL        ((void *)0)
+
+typedef __typeof(sizeof(int)) size_t;
+void *mmap(void *, size_t, int, int, int, long);
+
+void f1()
+{
+  void *a = mmap(NULL, 16, PROT_READ | PROT_EXEC, MAP_PRIVATE | MAP_ANON, -1, 0); // no-warning
+  void *b = mmap(a, 16, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED | MAP_ANON, -1, 0); // no-warning
+  void *c = mmap(NULL, 32, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON, -1, 0); // expected-warning{{Both PROT_WRITE and PROT_EXEC flags are set. This can lead to exploitable memory regions, which could be overwritten with malicious code}}
+  (void)a;
+  (void)b;
+  (void)c;
+}
+
+void f2()
+{
+  void *(*callm)(void *, size_t, int, int, int, long);
+  callm = mmap;
+  int prot = PROT_WRITE | PROT_EXEC;
+  (void)callm(NULL, 1024, prot, MAP_PRIVATE | MAP_ANON, -1, 0); // expected-warning{{Both PROT_WRITE and PROT_EXEC flags are set. This can lead to exploitable memory regions, which could be overwritten with malicious code}}
+}
Index: lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp
+++ lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp
@@ -0,0 +1,75 @@
+// MmapWriteExecChecker.cpp - Check for the prot argument -----------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This checker tests the 3rd argument of mmap's calls to check if
+// it is writable and executable in the same time. It's somehow
+// an optional checker since for example in JIT libraries it is pretty common.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangSACheckers.h"
+
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+
+using namespace clang;
+using namespace ento;
+using llvm::APSInt;
+
+namespace {
+class MmapWriteExecChecker : public Checker<check::PreCall> {
+  CallDescription MmapFn;
+  static int ProtWrite;
+  static int ProtExec;
+  mutable std::unique_ptr<BugType> BT;
+public:
+  MmapWriteExecChecker() : MmapFn("mmap", 6) {}
+  void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
+};
+}
+
+int MmapWriteExecChecker::ProtWrite = 0x02;
+int MmapWriteExecChecker::ProtExec  = 0x04;
+
+void MmapWriteExecChecker::checkPreCall(const CallEvent &Call,
+                                         CheckerContext &C) const {
+  if (Call.isCalled(MmapFn)) {
+    llvm::Triple Triple = C.getASTContext().getTargetInfo().getTriple();
+
+    if (Triple.isOSGlibc())
+      ProtExec = 0x01;
+
+    SVal ProtVal = Call.getArgSVal(2); 
+    Optional<nonloc::ConcreteInt> ProtLoc = ProtVal.getAs<nonloc::ConcreteInt>();
+    int64_t Prot = ProtLoc->getValue().getSExtValue();
+
+    if ((Prot & (ProtWrite | ProtExec)) == (ProtWrite | ProtExec)) {
+      if (!BT)
+        BT.reset(new BugType(this, "W^X check fails, Write Exec prot flags set", "Security"));
+
+      ExplodedNode *N = C.generateNonFatalErrorNode();
+      if (!N)
+        return;
+
+      auto Report = llvm::make_unique<BugReport>(
+          *BT, "Both PROT_WRITE and PROT_EXEC flags are set. This can "
+               "lead to exploitable memory regions, which could be overwritten "
+               "with malicious code", N);
+      Report->addRange(Call.getArgSourceRange(2));
+      C.emitReport(std::move(Report));
+    }
+  }
+}
+
+void ento::registerMmapWriteExecChecker(CheckerManager &mgr) {
+  mgr.registerChecker<MmapWriteExecChecker>();
+}
Index: lib/StaticAnalyzer/Checkers/CMakeLists.txt
===================================================================
--- lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -49,6 +49,7 @@
   MallocChecker.cpp
   MallocOverflowSecurityChecker.cpp
   MallocSizeofChecker.cpp
+  MmapWriteExecChecker.cpp
   MisusedMovedObjectChecker.cpp
   MPI-Checker/MPIBugReporter.cpp
   MPI-Checker/MPIChecker.cpp
Index: include/clang/StaticAnalyzer/Checkers/Checkers.td
===================================================================
--- include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -394,6 +394,10 @@
   def FloatLoopCounter : Checker<"FloatLoopCounter">,
     HelpText<"Warn on using a floating point value as a loop counter (CERT: FLP30-C, FLP30-CPP)">,
     DescFile<"CheckSecuritySyntaxOnly.cpp">;
+
+  def MmapWriteExecChecker : Checker<"MmapWriteExec">,
+    HelpText<"Warn on mmap() calls that are both writable and executable">,
+    DescFile<"MmapWriteExecChecker.cpp">;
 }
 
 let ParentPackage = SecurityAlpha in {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to