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