Home | History | Annotate | Download | only in sanitizer_common
      1 //===-- sanitizer_linux_s390.cc -------------------------------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // This file is shared between AddressSanitizer and ThreadSanitizer
     11 // run-time libraries and implements s390-linux-specific functions from
     12 // sanitizer_libc.h.
     13 //===----------------------------------------------------------------------===//
     14 
     15 #include "sanitizer_platform.h"
     16 
     17 #if SANITIZER_LINUX && SANITIZER_S390
     18 
     19 #include "sanitizer_libc.h"
     20 #include "sanitizer_linux.h"
     21 
     22 #include <errno.h>
     23 #include <sys/syscall.h>
     24 #include <sys/utsname.h>
     25 #include <unistd.h>
     26 
     27 namespace __sanitizer {
     28 
     29 // --------------- sanitizer_libc.h
     30 uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd,
     31                    OFF_T offset) {
     32   struct s390_mmap_params {
     33     unsigned long addr;
     34     unsigned long length;
     35     unsigned long prot;
     36     unsigned long flags;
     37     unsigned long fd;
     38     unsigned long offset;
     39   } params = {
     40     (unsigned long)addr,
     41     (unsigned long)length,
     42     (unsigned long)prot,
     43     (unsigned long)flags,
     44     (unsigned long)fd,
     45 # ifdef __s390x__
     46     (unsigned long)offset,
     47 # else
     48     (unsigned long)(offset / 4096),
     49 # endif
     50   };
     51 # ifdef __s390x__
     52   return syscall(__NR_mmap, &params);
     53 # else
     54   return syscall(__NR_mmap2, &params);
     55 # endif
     56 }
     57 
     58 uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
     59                     int *parent_tidptr, void *newtls, int *child_tidptr) {
     60   if (!fn || !child_stack)
     61     return -EINVAL;
     62   CHECK_EQ(0, (uptr)child_stack % 16);
     63   // Minimum frame size.
     64 #ifdef __s390x__
     65   child_stack = (char *)child_stack - 160;
     66 #else
     67   child_stack = (char *)child_stack - 96;
     68 #endif
     69   // Terminate unwind chain.
     70   ((unsigned long *)child_stack)[0] = 0;
     71   // And pass parameters.
     72   ((unsigned long *)child_stack)[1] = (uptr)fn;
     73   ((unsigned long *)child_stack)[2] = (uptr)arg;
     74   register long res __asm__("r2");
     75   register void *__cstack      __asm__("r2") = child_stack;
     76   register int __flags         __asm__("r3") = flags;
     77   register int * __ptidptr     __asm__("r4") = parent_tidptr;
     78   register int * __ctidptr     __asm__("r5") = child_tidptr;
     79   register void * __newtls     __asm__("r6") = newtls;
     80 
     81   __asm__ __volatile__(
     82                        /* Clone. */
     83                        "svc    %1\n"
     84 
     85                        /* if (%r2 != 0)
     86                         *   return;
     87                         */
     88 #ifdef __s390x__
     89                        "cghi   %%r2, 0\n"
     90 #else
     91                        "chi    %%r2, 0\n"
     92 #endif
     93                        "jne    1f\n"
     94 
     95                        /* Call "fn(arg)". */
     96 #ifdef __s390x__
     97                        "lmg    %%r1, %%r2, 8(%%r15)\n"
     98 #else
     99                        "lm     %%r1, %%r2, 4(%%r15)\n"
    100 #endif
    101                        "basr   %%r14, %%r1\n"
    102 
    103                        /* Call _exit(%r2). */
    104                        "svc %2\n"
    105 
    106                        /* Return to parent. */
    107                      "1:\n"
    108                        : "=r" (res)
    109                        : "i"(__NR_clone), "i"(__NR_exit),
    110                          "r"(__cstack),
    111                          "r"(__flags),
    112                          "r"(__ptidptr),
    113                          "r"(__ctidptr),
    114                          "r"(__newtls)
    115                        : "memory", "cc");
    116   return res;
    117 }
    118 
    119 #if SANITIZER_S390_64
    120 static bool FixedCVE_2016_2143() {
    121   // Try to determine if the running kernel has a fix for CVE-2016-2143,
    122   // return false if in doubt (better safe than sorry).  Distros may want to
    123   // adjust this for their own kernels.
    124   struct utsname buf;
    125   unsigned int major, minor, patch = 0;
    126   // This should never fail, but just in case...
    127   if (uname(&buf))
    128     return false;
    129   char *ptr = buf.release;
    130   major = internal_simple_strtoll(ptr, &ptr, 10);
    131   // At least first 2 should be matched.
    132   if (ptr[0] != '.')
    133     return false;
    134   minor = internal_simple_strtoll(ptr+1, &ptr, 10);
    135   // Third is optional.
    136   if (ptr[0] == '.')
    137     patch = internal_simple_strtoll(ptr+1, &ptr, 10);
    138   if (major < 3) {
    139     // <3.0 is bad.
    140     return false;
    141   } else if (major == 3) {
    142     // 3.2.79+ is OK.
    143     if (minor == 2 && patch >= 79)
    144       return true;
    145     // 3.12.58+ is OK.
    146     if (minor == 12 && patch >= 58)
    147       return true;
    148     // Otherwise, bad.
    149     return false;
    150   } else if (major == 4) {
    151     // 4.1.21+ is OK.
    152     if (minor == 1 && patch >= 21)
    153       return true;
    154     // 4.4.6+ is OK.
    155     if (minor == 4 && patch >= 6)
    156       return true;
    157     // Otherwise, OK if 4.5+.
    158     return minor >= 5;
    159   } else {
    160     // Linux 5 and up are fine.
    161     return true;
    162   }
    163 }
    164 
    165 void AvoidCVE_2016_2143() {
    166   // Older kernels are affected by CVE-2016-2143 - they will crash hard
    167   // if someone uses 4-level page tables (ie. virtual addresses >= 4TB)
    168   // and fork() in the same process.  Unfortunately, sanitizers tend to
    169   // require such addresses.  Since this is very likely to crash the whole
    170   // machine (sanitizers themselves use fork() for llvm-symbolizer, for one),
    171   // abort the process at initialization instead.
    172   if (FixedCVE_2016_2143())
    173     return;
    174   if (GetEnv("SANITIZER_IGNORE_CVE_2016_2143"))
    175     return;
    176   Report(
    177     "ERROR: Your kernel seems to be vulnerable to CVE-2016-2143.  Using ASan,\n"
    178     "MSan, TSan, DFSan or LSan with such kernel can and will crash your\n"
    179     "machine, or worse.\n"
    180     "\n"
    181     "If you are certain your kernel is not vulnerable (you have compiled it\n"
    182     "yourself, or are using an unrecognized distribution kernel), you can\n"
    183     "override this safety check by exporting SANITIZER_IGNORE_CVE_2016_2143\n"
    184     "with any value.\n");
    185   Die();
    186 }
    187 #endif
    188 
    189 } // namespace __sanitizer
    190 
    191 #endif // SANITIZER_LINUX && SANITIZER_S390
    192