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