Index: compiler-rt/trunk/lib/asan/asan_rtl.cc =================================================================== --- compiler-rt/trunk/lib/asan/asan_rtl.cc +++ compiler-rt/trunk/lib/asan/asan_rtl.cc @@ -27,6 +27,10 @@ #include "sanitizer_common/sanitizer_atomic.h" #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_libc.h" +#if defined(__s390x__) && defined(__linux__) +// For AvoidCVE_2016_2143. +#include "sanitizer_common/sanitizer_linux.h" +#endif #include "sanitizer_common/sanitizer_symbolizer.h" #include "lsan/lsan_common.h" #include "ubsan/ubsan_init.h" @@ -415,6 +419,9 @@ AsanCheckIncompatibleRT(); AsanCheckDynamicRTPrereqs(); +#if defined(__s390x__) && defined(__linux__) + AvoidCVE_2016_2143(); +#endif SetCanPoisonMemory(flags()->poison_heap); SetMallocContextSize(common_flags()->malloc_context_size); Index: compiler-rt/trunk/lib/msan/msan.cc =================================================================== --- compiler-rt/trunk/lib/msan/msan.cc +++ compiler-rt/trunk/lib/msan/msan.cc @@ -22,6 +22,10 @@ #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_flag_parser.h" #include "sanitizer_common/sanitizer_libc.h" +#if defined(__s390x__) && defined(__linux__) +// For AvoidCVE_2016_2143. +#include "sanitizer_common/sanitizer_linux.h" +#endif #include "sanitizer_common/sanitizer_procmaps.h" #include "sanitizer_common/sanitizer_stacktrace.h" #include "sanitizer_common/sanitizer_symbolizer.h" @@ -375,6 +379,9 @@ msan_init_is_running = 1; SanitizerToolName = "MemorySanitizer"; +#if defined(__s390x__) && defined(__linux__) + AvoidCVE_2016_2143(); +#endif InitTlsSize(); CacheBinaryName(); Index: compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.h =================================================================== --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.h +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.h @@ -83,6 +83,11 @@ // Call cb for each region mapped by map. void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr)); + +#ifdef __s390x__ +// Aborts the process if running on a kernel without a fix for CVE-2016-2143. +void AvoidCVE_2016_2143(); +#endif } // namespace __sanitizer #endif // SANITIZER_FREEBSD || SANITIZER_LINUX Index: compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.cc =================================================================== --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.cc +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.cc @@ -56,6 +56,7 @@ #include #include #include +#include #include #include @@ -1346,6 +1347,72 @@ // No need to re-exec on Linux. } +#ifdef __s390x__ +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 or TSan with such kernel can and will crash your machine, or worse.\n" + "\n" + "If you are certain your kernel is not vulnerable (you have compiled it\n" + "yourself, are 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_FREEBSD || SANITIZER_LINUX Index: compiler-rt/trunk/lib/tsan/rtl/tsan_platform_linux.cc =================================================================== --- compiler-rt/trunk/lib/tsan/rtl/tsan_platform_linux.cc +++ compiler-rt/trunk/lib/tsan/rtl/tsan_platform_linux.cc @@ -247,6 +247,9 @@ #endif // #ifndef SANITIZER_GO void InitializePlatformEarly() { +#ifdef __s390x__ + AvoidCVE_2016_2143(); +#endif #ifdef TSAN_RUNTIME_VMA vmaSize = (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1);