[llvm] [llvm][Support][Memory] Add memfd based fallback for strict W^X Linux systems (PR #98538)

Jannik Glückert via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 1 13:03:04 PDT 2024


================
@@ -251,5 +320,50 @@ void Memory::InvalidateInstructionCache(const void *Addr, size_t Len) {
   ValgrindDiscardTranslations(Addr, Len);
 }
 
+static inline bool isPermissionError(int err) {
+  // PaX uses EPERM, SELinux uses EACCES
+  return err == EPERM || err == EACCES;
+}
+
+bool Memory::execProtectionChangeNeedsNewMapping() {
+#if defined(__linux__)
+  static int status = -1;
+
+  if (status != -1)
+    return status;
+
+  // Try to get the status from /proc/self/status, looking for PaX flags.
+  if (auto file = MemoryBuffer::getFileAsStream("/proc/self/status")) {
+    auto pax_flags =
+        (*file)->getBuffer().rsplit("PaX:").second.split('\n').first.trim();
+    if (!pax_flags.empty())
+      // 'M' indicates MPROTECT is enabled
+      return (status = pax_flags.find('M') != StringRef::npos);
+  }
+
+  // Create a temporary writable mapping and try to make it executable.  If
+  // this fails, test 'errno' to ensure it failed because we were not allowed
+  // to create such a mapping and not because of some transient error.
+  size_t size = Process::getPageSizeEstimate();
+  void *addr = ::mmap(NULL, size, PROT_READ | PROT_WRITE,
+                      MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+  if (addr == MAP_FAILED) {
+    // Must be low on memory or have too many mappings already, not much we can
+    // do here.
+    status = 0;
+  } else {
+    if (::mprotect(addr, size, PROT_READ | PROT_EXEC) < 0)
+      status = isPermissionError(errno);
----------------
Jannik2099 wrote:

I (and I bet everyone else who works on selinux policies) would still much prefer being overly cautious rather than causing an AVC denial to detect `execmem` support.
It means we'd have to add a suppression for everything that uses the llvm jit, which means losing any information / audit logging on when a program unintentionally tries to use `execmem`.

https://github.com/llvm/llvm-project/pull/98538


More information about the llvm-commits mailing list