1e5dd7070Spatrick // MmapWriteExecChecker.cpp - Check for the prot argument -----------------===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick // This checker tests the 3rd argument of mmap's calls to check if
10e5dd7070Spatrick // it is writable and executable in the same time. It's somehow
11e5dd7070Spatrick // an optional checker since for example in JIT libraries it is pretty common.
12e5dd7070Spatrick //
13e5dd7070Spatrick //===----------------------------------------------------------------------===//
14e5dd7070Spatrick
15e5dd7070Spatrick #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
16e5dd7070Spatrick
17e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
18e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/Checker.h"
19e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/CheckerManager.h"
20*12c85518Srobert #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
21e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
22e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
23e5dd7070Spatrick
24e5dd7070Spatrick using namespace clang;
25e5dd7070Spatrick using namespace ento;
26e5dd7070Spatrick
27e5dd7070Spatrick namespace {
28e5dd7070Spatrick class MmapWriteExecChecker : public Checker<check::PreCall> {
29e5dd7070Spatrick CallDescription MmapFn;
30e5dd7070Spatrick CallDescription MprotectFn;
31e5dd7070Spatrick static int ProtWrite;
32e5dd7070Spatrick static int ProtExec;
33e5dd7070Spatrick static int ProtRead;
34e5dd7070Spatrick mutable std::unique_ptr<BugType> BT;
35e5dd7070Spatrick public:
MmapWriteExecChecker()36*12c85518Srobert MmapWriteExecChecker() : MmapFn({"mmap"}, 6), MprotectFn({"mprotect"}, 3) {}
37e5dd7070Spatrick void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
38e5dd7070Spatrick int ProtExecOv;
39e5dd7070Spatrick int ProtReadOv;
40e5dd7070Spatrick };
41e5dd7070Spatrick }
42e5dd7070Spatrick
43e5dd7070Spatrick int MmapWriteExecChecker::ProtWrite = 0x02;
44e5dd7070Spatrick int MmapWriteExecChecker::ProtExec = 0x04;
45e5dd7070Spatrick int MmapWriteExecChecker::ProtRead = 0x01;
46e5dd7070Spatrick
checkPreCall(const CallEvent & Call,CheckerContext & C) const47e5dd7070Spatrick void MmapWriteExecChecker::checkPreCall(const CallEvent &Call,
48e5dd7070Spatrick CheckerContext &C) const {
49*12c85518Srobert if (matchesAny(Call, MmapFn, MprotectFn)) {
50e5dd7070Spatrick SVal ProtVal = Call.getArgSVal(2);
51*12c85518Srobert auto ProtLoc = ProtVal.castAs<nonloc::ConcreteInt>();
52*12c85518Srobert int64_t Prot = ProtLoc.getValue().getSExtValue();
53e5dd7070Spatrick if (ProtExecOv != ProtExec)
54e5dd7070Spatrick ProtExec = ProtExecOv;
55e5dd7070Spatrick if (ProtReadOv != ProtRead)
56e5dd7070Spatrick ProtRead = ProtReadOv;
57e5dd7070Spatrick
58e5dd7070Spatrick // Wrong settings
59e5dd7070Spatrick if (ProtRead == ProtExec)
60e5dd7070Spatrick return;
61e5dd7070Spatrick
62e5dd7070Spatrick if ((Prot & (ProtWrite | ProtExec)) == (ProtWrite | ProtExec)) {
63e5dd7070Spatrick if (!BT)
64e5dd7070Spatrick BT.reset(new BugType(this, "W^X check fails, Write Exec prot flags set", "Security"));
65e5dd7070Spatrick
66e5dd7070Spatrick ExplodedNode *N = C.generateNonFatalErrorNode();
67e5dd7070Spatrick if (!N)
68e5dd7070Spatrick return;
69e5dd7070Spatrick
70e5dd7070Spatrick auto Report = std::make_unique<PathSensitiveBugReport>(
71e5dd7070Spatrick *BT, "Both PROT_WRITE and PROT_EXEC flags are set. This can "
72e5dd7070Spatrick "lead to exploitable memory regions, which could be overwritten "
73e5dd7070Spatrick "with malicious code", N);
74e5dd7070Spatrick Report->addRange(Call.getArgSourceRange(2));
75e5dd7070Spatrick C.emitReport(std::move(Report));
76e5dd7070Spatrick }
77e5dd7070Spatrick }
78e5dd7070Spatrick }
79e5dd7070Spatrick
registerMmapWriteExecChecker(CheckerManager & mgr)80e5dd7070Spatrick void ento::registerMmapWriteExecChecker(CheckerManager &mgr) {
81e5dd7070Spatrick MmapWriteExecChecker *Mwec =
82e5dd7070Spatrick mgr.registerChecker<MmapWriteExecChecker>();
83e5dd7070Spatrick Mwec->ProtExecOv =
84e5dd7070Spatrick mgr.getAnalyzerOptions()
85e5dd7070Spatrick .getCheckerIntegerOption(Mwec, "MmapProtExec");
86e5dd7070Spatrick Mwec->ProtReadOv =
87e5dd7070Spatrick mgr.getAnalyzerOptions()
88e5dd7070Spatrick .getCheckerIntegerOption(Mwec, "MmapProtRead");
89e5dd7070Spatrick }
90e5dd7070Spatrick
shouldRegisterMmapWriteExecChecker(const CheckerManager & mgr)91ec727ea7Spatrick bool ento::shouldRegisterMmapWriteExecChecker(const CheckerManager &mgr) {
92e5dd7070Spatrick return true;
93e5dd7070Spatrick }
94