• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
internal_mmap(void * addr,uptr length,int prot,int flags,int fd,u64 offset)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, &params);
53 # else
54   return syscall(__NR_mmap2, &params);
55 # endif
56 }
57 
internal_clone(int (* fn)(void *),void * child_stack,int flags,void * arg,int * parent_tidptr,void * newtls,int * child_tidptr)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
FixedCVE_2016_2143()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 (internal_uname(&buf))
128     return false;
129   const 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     if (major == 2 && minor == 6 && patch == 32 && ptr[0] == '-' &&
140         internal_strstr(ptr, ".el6")) {
141       // Check RHEL6
142       int r1 = internal_simple_strtoll(ptr+1, &ptr, 10);
143       if (r1 >= 657) // 2.6.32-657.el6 or later
144         return true;
145       if (r1 == 642 && ptr[0] == '.') {
146         int r2 = internal_simple_strtoll(ptr+1, &ptr, 10);
147         if (r2 >= 9) // 2.6.32-642.9.1.el6 or later
148           return true;
149       }
150     }
151     // <3.0 is bad.
152     return false;
153   } else if (major == 3) {
154     // 3.2.79+ is OK.
155     if (minor == 2 && patch >= 79)
156       return true;
157     // 3.12.58+ is OK.
158     if (minor == 12 && patch >= 58)
159       return true;
160     if (minor == 10 && patch == 0 && ptr[0] == '-' &&
161         internal_strstr(ptr, ".el7")) {
162       // Check RHEL7
163       int r1 = internal_simple_strtoll(ptr+1, &ptr, 10);
164       if (r1 >= 426) // 3.10.0-426.el7 or later
165         return true;
166       if (r1 == 327 && ptr[0] == '.') {
167         int r2 = internal_simple_strtoll(ptr+1, &ptr, 10);
168         if (r2 >= 27) // 3.10.0-327.27.1.el7 or later
169           return true;
170       }
171     }
172     // Otherwise, bad.
173     return false;
174   } else if (major == 4) {
175     // 4.1.21+ is OK.
176     if (minor == 1 && patch >= 21)
177       return true;
178     // 4.4.6+ is OK.
179     if (minor == 4 && patch >= 6)
180       return true;
181     if (minor == 4 && patch == 0 && ptr[0] == '-' &&
182         internal_strstr(buf.version, "Ubuntu")) {
183       // Check Ubuntu 16.04
184       int r1 = internal_simple_strtoll(ptr+1, &ptr, 10);
185       if (r1 >= 13) // 4.4.0-13 or later
186         return true;
187     }
188     // Otherwise, OK if 4.5+.
189     return minor >= 5;
190   } else {
191     // Linux 5 and up are fine.
192     return true;
193   }
194 }
195 
AvoidCVE_2016_2143()196 void AvoidCVE_2016_2143() {
197   // Older kernels are affected by CVE-2016-2143 - they will crash hard
198   // if someone uses 4-level page tables (ie. virtual addresses >= 4TB)
199   // and fork() in the same process.  Unfortunately, sanitizers tend to
200   // require such addresses.  Since this is very likely to crash the whole
201   // machine (sanitizers themselves use fork() for llvm-symbolizer, for one),
202   // abort the process at initialization instead.
203   if (FixedCVE_2016_2143())
204     return;
205   if (GetEnv("SANITIZER_IGNORE_CVE_2016_2143"))
206     return;
207   Report(
208     "ERROR: Your kernel seems to be vulnerable to CVE-2016-2143.  Using 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