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