13cab2bb3Spatrick //===-- sanitizer_linux_s390.cpp ------------------------------------------===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick //
93cab2bb3Spatrick // This file is shared between AddressSanitizer and ThreadSanitizer
103cab2bb3Spatrick // run-time libraries and implements s390-linux-specific functions from
113cab2bb3Spatrick // sanitizer_libc.h.
123cab2bb3Spatrick //===----------------------------------------------------------------------===//
133cab2bb3Spatrick
143cab2bb3Spatrick #include "sanitizer_platform.h"
153cab2bb3Spatrick
163cab2bb3Spatrick #if SANITIZER_LINUX && SANITIZER_S390
173cab2bb3Spatrick
181f9cb04fSpatrick #include <dlfcn.h>
193cab2bb3Spatrick #include <errno.h>
203cab2bb3Spatrick #include <sys/syscall.h>
213cab2bb3Spatrick #include <sys/utsname.h>
223cab2bb3Spatrick #include <unistd.h>
233cab2bb3Spatrick
241f9cb04fSpatrick #include "sanitizer_libc.h"
251f9cb04fSpatrick #include "sanitizer_linux.h"
261f9cb04fSpatrick
273cab2bb3Spatrick namespace __sanitizer {
283cab2bb3Spatrick
293cab2bb3Spatrick // --------------- sanitizer_libc.h
internal_mmap(void * addr,uptr length,int prot,int flags,int fd,u64 offset)303cab2bb3Spatrick uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd,
313cab2bb3Spatrick u64 offset) {
323cab2bb3Spatrick struct s390_mmap_params {
333cab2bb3Spatrick unsigned long addr;
343cab2bb3Spatrick unsigned long length;
353cab2bb3Spatrick unsigned long prot;
363cab2bb3Spatrick unsigned long flags;
373cab2bb3Spatrick unsigned long fd;
383cab2bb3Spatrick unsigned long offset;
393cab2bb3Spatrick } params = {
403cab2bb3Spatrick (unsigned long)addr,
413cab2bb3Spatrick (unsigned long)length,
423cab2bb3Spatrick (unsigned long)prot,
433cab2bb3Spatrick (unsigned long)flags,
443cab2bb3Spatrick (unsigned long)fd,
453cab2bb3Spatrick # ifdef __s390x__
463cab2bb3Spatrick (unsigned long)offset,
473cab2bb3Spatrick # else
483cab2bb3Spatrick (unsigned long)(offset / 4096),
493cab2bb3Spatrick # endif
503cab2bb3Spatrick };
513cab2bb3Spatrick # ifdef __s390x__
523cab2bb3Spatrick return syscall(__NR_mmap, ¶ms);
533cab2bb3Spatrick # else
543cab2bb3Spatrick return syscall(__NR_mmap2, ¶ms);
553cab2bb3Spatrick # endif
563cab2bb3Spatrick }
573cab2bb3Spatrick
internal_clone(int (* fn)(void *),void * child_stack,int flags,void * arg,int * parent_tidptr,void * newtls,int * child_tidptr)583cab2bb3Spatrick uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
593cab2bb3Spatrick int *parent_tidptr, void *newtls, int *child_tidptr) {
60*810390e3Srobert if (!fn || !child_stack) {
61*810390e3Srobert errno = EINVAL;
62*810390e3Srobert return -1;
63*810390e3Srobert }
643cab2bb3Spatrick CHECK_EQ(0, (uptr)child_stack % 16);
653cab2bb3Spatrick // Minimum frame size.
663cab2bb3Spatrick #ifdef __s390x__
673cab2bb3Spatrick child_stack = (char *)child_stack - 160;
683cab2bb3Spatrick #else
693cab2bb3Spatrick child_stack = (char *)child_stack - 96;
703cab2bb3Spatrick #endif
713cab2bb3Spatrick // Terminate unwind chain.
723cab2bb3Spatrick ((unsigned long *)child_stack)[0] = 0;
733cab2bb3Spatrick // And pass parameters.
743cab2bb3Spatrick ((unsigned long *)child_stack)[1] = (uptr)fn;
753cab2bb3Spatrick ((unsigned long *)child_stack)[2] = (uptr)arg;
76*810390e3Srobert register uptr res __asm__("r2");
773cab2bb3Spatrick register void *__cstack __asm__("r2") = child_stack;
78*810390e3Srobert register long __flags __asm__("r3") = flags;
793cab2bb3Spatrick register int * __ptidptr __asm__("r4") = parent_tidptr;
803cab2bb3Spatrick register int * __ctidptr __asm__("r5") = child_tidptr;
813cab2bb3Spatrick register void * __newtls __asm__("r6") = newtls;
823cab2bb3Spatrick
833cab2bb3Spatrick __asm__ __volatile__(
843cab2bb3Spatrick /* Clone. */
853cab2bb3Spatrick "svc %1\n"
863cab2bb3Spatrick
873cab2bb3Spatrick /* if (%r2 != 0)
883cab2bb3Spatrick * return;
893cab2bb3Spatrick */
903cab2bb3Spatrick #ifdef __s390x__
913cab2bb3Spatrick "cghi %%r2, 0\n"
923cab2bb3Spatrick #else
933cab2bb3Spatrick "chi %%r2, 0\n"
943cab2bb3Spatrick #endif
953cab2bb3Spatrick "jne 1f\n"
963cab2bb3Spatrick
973cab2bb3Spatrick /* Call "fn(arg)". */
983cab2bb3Spatrick #ifdef __s390x__
993cab2bb3Spatrick "lmg %%r1, %%r2, 8(%%r15)\n"
1003cab2bb3Spatrick #else
1013cab2bb3Spatrick "lm %%r1, %%r2, 4(%%r15)\n"
1023cab2bb3Spatrick #endif
1033cab2bb3Spatrick "basr %%r14, %%r1\n"
1043cab2bb3Spatrick
1053cab2bb3Spatrick /* Call _exit(%r2). */
1063cab2bb3Spatrick "svc %2\n"
1073cab2bb3Spatrick
1083cab2bb3Spatrick /* Return to parent. */
1093cab2bb3Spatrick "1:\n"
1103cab2bb3Spatrick : "=r" (res)
1113cab2bb3Spatrick : "i"(__NR_clone), "i"(__NR_exit),
1123cab2bb3Spatrick "r"(__cstack),
1133cab2bb3Spatrick "r"(__flags),
1143cab2bb3Spatrick "r"(__ptidptr),
1153cab2bb3Spatrick "r"(__ctidptr),
1163cab2bb3Spatrick "r"(__newtls)
1173cab2bb3Spatrick : "memory", "cc");
118*810390e3Srobert if (res >= (uptr)-4095) {
119*810390e3Srobert errno = -res;
120*810390e3Srobert return -1;
121*810390e3Srobert }
1223cab2bb3Spatrick return res;
1233cab2bb3Spatrick }
1243cab2bb3Spatrick
1253cab2bb3Spatrick #if SANITIZER_S390_64
FixedCVE_2016_2143()1263cab2bb3Spatrick static bool FixedCVE_2016_2143() {
1273cab2bb3Spatrick // Try to determine if the running kernel has a fix for CVE-2016-2143,
1283cab2bb3Spatrick // return false if in doubt (better safe than sorry). Distros may want to
1293cab2bb3Spatrick // adjust this for their own kernels.
1303cab2bb3Spatrick struct utsname buf;
1313cab2bb3Spatrick unsigned int major, minor, patch = 0;
1323cab2bb3Spatrick // This should never fail, but just in case...
1331f9cb04fSpatrick if (internal_uname(&buf))
1343cab2bb3Spatrick return false;
1353cab2bb3Spatrick const char *ptr = buf.release;
1363cab2bb3Spatrick major = internal_simple_strtoll(ptr, &ptr, 10);
1373cab2bb3Spatrick // At least first 2 should be matched.
1383cab2bb3Spatrick if (ptr[0] != '.')
1393cab2bb3Spatrick return false;
1403cab2bb3Spatrick minor = internal_simple_strtoll(ptr+1, &ptr, 10);
1413cab2bb3Spatrick // Third is optional.
1423cab2bb3Spatrick if (ptr[0] == '.')
1433cab2bb3Spatrick patch = internal_simple_strtoll(ptr+1, &ptr, 10);
1443cab2bb3Spatrick if (major < 3) {
1453cab2bb3Spatrick if (major == 2 && minor == 6 && patch == 32 && ptr[0] == '-' &&
1463cab2bb3Spatrick internal_strstr(ptr, ".el6")) {
1473cab2bb3Spatrick // Check RHEL6
1483cab2bb3Spatrick int r1 = internal_simple_strtoll(ptr+1, &ptr, 10);
1493cab2bb3Spatrick if (r1 >= 657) // 2.6.32-657.el6 or later
1503cab2bb3Spatrick return true;
1513cab2bb3Spatrick if (r1 == 642 && ptr[0] == '.') {
1523cab2bb3Spatrick int r2 = internal_simple_strtoll(ptr+1, &ptr, 10);
1533cab2bb3Spatrick if (r2 >= 9) // 2.6.32-642.9.1.el6 or later
1543cab2bb3Spatrick return true;
1553cab2bb3Spatrick }
1563cab2bb3Spatrick }
1573cab2bb3Spatrick // <3.0 is bad.
1583cab2bb3Spatrick return false;
1593cab2bb3Spatrick } else if (major == 3) {
1603cab2bb3Spatrick // 3.2.79+ is OK.
1613cab2bb3Spatrick if (minor == 2 && patch >= 79)
1623cab2bb3Spatrick return true;
1633cab2bb3Spatrick // 3.12.58+ is OK.
1643cab2bb3Spatrick if (minor == 12 && patch >= 58)
1653cab2bb3Spatrick return true;
1663cab2bb3Spatrick if (minor == 10 && patch == 0 && ptr[0] == '-' &&
1673cab2bb3Spatrick internal_strstr(ptr, ".el7")) {
1683cab2bb3Spatrick // Check RHEL7
1693cab2bb3Spatrick int r1 = internal_simple_strtoll(ptr+1, &ptr, 10);
1703cab2bb3Spatrick if (r1 >= 426) // 3.10.0-426.el7 or later
1713cab2bb3Spatrick return true;
1723cab2bb3Spatrick if (r1 == 327 && ptr[0] == '.') {
1733cab2bb3Spatrick int r2 = internal_simple_strtoll(ptr+1, &ptr, 10);
1743cab2bb3Spatrick if (r2 >= 27) // 3.10.0-327.27.1.el7 or later
1753cab2bb3Spatrick return true;
1763cab2bb3Spatrick }
1773cab2bb3Spatrick }
1783cab2bb3Spatrick // Otherwise, bad.
1793cab2bb3Spatrick return false;
1803cab2bb3Spatrick } else if (major == 4) {
1813cab2bb3Spatrick // 4.1.21+ is OK.
1823cab2bb3Spatrick if (minor == 1 && patch >= 21)
1833cab2bb3Spatrick return true;
1843cab2bb3Spatrick // 4.4.6+ is OK.
1853cab2bb3Spatrick if (minor == 4 && patch >= 6)
1863cab2bb3Spatrick return true;
1873cab2bb3Spatrick if (minor == 4 && patch == 0 && ptr[0] == '-' &&
1883cab2bb3Spatrick internal_strstr(buf.version, "Ubuntu")) {
1893cab2bb3Spatrick // Check Ubuntu 16.04
1903cab2bb3Spatrick int r1 = internal_simple_strtoll(ptr+1, &ptr, 10);
1913cab2bb3Spatrick if (r1 >= 13) // 4.4.0-13 or later
1923cab2bb3Spatrick return true;
1933cab2bb3Spatrick }
1943cab2bb3Spatrick // Otherwise, OK if 4.5+.
1953cab2bb3Spatrick return minor >= 5;
1963cab2bb3Spatrick } else {
1973cab2bb3Spatrick // Linux 5 and up are fine.
1983cab2bb3Spatrick return true;
1993cab2bb3Spatrick }
2003cab2bb3Spatrick }
2013cab2bb3Spatrick
AvoidCVE_2016_2143()2023cab2bb3Spatrick void AvoidCVE_2016_2143() {
2033cab2bb3Spatrick // Older kernels are affected by CVE-2016-2143 - they will crash hard
2043cab2bb3Spatrick // if someone uses 4-level page tables (ie. virtual addresses >= 4TB)
2053cab2bb3Spatrick // and fork() in the same process. Unfortunately, sanitizers tend to
2063cab2bb3Spatrick // require such addresses. Since this is very likely to crash the whole
2073cab2bb3Spatrick // machine (sanitizers themselves use fork() for llvm-symbolizer, for one),
2083cab2bb3Spatrick // abort the process at initialization instead.
2093cab2bb3Spatrick if (FixedCVE_2016_2143())
2103cab2bb3Spatrick return;
2113cab2bb3Spatrick if (GetEnv("SANITIZER_IGNORE_CVE_2016_2143"))
2123cab2bb3Spatrick return;
2133cab2bb3Spatrick Report(
2143cab2bb3Spatrick "ERROR: Your kernel seems to be vulnerable to CVE-2016-2143. Using ASan,\n"
2153cab2bb3Spatrick "MSan, TSan, DFSan or LSan with such kernel can and will crash your\n"
2163cab2bb3Spatrick "machine, or worse.\n"
2173cab2bb3Spatrick "\n"
2183cab2bb3Spatrick "If you are certain your kernel is not vulnerable (you have compiled it\n"
2193cab2bb3Spatrick "yourself, or are using an unrecognized distribution kernel), you can\n"
2203cab2bb3Spatrick "override this safety check by exporting SANITIZER_IGNORE_CVE_2016_2143\n"
2213cab2bb3Spatrick "with any value.\n");
2223cab2bb3Spatrick Die();
2233cab2bb3Spatrick }
2243cab2bb3Spatrick #endif
2253cab2bb3Spatrick
2263cab2bb3Spatrick } // namespace __sanitizer
2273cab2bb3Spatrick
2283cab2bb3Spatrick #endif // SANITIZER_LINUX && SANITIZER_S390
229