1 //===-- sanitizer_linux_s390.cpp ------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file is shared between AddressSanitizer and ThreadSanitizer 10 // run-time libraries and implements s390-linux-specific functions from 11 // sanitizer_libc.h. 12 //===----------------------------------------------------------------------===// 13 14 #include "sanitizer_platform.h" 15 16 #if SANITIZER_LINUX && SANITIZER_S390 17 18 #include <dlfcn.h> 19 #include <errno.h> 20 #include <sys/syscall.h> 21 #include <sys/utsname.h> 22 #include <unistd.h> 23 24 #include "sanitizer_libc.h" 25 #include "sanitizer_linux.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 u64 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 errno = EINVAL; 62 return -1; 63 } 64 CHECK_EQ(0, (uptr)child_stack % 16); 65 // Minimum frame size. 66 #ifdef __s390x__ 67 child_stack = (char *)child_stack - 160; 68 #else 69 child_stack = (char *)child_stack - 96; 70 #endif 71 // Terminate unwind chain. 72 ((unsigned long *)child_stack)[0] = 0; 73 // And pass parameters. 74 ((unsigned long *)child_stack)[1] = (uptr)fn; 75 ((unsigned long *)child_stack)[2] = (uptr)arg; 76 register uptr res __asm__("r2"); 77 register void *__cstack __asm__("r2") = child_stack; 78 register long __flags __asm__("r3") = flags; 79 register int * __ptidptr __asm__("r4") = parent_tidptr; 80 register int * __ctidptr __asm__("r5") = child_tidptr; 81 register void * __newtls __asm__("r6") = newtls; 82 83 __asm__ __volatile__( 84 /* Clone. */ 85 "svc %1\n" 86 87 /* if (%r2 != 0) 88 * return; 89 */ 90 #ifdef __s390x__ 91 "cghi %%r2, 0\n" 92 #else 93 "chi %%r2, 0\n" 94 #endif 95 "jne 1f\n" 96 97 /* Call "fn(arg)". */ 98 #ifdef __s390x__ 99 "lmg %%r1, %%r2, 8(%%r15)\n" 100 #else 101 "lm %%r1, %%r2, 4(%%r15)\n" 102 #endif 103 "basr %%r14, %%r1\n" 104 105 /* Call _exit(%r2). */ 106 "svc %2\n" 107 108 /* Return to parent. */ 109 "1:\n" 110 : "=r" (res) 111 : "i"(__NR_clone), "i"(__NR_exit), 112 "r"(__cstack), 113 "r"(__flags), 114 "r"(__ptidptr), 115 "r"(__ctidptr), 116 "r"(__newtls) 117 : "memory", "cc"); 118 if (res >= (uptr)-4095) { 119 errno = -res; 120 return -1; 121 } 122 return res; 123 } 124 125 #if SANITIZER_S390_64 126 static bool FixedCVE_2016_2143() { 127 // Try to determine if the running kernel has a fix for CVE-2016-2143, 128 // return false if in doubt (better safe than sorry). Distros may want to 129 // adjust this for their own kernels. 130 struct utsname buf; 131 unsigned int major, minor, patch = 0; 132 // This should never fail, but just in case... 133 if (internal_uname(&buf)) 134 return false; 135 const char *ptr = buf.release; 136 major = internal_simple_strtoll(ptr, &ptr, 10); 137 // At least first 2 should be matched. 138 if (ptr[0] != '.') 139 return false; 140 minor = internal_simple_strtoll(ptr+1, &ptr, 10); 141 // Third is optional. 142 if (ptr[0] == '.') 143 patch = internal_simple_strtoll(ptr+1, &ptr, 10); 144 if (major < 3) { 145 if (major == 2 && minor == 6 && patch == 32 && ptr[0] == '-' && 146 internal_strstr(ptr, ".el6")) { 147 // Check RHEL6 148 int r1 = internal_simple_strtoll(ptr+1, &ptr, 10); 149 if (r1 >= 657) // 2.6.32-657.el6 or later 150 return true; 151 if (r1 == 642 && ptr[0] == '.') { 152 int r2 = internal_simple_strtoll(ptr+1, &ptr, 10); 153 if (r2 >= 9) // 2.6.32-642.9.1.el6 or later 154 return true; 155 } 156 } 157 // <3.0 is bad. 158 return false; 159 } else if (major == 3) { 160 // 3.2.79+ is OK. 161 if (minor == 2 && patch >= 79) 162 return true; 163 // 3.12.58+ is OK. 164 if (minor == 12 && patch >= 58) 165 return true; 166 if (minor == 10 && patch == 0 && ptr[0] == '-' && 167 internal_strstr(ptr, ".el7")) { 168 // Check RHEL7 169 int r1 = internal_simple_strtoll(ptr+1, &ptr, 10); 170 if (r1 >= 426) // 3.10.0-426.el7 or later 171 return true; 172 if (r1 == 327 && ptr[0] == '.') { 173 int r2 = internal_simple_strtoll(ptr+1, &ptr, 10); 174 if (r2 >= 27) // 3.10.0-327.27.1.el7 or later 175 return true; 176 } 177 } 178 // Otherwise, bad. 179 return false; 180 } else if (major == 4) { 181 // 4.1.21+ is OK. 182 if (minor == 1 && patch >= 21) 183 return true; 184 // 4.4.6+ is OK. 185 if (minor == 4 && patch >= 6) 186 return true; 187 if (minor == 4 && patch == 0 && ptr[0] == '-' && 188 internal_strstr(buf.version, "Ubuntu")) { 189 // Check Ubuntu 16.04 190 int r1 = internal_simple_strtoll(ptr+1, &ptr, 10); 191 if (r1 >= 13) // 4.4.0-13 or later 192 return true; 193 } 194 // Otherwise, OK if 4.5+. 195 return minor >= 5; 196 } else { 197 // Linux 5 and up are fine. 198 return true; 199 } 200 } 201 202 void AvoidCVE_2016_2143() { 203 // Older kernels are affected by CVE-2016-2143 - they will crash hard 204 // if someone uses 4-level page tables (ie. virtual addresses >= 4TB) 205 // and fork() in the same process. Unfortunately, sanitizers tend to 206 // require such addresses. Since this is very likely to crash the whole 207 // machine (sanitizers themselves use fork() for llvm-symbolizer, for one), 208 // abort the process at initialization instead. 209 if (FixedCVE_2016_2143()) 210 return; 211 if (GetEnv("SANITIZER_IGNORE_CVE_2016_2143")) 212 return; 213 Report( 214 "ERROR: Your kernel seems to be vulnerable to CVE-2016-2143. Using ASan,\n" 215 "MSan, TSan, DFSan or LSan with such kernel can and will crash your\n" 216 "machine, or worse.\n" 217 "\n" 218 "If you are certain your kernel is not vulnerable (you have compiled it\n" 219 "yourself, or are using an unrecognized distribution kernel), you can\n" 220 "override this safety check by exporting SANITIZER_IGNORE_CVE_2016_2143\n" 221 "with any value.\n"); 222 Die(); 223 } 224 #endif 225 226 } // namespace __sanitizer 227 228 #endif // SANITIZER_LINUX && SANITIZER_S390 229