sanitizer_linux_s390.cpp 7.0 KB

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