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, ¶ms); 53 # else 54 return syscall(__NR_mmap2, ¶ms); 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