]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_linux_s390.cc
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / llvm-project / compiler-rt / lib / sanitizer_common / sanitizer_linux_s390.cc
1 //===-- sanitizer_linux_s390.cc -------------------------------------------===//
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 "sanitizer_libc.h"
19 #include "sanitizer_linux.h"
20
21 #include <errno.h>
22 #include <sys/syscall.h>
23 #include <sys/utsname.h>
24 #include <unistd.h>
25
26 namespace __sanitizer {
27
28 // --------------- sanitizer_libc.h
29 uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd,
30                    OFF_T offset) {
31   struct s390_mmap_params {
32     unsigned long addr;
33     unsigned long length;
34     unsigned long prot;
35     unsigned long flags;
36     unsigned long fd;
37     unsigned long offset;
38   } params = {
39     (unsigned long)addr,
40     (unsigned long)length,
41     (unsigned long)prot,
42     (unsigned long)flags,
43     (unsigned long)fd,
44 # ifdef __s390x__
45     (unsigned long)offset,
46 # else
47     (unsigned long)(offset / 4096),
48 # endif
49   };
50 # ifdef __s390x__
51   return syscall(__NR_mmap, &params);
52 # else
53   return syscall(__NR_mmap2, &params);
54 # endif
55 }
56
57 uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
58                     int *parent_tidptr, void *newtls, int *child_tidptr) {
59   if (!fn || !child_stack)
60     return -EINVAL;
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 long res __asm__("r2");
74   register void *__cstack      __asm__("r2") = child_stack;
75   register int __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),
109                          "r"(__cstack),
110                          "r"(__flags),
111                          "r"(__ptidptr),
112                          "r"(__ctidptr),
113                          "r"(__newtls)
114                        : "memory", "cc");
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 (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 ASan,\n"
208     "MSan, TSan, DFSan or LSan with such kernel can and will crash your\n"
209     "machine, or worse.\n"
210     "\n"
211     "If you are certain your kernel is not vulnerable (you have compiled it\n"
212     "yourself, or are using an unrecognized distribution kernel), you can\n"
213     "override this safety check by exporting SANITIZER_IGNORE_CVE_2016_2143\n"
214     "with any value.\n");
215   Die();
216 }
217 #endif
218
219 } // namespace __sanitizer
220
221 #endif // SANITIZER_LINUX && SANITIZER_S390