start_up.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. /*
  2. * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  3. * Licensed under the GPL
  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/unistd.h>
  20. #include <init.h>
  21. #include <os.h>
  22. #include <mem_user.h>
  23. #include <ptrace_user.h>
  24. #include <registers.h>
  25. #include <skas.h>
  26. static void ptrace_child(void)
  27. {
  28. int ret;
  29. /* Calling os_getpid because some libcs cached getpid incorrectly */
  30. int pid = os_getpid(), ppid = getppid();
  31. int sc_result;
  32. if (change_sig(SIGWINCH, 0) < 0 ||
  33. ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) {
  34. perror("ptrace");
  35. kill(pid, SIGKILL);
  36. }
  37. kill(pid, SIGSTOP);
  38. /*
  39. * This syscall will be intercepted by the parent. Don't call more than
  40. * once, please.
  41. */
  42. sc_result = os_getpid();
  43. if (sc_result == pid)
  44. /* Nothing modified by the parent, we are running normally. */
  45. ret = 1;
  46. else if (sc_result == ppid)
  47. /*
  48. * Expected in check_ptrace and check_sysemu when they succeed
  49. * in modifying the stack frame
  50. */
  51. ret = 0;
  52. else
  53. /* Serious trouble! This could be caused by a bug in host 2.6
  54. * SKAS3/2.6 patch before release -V6, together with a bug in
  55. * the UML code itself.
  56. */
  57. ret = 2;
  58. exit(ret);
  59. }
  60. static void fatal_perror(const char *str)
  61. {
  62. perror(str);
  63. exit(1);
  64. }
  65. static void fatal(char *fmt, ...)
  66. {
  67. va_list list;
  68. va_start(list, fmt);
  69. vfprintf(stderr, fmt, list);
  70. va_end(list);
  71. exit(1);
  72. }
  73. static void non_fatal(char *fmt, ...)
  74. {
  75. va_list list;
  76. va_start(list, fmt);
  77. vfprintf(stderr, fmt, list);
  78. va_end(list);
  79. }
  80. static int start_ptraced_child(void)
  81. {
  82. int pid, n, status;
  83. fflush(stdout);
  84. pid = fork();
  85. if (pid == 0)
  86. ptrace_child();
  87. else if (pid < 0)
  88. fatal_perror("start_ptraced_child : fork failed");
  89. CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
  90. if (n < 0)
  91. fatal_perror("check_ptrace : waitpid failed");
  92. if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP))
  93. fatal("check_ptrace : expected SIGSTOP, got status = %d",
  94. status);
  95. return pid;
  96. }
  97. /* When testing for SYSEMU support, if it is one of the broken versions, we
  98. * must just avoid using sysemu, not panic, but only if SYSEMU features are
  99. * broken.
  100. * So only for SYSEMU features we test mustpanic, while normal host features
  101. * must work anyway!
  102. */
  103. static int stop_ptraced_child(int pid, int exitcode, int mustexit)
  104. {
  105. int status, n, ret = 0;
  106. if (ptrace(PTRACE_CONT, pid, 0, 0) < 0) {
  107. perror("stop_ptraced_child : ptrace failed");
  108. return -1;
  109. }
  110. CATCH_EINTR(n = waitpid(pid, &status, 0));
  111. if (!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) {
  112. int exit_with = WEXITSTATUS(status);
  113. if (exit_with == 2)
  114. non_fatal("check_ptrace : child exited with status 2. "
  115. "\nDisabling SYSEMU support.\n");
  116. non_fatal("check_ptrace : child exited with exitcode %d, while "
  117. "expecting %d; status 0x%x\n", exit_with,
  118. exitcode, status);
  119. if (mustexit)
  120. exit(1);
  121. ret = -1;
  122. }
  123. return ret;
  124. }
  125. /* Changed only during early boot */
  126. static int force_sysemu_disabled = 0;
  127. static int __init nosysemu_cmd_param(char *str, int* add)
  128. {
  129. force_sysemu_disabled = 1;
  130. return 0;
  131. }
  132. __uml_setup("nosysemu", nosysemu_cmd_param,
  133. "nosysemu\n"
  134. " Turns off syscall emulation patch for ptrace (SYSEMU).\n"
  135. " SYSEMU is a performance-patch introduced by Laurent Vivier. It changes\n"
  136. " behaviour of ptrace() and helps reduce host context switch rates.\n"
  137. " To make it work, you need a kernel patch for your host, too.\n"
  138. " See http://perso.wanadoo.fr/laurent.vivier/UML/ for further \n"
  139. " information.\n\n");
  140. static void __init check_sysemu(void)
  141. {
  142. unsigned long regs[MAX_REG_NR];
  143. int pid, n, status, count=0;
  144. os_info("Checking syscall emulation patch for ptrace...");
  145. sysemu_supported = 0;
  146. pid = start_ptraced_child();
  147. if (ptrace(PTRACE_SYSEMU, pid, 0, 0) < 0)
  148. goto fail;
  149. CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
  150. if (n < 0)
  151. fatal_perror("check_sysemu : wait failed");
  152. if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP))
  153. fatal("check_sysemu : expected SIGTRAP, got status = %d\n",
  154. status);
  155. if (ptrace(PTRACE_GETREGS, pid, 0, regs) < 0)
  156. fatal_perror("check_sysemu : PTRACE_GETREGS failed");
  157. if (PT_SYSCALL_NR(regs) != __NR_getpid) {
  158. non_fatal("check_sysemu got system call number %d, "
  159. "expected %d...", PT_SYSCALL_NR(regs), __NR_getpid);
  160. goto fail;
  161. }
  162. n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET, os_getpid());
  163. if (n < 0) {
  164. non_fatal("check_sysemu : failed to modify system call "
  165. "return");
  166. goto fail;
  167. }
  168. if (stop_ptraced_child(pid, 0, 0) < 0)
  169. goto fail_stopped;
  170. sysemu_supported = 1;
  171. os_info("OK\n");
  172. set_using_sysemu(!force_sysemu_disabled);
  173. os_info("Checking advanced syscall emulation patch for ptrace...");
  174. pid = start_ptraced_child();
  175. if ((ptrace(PTRACE_OLDSETOPTIONS, pid, 0,
  176. (void *) PTRACE_O_TRACESYSGOOD) < 0))
  177. fatal_perror("check_sysemu: PTRACE_OLDSETOPTIONS failed");
  178. while (1) {
  179. count++;
  180. if (ptrace(PTRACE_SYSEMU_SINGLESTEP, pid, 0, 0) < 0)
  181. goto fail;
  182. CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
  183. if (n < 0)
  184. fatal_perror("check_sysemu: wait failed");
  185. if (WIFSTOPPED(status) &&
  186. (WSTOPSIG(status) == (SIGTRAP|0x80))) {
  187. if (!count) {
  188. non_fatal("check_sysemu: SYSEMU_SINGLESTEP "
  189. "doesn't singlestep");
  190. goto fail;
  191. }
  192. n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET,
  193. os_getpid());
  194. if (n < 0)
  195. fatal_perror("check_sysemu : failed to modify "
  196. "system call return");
  197. break;
  198. }
  199. else if (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP))
  200. count++;
  201. else {
  202. non_fatal("check_sysemu: expected SIGTRAP or "
  203. "(SIGTRAP | 0x80), got status = %d\n",
  204. status);
  205. goto fail;
  206. }
  207. }
  208. if (stop_ptraced_child(pid, 0, 0) < 0)
  209. goto fail_stopped;
  210. sysemu_supported = 2;
  211. os_info("OK\n");
  212. if (!force_sysemu_disabled)
  213. set_using_sysemu(sysemu_supported);
  214. return;
  215. fail:
  216. stop_ptraced_child(pid, 1, 0);
  217. fail_stopped:
  218. non_fatal("missing\n");
  219. }
  220. static void __init check_ptrace(void)
  221. {
  222. int pid, syscall, n, status;
  223. os_info("Checking that ptrace can change system call numbers...");
  224. pid = start_ptraced_child();
  225. if ((ptrace(PTRACE_OLDSETOPTIONS, pid, 0,
  226. (void *) PTRACE_O_TRACESYSGOOD) < 0))
  227. fatal_perror("check_ptrace: PTRACE_OLDSETOPTIONS failed");
  228. while (1) {
  229. if (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
  230. fatal_perror("check_ptrace : ptrace failed");
  231. CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
  232. if (n < 0)
  233. fatal_perror("check_ptrace : wait failed");
  234. if (!WIFSTOPPED(status) ||
  235. (WSTOPSIG(status) != (SIGTRAP | 0x80)))
  236. fatal("check_ptrace : expected (SIGTRAP|0x80), "
  237. "got status = %d", status);
  238. syscall = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_NR_OFFSET,
  239. 0);
  240. if (syscall == __NR_getpid) {
  241. n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET,
  242. __NR_getppid);
  243. if (n < 0)
  244. fatal_perror("check_ptrace : failed to modify "
  245. "system call");
  246. break;
  247. }
  248. }
  249. stop_ptraced_child(pid, 0, 1);
  250. os_info("OK\n");
  251. check_sysemu();
  252. }
  253. extern void check_tmpexec(void);
  254. static void __init check_coredump_limit(void)
  255. {
  256. struct rlimit lim;
  257. int err = getrlimit(RLIMIT_CORE, &lim);
  258. if (err) {
  259. perror("Getting core dump limit");
  260. return;
  261. }
  262. os_info("Core dump limits :\n\tsoft - ");
  263. if (lim.rlim_cur == RLIM_INFINITY)
  264. os_info("NONE\n");
  265. else
  266. os_info("%llu\n", (unsigned long long)lim.rlim_cur);
  267. os_info("\thard - ");
  268. if (lim.rlim_max == RLIM_INFINITY)
  269. os_info("NONE\n");
  270. else
  271. os_info("%llu\n", (unsigned long long)lim.rlim_max);
  272. }
  273. void __init os_early_checks(void)
  274. {
  275. int pid;
  276. /* Print out the core dump limits early */
  277. check_coredump_limit();
  278. check_ptrace();
  279. /* Need to check this early because mmapping happens before the
  280. * kernel is running.
  281. */
  282. check_tmpexec();
  283. pid = start_ptraced_child();
  284. if (init_registers(pid))
  285. fatal("Failed to initialize default registers");
  286. stop_ptraced_child(pid, 1, 1);
  287. }
  288. int __init parse_iomem(char *str, int *add)
  289. {
  290. struct iomem_region *new;
  291. struct stat64 buf;
  292. char *file, *driver;
  293. int fd, size;
  294. driver = str;
  295. file = strchr(str,',');
  296. if (file == NULL) {
  297. os_warn("parse_iomem : failed to parse iomem\n");
  298. goto out;
  299. }
  300. *file = '\0';
  301. file++;
  302. fd = open(file, O_RDWR, 0);
  303. if (fd < 0) {
  304. perror("parse_iomem - Couldn't open io file");
  305. goto out;
  306. }
  307. if (fstat64(fd, &buf) < 0) {
  308. perror("parse_iomem - cannot stat_fd file");
  309. goto out_close;
  310. }
  311. new = malloc(sizeof(*new));
  312. if (new == NULL) {
  313. perror("Couldn't allocate iomem_region struct");
  314. goto out_close;
  315. }
  316. size = (buf.st_size + UM_KERN_PAGE_SIZE) & ~(UM_KERN_PAGE_SIZE - 1);
  317. *new = ((struct iomem_region) { .next = iomem_regions,
  318. .driver = driver,
  319. .fd = fd,
  320. .size = size,
  321. .phys = 0,
  322. .virt = 0 });
  323. iomem_regions = new;
  324. iomem_size += new->size + UM_KERN_PAGE_SIZE;
  325. return 0;
  326. out_close:
  327. close(fd);
  328. out:
  329. return 1;
  330. }