summaryrefslogtreecommitdiff
path: root/lib/sanitizer_common
diff options
context:
space:
mode:
authorMarcin Koscielnicki <koriakin@0x04.net>2016-04-27 17:42:00 +0000
committerMarcin Koscielnicki <koriakin@0x04.net>2016-04-27 17:42:00 +0000
commita6a82f392638c9afac77850851e7e8f0f5ddb2a3 (patch)
treeb180c78a59fd6870781df621feb787fbf936024d /lib/sanitizer_common
parent0b438ec2e633815383ef034b11e90f92d6af1323 (diff)
[sanitizer] [SystemZ] Abort if the kernel might be vulnerable to CVE-2016-2143.
In short, CVE-2016-2143 will crash the machine if a process uses both >4TB virtual addresses and fork(). ASan, TSan, and MSan will, by necessity, map a sizable chunk of virtual address space, which is much larger than 4TB. Even worse, sanitizers will always use fork() for llvm-symbolizer when a bug is detected. Disable all three by aborting on process initialization if the running kernel version is not known to contain a fix. Unfortunately, there's no reliable way to detect the fix without crashing the kernel. So, we rely on whitelisting - I've included a list of upstream kernel versions that will work. In case someone uses a distribution kernel or applied the fix themselves, an override switch is also included. Differential Revision: http://reviews.llvm.org/D19576 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@267747 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/sanitizer_common')
-rw-r--r--lib/sanitizer_common/sanitizer_common.h10
-rw-r--r--lib/sanitizer_common/sanitizer_linux_s390.cc69
2 files changed, 79 insertions, 0 deletions
diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h
index 4cf5b7e77..5aaedde59 100644
--- a/lib/sanitizer_common/sanitizer_common.h
+++ b/lib/sanitizer_common/sanitizer_common.h
@@ -809,6 +809,16 @@ RunOnDestruction<Fn> at_scope_exit(Fn fn) {
return RunOnDestruction<Fn>(fn);
}
+// Linux on 64-bit s390 had a nasty bug that crashes the whole machine
+// if a process uses virtual memory over 4TB (as many sanitizers like
+// to do). This function will abort the process if running on a kernel
+// that looks vulnerable.
+#if SANITIZER_LINUX && SANITIZER_S390_64
+void AvoidCVE_2016_2143();
+#else
+INLINE void AvoidCVE_2016_2143() {}
+#endif
+
} // namespace __sanitizer
inline void *operator new(__sanitizer::operator_new_size_type size,
diff --git a/lib/sanitizer_common/sanitizer_linux_s390.cc b/lib/sanitizer_common/sanitizer_linux_s390.cc
index 03a19ea97..27c3c7d08 100644
--- a/lib/sanitizer_common/sanitizer_linux_s390.cc
+++ b/lib/sanitizer_common/sanitizer_linux_s390.cc
@@ -16,10 +16,12 @@
#if SANITIZER_LINUX && SANITIZER_S390
+#include "sanitizer_libc.h"
#include "sanitizer_linux.h"
#include <errno.h>
#include <sys/syscall.h>
+#include <sys/utsname.h>
#include <unistd.h>
namespace __sanitizer {
@@ -114,6 +116,73 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
return res;
}
+#if SANITIZER_S390_64
+static bool FixedCVE_2016_2143() {
+ // Try to determine if the running kernel has a fix for CVE-2016-2143,
+ // return false if in doubt (better safe than sorry). Distros may want to
+ // adjust this for their own kernels.
+ struct utsname buf;
+ unsigned int major, minor, patch = 0;
+ // This should never fail, but just in case...
+ if (uname(&buf))
+ return false;
+ char *ptr = buf.release;
+ major = internal_simple_strtoll(ptr, &ptr, 10);
+ // At least first 2 should be matched.
+ if (ptr[0] != '.')
+ return false;
+ minor = internal_simple_strtoll(ptr+1, &ptr, 10);
+ // Third is optional.
+ if (ptr[0] == '.')
+ patch = internal_simple_strtoll(ptr+1, &ptr, 10);
+ if (major < 3) {
+ // <3.0 is bad.
+ return false;
+ } else if (major == 3) {
+ // 3.2.79+ is OK.
+ if (minor == 2 && patch >= 79)
+ return true;
+ // Otherwise, bad.
+ return false;
+ } else if (major == 4) {
+ // 4.1.21+ is OK.
+ if (minor == 1 && patch >= 21)
+ return true;
+ // 4.4.6+ is OK.
+ if (minor == 4 && patch >= 6)
+ return true;
+ // Otherwise, OK if 4.5+.
+ return minor >= 5;
+ } else {
+ // Linux 5 and up are fine.
+ return true;
+ }
+}
+
+void AvoidCVE_2016_2143() {
+ // Older kernels are affected by CVE-2016-2143 - they will crash hard
+ // if someone uses 4-level page tables (ie. virtual addresses >= 4TB)
+ // and fork() in the same process. Unfortunately, sanitizers tend to
+ // require such addresses. Since this is very likely to crash the whole
+ // machine (sanitizers themselves use fork() for llvm-symbolizer, for one),
+ // abort the process at initialization instead.
+ if (FixedCVE_2016_2143())
+ return;
+ if (GetEnv("SANITIZER_IGNORE_CVE_2016_2143"))
+ return;
+ Report(
+ "ERROR: Your kernel seems to be vulnerable to CVE-2016-2143. Using ASan,\n"
+ "MSan, TSan, DFSan or LSan with such kernel can and will crash your\n"
+ "machine, or worse.\n"
+ "\n"
+ "If you are certain your kernel is not vulnerable (you have compiled it\n"
+ "yourself, or are using an unrecognized distribution kernel), you can\n"
+ "override this safety check by exporting SANITIZER_IGNORE_CVE_2016_2143\n"
+ "with any value.\n");
+ Die();
+}
+#endif
+
} // namespace __sanitizer
#endif // SANITIZER_LINUX && SANITIZER_S390