start_up.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  4. */
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <stdarg.h>
  8. #include <unistd.h>
  9. #include <errno.h>
  10. #include <fcntl.h>
  11. #include <sched.h>
  12. #include <signal.h>
  13. #include <string.h>
  14. #include <sys/mman.h>
  15. #include <sys/stat.h>
  16. #include <sys/wait.h>
  17. #include <sys/time.h>
  18. #include <sys/resource.h>
  19. #include <asm/ldt.h>
  20. #include <asm/unistd.h>
  21. #include <init.h>
  22. #include <os.h>
  23. #include <kern_util.h>
  24. #include <mem_user.h>
  25. #include <ptrace_user.h>
  26. #include <registers.h>
  27. #include <skas.h>
  28. #include "internal.h"
  29. static void ptrace_child(void)
  30. {
  31. int ret;
  32. /* Calling os_getpid because some libcs cached getpid incorrectly */
  33. int pid = os_getpid(), ppid = getppid();
  34. int sc_result;
  35. if (change_sig(SIGWINCH, 0) < 0 ||
  36. ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) {
  37. perror("ptrace");
  38. kill(pid, SIGKILL);
  39. }
  40. kill(pid, SIGSTOP);
  41. /*
  42. * This syscall will be intercepted by the parent. Don't call more than
  43. * once, please.
  44. */
  45. sc_result = os_getpid();
  46. if (sc_result == pid)
  47. /* Nothing modified by the parent, we are running normally. */
  48. ret = 1;
  49. else if (sc_result == ppid)
  50. /*
  51. * Expected in check_ptrace and check_sysemu when they succeed
  52. * in modifying the stack frame
  53. */
  54. ret = 0;
  55. else
  56. /* Serious trouble! This could be caused by a bug in host 2.6
  57. * SKAS3/2.6 patch before release -V6, together with a bug in
  58. * the UML code itself.
  59. */
  60. ret = 2;
  61. exit(ret);
  62. }
  63. static void fatal_perror(const char *str)
  64. {
  65. perror(str);
  66. exit(1);
  67. }
  68. static void fatal(char *fmt, ...)
  69. {
  70. va_list list;
  71. va_start(list, fmt);
  72. vfprintf(stderr, fmt, list);
  73. va_end(list);
  74. exit(1);
  75. }
  76. static void non_fatal(char *fmt, ...)
  77. {
  78. va_list list;
  79. va_start(list, fmt);
  80. vfprintf(stderr, fmt, list);
  81. va_end(list);
  82. }
  83. static int start_ptraced_child(void)
  84. {
  85. int pid, n, status;
  86. fflush(stdout);
  87. pid = fork();
  88. if (pid == 0)
  89. ptrace_child();
  90. else if (pid < 0)
  91. fatal_perror("start_ptraced_child : fork failed");
  92. CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
  93. if (n < 0)
  94. fatal_perror("check_ptrace : waitpid failed");
  95. if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP))
  96. fatal("check_ptrace : expected SIGSTOP, got status = %d",
  97. status);
  98. return pid;
  99. }
  100. static void stop_ptraced_child(int pid, int exitcode)
  101. {
  102. int status, n;
  103. if (ptrace(PTRACE_CONT, pid, 0, 0) < 0)
  104. fatal_perror("stop_ptraced_child : ptrace failed");
  105. CATCH_EINTR(n = waitpid(pid, &status, 0));
  106. if (!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) {
  107. int exit_with = WEXITSTATUS(status);
  108. fatal("stop_ptraced_child : child exited with exitcode %d, "
  109. "while expecting %d; status 0x%x\n", exit_with,
  110. exitcode, status);
  111. }
  112. }
  113. static void __init check_sysemu(void)
  114. {
  115. int pid, n, status, count=0;
  116. os_info("Checking syscall emulation for ptrace...");
  117. pid = start_ptraced_child();
  118. if ((ptrace(PTRACE_SETOPTIONS, pid, 0,
  119. (void *) PTRACE_O_TRACESYSGOOD) < 0))
  120. fatal_perror("check_sysemu: PTRACE_SETOPTIONS failed");
  121. while (1) {
  122. count++;
  123. if (ptrace(PTRACE_SYSEMU_SINGLESTEP, pid, 0, 0) < 0)
  124. goto fail;
  125. CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
  126. if (n < 0)
  127. fatal_perror("check_sysemu: wait failed");
  128. if (WIFSTOPPED(status) &&
  129. (WSTOPSIG(status) == (SIGTRAP|0x80))) {
  130. if (!count) {
  131. non_fatal("check_sysemu: SYSEMU_SINGLESTEP "
  132. "doesn't singlestep");
  133. goto fail;
  134. }
  135. n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET,
  136. os_getpid());
  137. if (n < 0)
  138. fatal_perror("check_sysemu : failed to modify "
  139. "system call return");
  140. break;
  141. }
  142. else if (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP))
  143. count++;
  144. else {
  145. non_fatal("check_sysemu: expected SIGTRAP or "
  146. "(SIGTRAP | 0x80), got status = %d\n",
  147. status);
  148. goto fail;
  149. }
  150. }
  151. stop_ptraced_child(pid, 0);
  152. os_info("OK\n");
  153. return;
  154. fail:
  155. stop_ptraced_child(pid, 1);
  156. fatal("missing\n");
  157. }
  158. static void __init check_ptrace(void)
  159. {
  160. int pid, syscall, n, status;
  161. os_info("Checking that ptrace can change system call numbers...");
  162. pid = start_ptraced_child();
  163. if ((ptrace(PTRACE_SETOPTIONS, pid, 0,
  164. (void *) PTRACE_O_TRACESYSGOOD) < 0))
  165. fatal_perror("check_ptrace: PTRACE_SETOPTIONS failed");
  166. while (1) {
  167. if (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
  168. fatal_perror("check_ptrace : ptrace failed");
  169. CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
  170. if (n < 0)
  171. fatal_perror("check_ptrace : wait failed");
  172. if (!WIFSTOPPED(status) ||
  173. (WSTOPSIG(status) != (SIGTRAP | 0x80)))
  174. fatal("check_ptrace : expected (SIGTRAP|0x80), "
  175. "got status = %d", status);
  176. syscall = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_NR_OFFSET,
  177. 0);
  178. if (syscall == __NR_getpid) {
  179. n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET,
  180. __NR_getppid);
  181. if (n < 0)
  182. fatal_perror("check_ptrace : failed to modify "
  183. "system call");
  184. break;
  185. }
  186. }
  187. stop_ptraced_child(pid, 0);
  188. os_info("OK\n");
  189. check_sysemu();
  190. }
  191. static void __init check_coredump_limit(void)
  192. {
  193. struct rlimit lim;
  194. int err = getrlimit(RLIMIT_CORE, &lim);
  195. if (err) {
  196. perror("Getting core dump limit");
  197. return;
  198. }
  199. os_info("Core dump limits :\n\tsoft - ");
  200. if (lim.rlim_cur == RLIM_INFINITY)
  201. os_info("NONE\n");
  202. else
  203. os_info("%llu\n", (unsigned long long)lim.rlim_cur);
  204. os_info("\thard - ");
  205. if (lim.rlim_max == RLIM_INFINITY)
  206. os_info("NONE\n");
  207. else
  208. os_info("%llu\n", (unsigned long long)lim.rlim_max);
  209. }
  210. void __init get_host_cpu_features(
  211. void (*flags_helper_func)(char *line),
  212. void (*cache_helper_func)(char *line))
  213. {
  214. FILE *cpuinfo;
  215. char *line = NULL;
  216. size_t len = 0;
  217. int done_parsing = 0;
  218. cpuinfo = fopen("/proc/cpuinfo", "r");
  219. if (cpuinfo == NULL) {
  220. os_info("Failed to get host CPU features\n");
  221. } else {
  222. while ((getline(&line, &len, cpuinfo)) != -1) {
  223. if (strstr(line, "flags")) {
  224. flags_helper_func(line);
  225. done_parsing++;
  226. }
  227. if (strstr(line, "cache_alignment")) {
  228. cache_helper_func(line);
  229. done_parsing++;
  230. }
  231. free(line);
  232. line = NULL;
  233. if (done_parsing > 1)
  234. break;
  235. }
  236. fclose(cpuinfo);
  237. }
  238. }
  239. void __init os_early_checks(void)
  240. {
  241. int pid;
  242. /* Print out the core dump limits early */
  243. check_coredump_limit();
  244. check_ptrace();
  245. /* Need to check this early because mmapping happens before the
  246. * kernel is running.
  247. */
  248. check_tmpexec();
  249. pid = start_ptraced_child();
  250. if (init_pid_registers(pid))
  251. fatal("Failed to initialize default registers");
  252. stop_ptraced_child(pid, 1);
  253. }
  254. int __init parse_iomem(char *str, int *add)
  255. {
  256. struct iomem_region *new;
  257. struct stat64 buf;
  258. char *file, *driver;
  259. int fd, size;
  260. driver = str;
  261. file = strchr(str,',');
  262. if (file == NULL) {
  263. os_warn("parse_iomem : failed to parse iomem\n");
  264. goto out;
  265. }
  266. *file = '\0';
  267. file++;
  268. fd = open(file, O_RDWR, 0);
  269. if (fd < 0) {
  270. perror("parse_iomem - Couldn't open io file");
  271. goto out;
  272. }
  273. if (fstat64(fd, &buf) < 0) {
  274. perror("parse_iomem - cannot stat_fd file");
  275. goto out_close;
  276. }
  277. new = malloc(sizeof(*new));
  278. if (new == NULL) {
  279. perror("Couldn't allocate iomem_region struct");
  280. goto out_close;
  281. }
  282. size = (buf.st_size + UM_KERN_PAGE_SIZE) & ~(UM_KERN_PAGE_SIZE - 1);
  283. *new = ((struct iomem_region) { .next = iomem_regions,
  284. .driver = driver,
  285. .fd = fd,
  286. .size = size,
  287. .phys = 0,
  288. .virt = 0 });
  289. iomem_regions = new;
  290. iomem_size += new->size + UM_KERN_PAGE_SIZE;
  291. return 0;
  292. out_close:
  293. close(fd);
  294. out:
  295. return 1;
  296. }