[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/D18915 llvm-svn: 266297
This commit is contained in:
parent
0ffa9eaa4a
commit
c8dda336bb
@ -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 @@ static void AsanInitInternal() {
|
||||
|
||||
AsanCheckIncompatibleRT();
|
||||
AsanCheckDynamicRTPrereqs();
|
||||
#if defined(__s390x__) && defined(__linux__)
|
||||
AvoidCVE_2016_2143();
|
||||
#endif
|
||||
|
||||
SetCanPoisonMemory(flags()->poison_heap);
|
||||
SetMallocContextSize(common_flags()->malloc_context_size);
|
||||
|
||||
@ -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 @@ void __msan_init() {
|
||||
msan_init_is_running = 1;
|
||||
SanitizerToolName = "MemorySanitizer";
|
||||
|
||||
#if defined(__s390x__) && defined(__linux__)
|
||||
AvoidCVE_2016_2143();
|
||||
#endif
|
||||
InitTlsSize();
|
||||
|
||||
CacheBinaryName();
|
||||
|
||||
@ -56,6 +56,7 @@
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <ucontext.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@ -1346,6 +1347,72 @@ void MaybeReexec() {
|
||||
// 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
|
||||
|
||||
@ -83,6 +83,11 @@ bool LibraryNameIs(const char *full_name, const char *base_name);
|
||||
|
||||
// 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
|
||||
|
||||
@ -247,6 +247,9 @@ static void InitDataSeg() {
|
||||
#endif // #ifndef SANITIZER_GO
|
||||
|
||||
void InitializePlatformEarly() {
|
||||
#ifdef __s390x__
|
||||
AvoidCVE_2016_2143();
|
||||
#endif
|
||||
#ifdef TSAN_RUNTIME_VMA
|
||||
vmaSize =
|
||||
(MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user