-
Notifications
You must be signed in to change notification settings - Fork 15.1k
[clang][analyzer] MmapWriteExecChecker improvements #97078
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Read the 'mmap' flags from macro values and use a better test for the error situation .
|
@llvm/pr-subscribers-clang-static-analyzer-1 Author: Balázs Kéri (balazske) ChangesRead the 'mmap' flags from macro values and use a better test for the error situation. Full diff: https://github.com/llvm/llvm-project/pull/97078.diff 2 Files Affected:
diff --git a/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp
index cd1dd1b2fc511..a5a2bd62b47d6 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp
@@ -21,30 +21,55 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
using namespace clang;
using namespace ento;
namespace {
-class MmapWriteExecChecker : public Checker<check::PreCall> {
+class MmapWriteExecChecker
+ : public Checker<check::BeginFunction, check::PreCall> {
CallDescription MmapFn{CDM::CLibrary, {"mmap"}, 6};
CallDescription MprotectFn{CDM::CLibrary, {"mprotect"}, 3};
- static int ProtWrite;
- static int ProtExec;
- static int ProtRead;
const BugType BT{this, "W^X check fails, Write Exec prot flags set",
"Security"};
+ mutable bool FlagsInitialized = false;
+ mutable int ProtRead = 0x01;
+ mutable int ProtWrite = 0x02;
+ mutable int ProtExec = 0x04;
+
public:
+ void checkBeginFunction(CheckerContext &C) const;
void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
+
int ProtExecOv;
int ProtReadOv;
};
}
-int MmapWriteExecChecker::ProtWrite = 0x02;
-int MmapWriteExecChecker::ProtExec = 0x04;
-int MmapWriteExecChecker::ProtRead = 0x01;
+void MmapWriteExecChecker::checkBeginFunction(CheckerContext &C) const {
+ if (FlagsInitialized)
+ return;
+
+ FlagsInitialized = true;
+
+ const std::optional<int> FoundProtRead =
+ tryExpandAsInteger("PROT_READ", C.getPreprocessor());
+ const std::optional<int> FoundProtWrite =
+ tryExpandAsInteger("PROT_WRITE", C.getPreprocessor());
+ const std::optional<int> FoundProtExec =
+ tryExpandAsInteger("PROT_EXEC", C.getPreprocessor());
+ if (FoundProtRead && FoundProtWrite && FoundProtExec) {
+ ProtRead = *FoundProtRead;
+ ProtWrite = *FoundProtWrite;
+ ProtExec = *FoundProtExec;
+ } else {
+ // FIXME: Are these useful?
+ ProtRead = ProtReadOv;
+ ProtExec = ProtExecOv;
+ }
+}
void MmapWriteExecChecker::checkPreCall(const CallEvent &Call,
CheckerContext &C) const {
@@ -54,16 +79,8 @@ void MmapWriteExecChecker::checkPreCall(const CallEvent &Call,
if (!ProtLoc)
return;
int64_t Prot = ProtLoc->getValue().getSExtValue();
- if (ProtExecOv != ProtExec)
- ProtExec = ProtExecOv;
- if (ProtReadOv != ProtRead)
- ProtRead = ProtReadOv;
-
- // Wrong settings
- if (ProtRead == ProtExec)
- return;
- if ((Prot & (ProtWrite | ProtExec)) == (ProtWrite | ProtExec)) {
+ if ((Prot & ProtWrite) && (Prot & ProtExec)) {
ExplodedNode *N = C.generateNonFatalErrorNode();
if (!N)
return;
diff --git a/clang/test/Analysis/mmap-writeexec.c b/clang/test/Analysis/mmap-writeexec.c
index 8fd86ceb9d2a2..88fcc7788e683 100644
--- a/clang/test/Analysis/mmap-writeexec.c
+++ b/clang/test/Analysis/mmap-writeexec.c
@@ -1,13 +1,14 @@
// RUN: %clang_analyze_cc1 -triple i686-unknown-linux -analyzer-checker=alpha.security.MmapWriteExec -analyzer-config alpha.security.MmapWriteExec:MmapProtExec=1 -analyzer-config alpha.security.MmapWriteExec:MmapProtRead=4 -DUSE_ALTERNATIVE_PROT_EXEC_DEFINITION -verify %s
// RUN: %clang_analyze_cc1 -triple x86_64-unknown-apple-darwin10 -analyzer-checker=alpha.security.MmapWriteExec -verify %s
-#define PROT_WRITE 0x02
#ifndef USE_ALTERNATIVE_PROT_EXEC_DEFINITION
-#define PROT_EXEC 0x04
-#define PROT_READ 0x01
-#else
#define PROT_EXEC 0x01
+#define PROT_WRITE 0x02
#define PROT_READ 0x04
+#else
+#define PROT_EXEC 0x08
+#define PROT_WRITE 0x04
+#define PROT_READ 0x02
#endif
#define MAP_PRIVATE 0x0002
#define MAP_ANON 0x1000
|
|
@llvm/pr-subscribers-clang Author: Balázs Kéri (balazske) ChangesRead the 'mmap' flags from macro values and use a better test for the error situation. Full diff: https://github.com/llvm/llvm-project/pull/97078.diff 2 Files Affected:
diff --git a/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp
index cd1dd1b2fc511..a5a2bd62b47d6 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp
@@ -21,30 +21,55 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
using namespace clang;
using namespace ento;
namespace {
-class MmapWriteExecChecker : public Checker<check::PreCall> {
+class MmapWriteExecChecker
+ : public Checker<check::BeginFunction, check::PreCall> {
CallDescription MmapFn{CDM::CLibrary, {"mmap"}, 6};
CallDescription MprotectFn{CDM::CLibrary, {"mprotect"}, 3};
- static int ProtWrite;
- static int ProtExec;
- static int ProtRead;
const BugType BT{this, "W^X check fails, Write Exec prot flags set",
"Security"};
+ mutable bool FlagsInitialized = false;
+ mutable int ProtRead = 0x01;
+ mutable int ProtWrite = 0x02;
+ mutable int ProtExec = 0x04;
+
public:
+ void checkBeginFunction(CheckerContext &C) const;
void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
+
int ProtExecOv;
int ProtReadOv;
};
}
-int MmapWriteExecChecker::ProtWrite = 0x02;
-int MmapWriteExecChecker::ProtExec = 0x04;
-int MmapWriteExecChecker::ProtRead = 0x01;
+void MmapWriteExecChecker::checkBeginFunction(CheckerContext &C) const {
+ if (FlagsInitialized)
+ return;
+
+ FlagsInitialized = true;
+
+ const std::optional<int> FoundProtRead =
+ tryExpandAsInteger("PROT_READ", C.getPreprocessor());
+ const std::optional<int> FoundProtWrite =
+ tryExpandAsInteger("PROT_WRITE", C.getPreprocessor());
+ const std::optional<int> FoundProtExec =
+ tryExpandAsInteger("PROT_EXEC", C.getPreprocessor());
+ if (FoundProtRead && FoundProtWrite && FoundProtExec) {
+ ProtRead = *FoundProtRead;
+ ProtWrite = *FoundProtWrite;
+ ProtExec = *FoundProtExec;
+ } else {
+ // FIXME: Are these useful?
+ ProtRead = ProtReadOv;
+ ProtExec = ProtExecOv;
+ }
+}
void MmapWriteExecChecker::checkPreCall(const CallEvent &Call,
CheckerContext &C) const {
@@ -54,16 +79,8 @@ void MmapWriteExecChecker::checkPreCall(const CallEvent &Call,
if (!ProtLoc)
return;
int64_t Prot = ProtLoc->getValue().getSExtValue();
- if (ProtExecOv != ProtExec)
- ProtExec = ProtExecOv;
- if (ProtReadOv != ProtRead)
- ProtRead = ProtReadOv;
-
- // Wrong settings
- if (ProtRead == ProtExec)
- return;
- if ((Prot & (ProtWrite | ProtExec)) == (ProtWrite | ProtExec)) {
+ if ((Prot & ProtWrite) && (Prot & ProtExec)) {
ExplodedNode *N = C.generateNonFatalErrorNode();
if (!N)
return;
diff --git a/clang/test/Analysis/mmap-writeexec.c b/clang/test/Analysis/mmap-writeexec.c
index 8fd86ceb9d2a2..88fcc7788e683 100644
--- a/clang/test/Analysis/mmap-writeexec.c
+++ b/clang/test/Analysis/mmap-writeexec.c
@@ -1,13 +1,14 @@
// RUN: %clang_analyze_cc1 -triple i686-unknown-linux -analyzer-checker=alpha.security.MmapWriteExec -analyzer-config alpha.security.MmapWriteExec:MmapProtExec=1 -analyzer-config alpha.security.MmapWriteExec:MmapProtRead=4 -DUSE_ALTERNATIVE_PROT_EXEC_DEFINITION -verify %s
// RUN: %clang_analyze_cc1 -triple x86_64-unknown-apple-darwin10 -analyzer-checker=alpha.security.MmapWriteExec -verify %s
-#define PROT_WRITE 0x02
#ifndef USE_ALTERNATIVE_PROT_EXEC_DEFINITION
-#define PROT_EXEC 0x04
-#define PROT_READ 0x01
-#else
#define PROT_EXEC 0x01
+#define PROT_WRITE 0x02
#define PROT_READ 0x04
+#else
+#define PROT_EXEC 0x08
+#define PROT_WRITE 0x04
+#define PROT_READ 0x02
#endif
#define MAP_PRIVATE 0x0002
#define MAP_ANON 0x1000
|
steakhal
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good. I only had some minor remarks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, straightforward change. Thanks!
EDIT: I posted this review without noticing that in the meantime @steakhal did his own review with some valuable suggestions. I'd still say that the PR would be acceptable without those stylistic tweaks, but if you apply them, then it'll be even better.
| ProtWrite = *FoundProtWrite; | ||
| ProtExec = *FoundProtExec; | ||
| } else { | ||
| // FIXME: Are these useful? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They are not too useful (and it's a little bit surprising that there is no "ProtWriteOv"), but they're harmless and they don't require complex code, so let's keep them for now.
|
I removed the options to specify |
steakhal
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks!
Nice cleanup.
clang/test/Analysis/mmap-writeexec.c
Outdated
| @@ -1,13 +1,14 @@ | |||
| // RUN: %clang_analyze_cc1 -triple i686-unknown-linux -analyzer-checker=alpha.security.MmapWriteExec -analyzer-config alpha.security.MmapWriteExec:MmapProtExec=1 -analyzer-config alpha.security.MmapWriteExec:MmapProtRead=4 -DUSE_ALTERNATIVE_PROT_EXEC_DEFINITION -verify %s | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, isn't the -analyzer-config alpha.security.MmapWriteExec:MmapProtRead=4 obsolete?
Why does this not error out with such a config?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was really a test failure, fixed now.
|
Please make sure that the premerge bots are happy before merging. |
|
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/52/builds/1169 Here is the relevant piece of the build log for the reference: |
Read the 'mmap' flags from macro values and use a better test for the error situation.