1 /* 2 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 3 * Licensed under the GPL 4 */ 5 6 #include <stdio.h> 7 #include <stdlib.h> 8 #include <stdarg.h> 9 #include <unistd.h> 10 #include <errno.h> 11 #include <fcntl.h> 12 #include <sched.h> 13 #include <signal.h> 14 #include <string.h> 15 #include <sys/mman.h> 16 #include <sys/stat.h> 17 #include <sys/wait.h> 18 #include <asm/unistd.h> 19 #include <init.h> 20 #include <os.h> 21 #include <mem_user.h> 22 #include <ptrace_user.h> 23 #include <registers.h> 24 #include <skas.h> 25 #include <skas_ptrace.h> 26 27 static void ptrace_child(void) 28 { 29 int ret; 30 /* Calling os_getpid because some libcs cached getpid incorrectly */ 31 int pid = os_getpid(), ppid = getppid(); 32 int sc_result; 33 34 if (change_sig(SIGWINCH, 0) < 0 || 35 ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) { 36 perror("ptrace"); 37 kill(pid, SIGKILL); 38 } 39 kill(pid, SIGSTOP); 40 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 47 if (sc_result == pid) 48 /* Nothing modified by the parent, we are running normally. */ 49 ret = 1; 50 else if (sc_result == ppid) 51 /* 52 * Expected in check_ptrace and check_sysemu when they succeed 53 * in modifying the stack frame 54 */ 55 ret = 0; 56 else 57 /* Serious trouble! This could be caused by a bug in host 2.6 58 * SKAS3/2.6 patch before release -V6, together with a bug in 59 * the UML code itself. 60 */ 61 ret = 2; 62 63 exit(ret); 64 } 65 66 static void fatal_perror(const char *str) 67 { 68 perror(str); 69 exit(1); 70 } 71 72 static void fatal(char *fmt, ...) 73 { 74 va_list list; 75 76 va_start(list, fmt); 77 vfprintf(stderr, fmt, list); 78 va_end(list); 79 80 exit(1); 81 } 82 83 static void non_fatal(char *fmt, ...) 84 { 85 va_list list; 86 87 va_start(list, fmt); 88 vfprintf(stderr, fmt, list); 89 va_end(list); 90 } 91 92 static int start_ptraced_child(void) 93 { 94 int pid, n, status; 95 96 pid = fork(); 97 if (pid == 0) 98 ptrace_child(); 99 else if (pid < 0) 100 fatal_perror("start_ptraced_child : fork failed"); 101 102 CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); 103 if (n < 0) 104 fatal_perror("check_ptrace : waitpid failed"); 105 if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) 106 fatal("check_ptrace : expected SIGSTOP, got status = %d", 107 status); 108 109 return pid; 110 } 111 112 /* When testing for SYSEMU support, if it is one of the broken versions, we 113 * must just avoid using sysemu, not panic, but only if SYSEMU features are 114 * broken. 115 * So only for SYSEMU features we test mustpanic, while normal host features 116 * must work anyway! 117 */ 118 static int stop_ptraced_child(int pid, int exitcode, int mustexit) 119 { 120 int status, n, ret = 0; 121 122 if (ptrace(PTRACE_CONT, pid, 0, 0) < 0) { 123 perror("stop_ptraced_child : ptrace failed"); 124 return -1; 125 } 126 CATCH_EINTR(n = waitpid(pid, &status, 0)); 127 if (!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) { 128 int exit_with = WEXITSTATUS(status); 129 if (exit_with == 2) 130 non_fatal("check_ptrace : child exited with status 2. " 131 "\nDisabling SYSEMU support.\n"); 132 non_fatal("check_ptrace : child exited with exitcode %d, while " 133 "expecting %d; status 0x%x\n", exit_with, 134 exitcode, status); 135 if (mustexit) 136 exit(1); 137 ret = -1; 138 } 139 140 return ret; 141 } 142 143 /* Changed only during early boot */ 144 int ptrace_faultinfo; 145 static int disable_ptrace_faultinfo; 146 147 int ptrace_ldt; 148 static int disable_ptrace_ldt; 149 150 int proc_mm; 151 static int disable_proc_mm; 152 153 int have_switch_mm; 154 static int disable_switch_mm; 155 156 int skas_needs_stub; 157 158 static int __init skas0_cmd_param(char *str, int* add) 159 { 160 disable_ptrace_faultinfo = 1; 161 disable_ptrace_ldt = 1; 162 disable_proc_mm = 1; 163 disable_switch_mm = 1; 164 165 return 0; 166 } 167 168 /* The two __uml_setup would conflict, without this stupid alias. */ 169 170 static int __init mode_skas0_cmd_param(char *str, int* add) 171 __attribute__((alias("skas0_cmd_param"))); 172 173 __uml_setup("skas0", skas0_cmd_param, 174 "skas0\n" 175 " Disables SKAS3 and SKAS4 usage, so that SKAS0 is used\n\n"); 176 177 __uml_setup("mode=skas0", mode_skas0_cmd_param, 178 "mode=skas0\n" 179 " Disables SKAS3 and SKAS4 usage, so that SKAS0 is used.\n\n"); 180 181 /* Changed only during early boot */ 182 static int force_sysemu_disabled = 0; 183 184 static int __init nosysemu_cmd_param(char *str, int* add) 185 { 186 force_sysemu_disabled = 1; 187 return 0; 188 } 189 190 __uml_setup("nosysemu", nosysemu_cmd_param, 191 "nosysemu\n" 192 " Turns off syscall emulation patch for ptrace (SYSEMU) on.\n" 193 " SYSEMU is a performance-patch introduced by Laurent Vivier. It changes\n" 194 " behaviour of ptrace() and helps reducing host context switch rate.\n" 195 " To make it working, you need a kernel patch for your host, too.\n" 196 " See http://perso.wanadoo.fr/laurent.vivier/UML/ for further \n" 197 " information.\n\n"); 198 199 static void __init check_sysemu(void) 200 { 201 unsigned long regs[MAX_REG_NR]; 202 int pid, n, status, count=0; 203 204 non_fatal("Checking syscall emulation patch for ptrace..."); 205 sysemu_supported = 0; 206 pid = start_ptraced_child(); 207 208 if (ptrace(PTRACE_SYSEMU, pid, 0, 0) < 0) 209 goto fail; 210 211 CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); 212 if (n < 0) 213 fatal_perror("check_sysemu : wait failed"); 214 if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP)) 215 fatal("check_sysemu : expected SIGTRAP, got status = %d\n", 216 status); 217 218 if (ptrace(PTRACE_GETREGS, pid, 0, regs) < 0) 219 fatal_perror("check_sysemu : PTRACE_GETREGS failed"); 220 if (PT_SYSCALL_NR(regs) != __NR_getpid) { 221 non_fatal("check_sysemu got system call number %d, " 222 "expected %d...", PT_SYSCALL_NR(regs), __NR_getpid); 223 goto fail; 224 } 225 226 n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET, os_getpid()); 227 if (n < 0) { 228 non_fatal("check_sysemu : failed to modify system call " 229 "return"); 230 goto fail; 231 } 232 233 if (stop_ptraced_child(pid, 0, 0) < 0) 234 goto fail_stopped; 235 236 sysemu_supported = 1; 237 non_fatal("OK\n"); 238 set_using_sysemu(!force_sysemu_disabled); 239 240 non_fatal("Checking advanced syscall emulation patch for ptrace..."); 241 pid = start_ptraced_child(); 242 243 if ((ptrace(PTRACE_OLDSETOPTIONS, pid, 0, 244 (void *) PTRACE_O_TRACESYSGOOD) < 0)) 245 fatal_perror("check_sysemu: PTRACE_OLDSETOPTIONS failed"); 246 247 while (1) { 248 count++; 249 if (ptrace(PTRACE_SYSEMU_SINGLESTEP, pid, 0, 0) < 0) 250 goto fail; 251 CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); 252 if (n < 0) 253 fatal_perror("check_sysemu: wait failed"); 254 255 if (WIFSTOPPED(status) && 256 (WSTOPSIG(status) == (SIGTRAP|0x80))) { 257 if (!count) { 258 non_fatal("check_sysemu: SYSEMU_SINGLESTEP " 259 "doesn't singlestep"); 260 goto fail; 261 } 262 n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET, 263 os_getpid()); 264 if (n < 0) 265 fatal_perror("check_sysemu : failed to modify " 266 "system call return"); 267 break; 268 } 269 else if (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP)) 270 count++; 271 else { 272 non_fatal("check_sysemu: expected SIGTRAP or " 273 "(SIGTRAP | 0x80), got status = %d\n", 274 status); 275 goto fail; 276 } 277 } 278 if (stop_ptraced_child(pid, 0, 0) < 0) 279 goto fail_stopped; 280 281 sysemu_supported = 2; 282 non_fatal("OK\n"); 283 284 if (!force_sysemu_disabled) 285 set_using_sysemu(sysemu_supported); 286 return; 287 288 fail: 289 stop_ptraced_child(pid, 1, 0); 290 fail_stopped: 291 non_fatal("missing\n"); 292 } 293 294 static void __init check_ptrace(void) 295 { 296 int pid, syscall, n, status; 297 298 non_fatal("Checking that ptrace can change system call numbers..."); 299 pid = start_ptraced_child(); 300 301 if ((ptrace(PTRACE_OLDSETOPTIONS, pid, 0, 302 (void *) PTRACE_O_TRACESYSGOOD) < 0)) 303 fatal_perror("check_ptrace: PTRACE_OLDSETOPTIONS failed"); 304 305 while (1) { 306 if (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) 307 fatal_perror("check_ptrace : ptrace failed"); 308 309 CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); 310 if (n < 0) 311 fatal_perror("check_ptrace : wait failed"); 312 313 if (!WIFSTOPPED(status) || 314 (WSTOPSIG(status) != (SIGTRAP | 0x80))) 315 fatal("check_ptrace : expected (SIGTRAP|0x80), " 316 "got status = %d", status); 317 318 syscall = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_NR_OFFSET, 319 0); 320 if (syscall == __NR_getpid) { 321 n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, 322 __NR_getppid); 323 if (n < 0) 324 fatal_perror("check_ptrace : failed to modify " 325 "system call"); 326 break; 327 } 328 } 329 stop_ptraced_child(pid, 0, 1); 330 non_fatal("OK\n"); 331 check_sysemu(); 332 } 333 334 extern void check_tmpexec(void); 335 336 static void __init check_coredump_limit(void) 337 { 338 struct rlimit lim; 339 int err = getrlimit(RLIMIT_CORE, &lim); 340 341 if (err) { 342 perror("Getting core dump limit"); 343 return; 344 } 345 346 printf("Core dump limits :\n\tsoft - "); 347 if (lim.rlim_cur == RLIM_INFINITY) 348 printf("NONE\n"); 349 else printf("%lu\n", lim.rlim_cur); 350 351 printf("\thard - "); 352 if (lim.rlim_max == RLIM_INFINITY) 353 printf("NONE\n"); 354 else printf("%lu\n", lim.rlim_max); 355 } 356 357 void __init os_early_checks(void) 358 { 359 int pid; 360 361 /* Print out the core dump limits early */ 362 check_coredump_limit(); 363 364 check_ptrace(); 365 366 /* Need to check this early because mmapping happens before the 367 * kernel is running. 368 */ 369 check_tmpexec(); 370 371 pid = start_ptraced_child(); 372 if (init_registers(pid)) 373 fatal("Failed to initialize default registers"); 374 stop_ptraced_child(pid, 1, 1); 375 } 376 377 static int __init noprocmm_cmd_param(char *str, int* add) 378 { 379 disable_proc_mm = 1; 380 return 0; 381 } 382 383 __uml_setup("noprocmm", noprocmm_cmd_param, 384 "noprocmm\n" 385 " Turns off usage of /proc/mm, even if host supports it.\n" 386 " To support /proc/mm, the host needs to be patched using\n" 387 " the current skas3 patch.\n\n"); 388 389 static int __init noptracefaultinfo_cmd_param(char *str, int* add) 390 { 391 disable_ptrace_faultinfo = 1; 392 return 0; 393 } 394 395 __uml_setup("noptracefaultinfo", noptracefaultinfo_cmd_param, 396 "noptracefaultinfo\n" 397 " Turns off usage of PTRACE_FAULTINFO, even if host supports\n" 398 " it. To support PTRACE_FAULTINFO, the host needs to be patched\n" 399 " using the current skas3 patch.\n\n"); 400 401 static int __init noptraceldt_cmd_param(char *str, int* add) 402 { 403 disable_ptrace_ldt = 1; 404 return 0; 405 } 406 407 __uml_setup("noptraceldt", noptraceldt_cmd_param, 408 "noptraceldt\n" 409 " Turns off usage of PTRACE_LDT, even if host supports it.\n" 410 " To support PTRACE_LDT, the host needs to be patched using\n" 411 " the current skas3 patch.\n\n"); 412 413 static inline void check_skas3_ptrace_faultinfo(void) 414 { 415 struct ptrace_faultinfo fi; 416 int pid, n; 417 418 non_fatal(" - PTRACE_FAULTINFO..."); 419 pid = start_ptraced_child(); 420 421 n = ptrace(PTRACE_FAULTINFO, pid, 0, &fi); 422 if (n < 0) { 423 if (errno == EIO) 424 non_fatal("not found\n"); 425 else 426 perror("not found"); 427 } else if (disable_ptrace_faultinfo) 428 non_fatal("found but disabled on command line\n"); 429 else { 430 ptrace_faultinfo = 1; 431 non_fatal("found\n"); 432 } 433 434 stop_ptraced_child(pid, 1, 1); 435 } 436 437 static inline void check_skas3_ptrace_ldt(void) 438 { 439 #ifdef PTRACE_LDT 440 int pid, n; 441 unsigned char ldtbuf[40]; 442 struct ptrace_ldt ldt_op = (struct ptrace_ldt) { 443 .func = 2, /* read default ldt */ 444 .ptr = ldtbuf, 445 .bytecount = sizeof(ldtbuf)}; 446 447 non_fatal(" - PTRACE_LDT..."); 448 pid = start_ptraced_child(); 449 450 n = ptrace(PTRACE_LDT, pid, 0, (unsigned long) &ldt_op); 451 if (n < 0) { 452 if (errno == EIO) 453 non_fatal("not found\n"); 454 else 455 perror("not found"); 456 } else if (disable_ptrace_ldt) 457 non_fatal("found, but use is disabled\n"); 458 else { 459 ptrace_ldt = 1; 460 non_fatal("found\n"); 461 } 462 463 stop_ptraced_child(pid, 1, 1); 464 #endif 465 } 466 467 static inline void check_skas3_proc_mm(void) 468 { 469 non_fatal(" - /proc/mm..."); 470 if (access("/proc/mm", W_OK) < 0) 471 perror("not found"); 472 else if (disable_proc_mm) 473 non_fatal("found but disabled on command line\n"); 474 else { 475 proc_mm = 1; 476 non_fatal("found\n"); 477 } 478 } 479 480 void can_do_skas(void) 481 { 482 non_fatal("Checking for the skas3 patch in the host:\n"); 483 484 check_skas3_proc_mm(); 485 check_skas3_ptrace_faultinfo(); 486 check_skas3_ptrace_ldt(); 487 488 if (!proc_mm || !ptrace_faultinfo || !ptrace_ldt) 489 skas_needs_stub = 1; 490 } 491 492 int __init parse_iomem(char *str, int *add) 493 { 494 struct iomem_region *new; 495 struct stat64 buf; 496 char *file, *driver; 497 int fd, size; 498 499 driver = str; 500 file = strchr(str,','); 501 if (file == NULL) { 502 fprintf(stderr, "parse_iomem : failed to parse iomem\n"); 503 goto out; 504 } 505 *file = '\0'; 506 file++; 507 fd = open(file, O_RDWR, 0); 508 if (fd < 0) { 509 perror("parse_iomem - Couldn't open io file"); 510 goto out; 511 } 512 513 if (fstat64(fd, &buf) < 0) { 514 perror("parse_iomem - cannot stat_fd file"); 515 goto out_close; 516 } 517 518 new = malloc(sizeof(*new)); 519 if (new == NULL) { 520 perror("Couldn't allocate iomem_region struct"); 521 goto out_close; 522 } 523 524 size = (buf.st_size + UM_KERN_PAGE_SIZE) & ~(UM_KERN_PAGE_SIZE - 1); 525 526 *new = ((struct iomem_region) { .next = iomem_regions, 527 .driver = driver, 528 .fd = fd, 529 .size = size, 530 .phys = 0, 531 .virt = 0 }); 532 iomem_regions = new; 533 iomem_size += new->size + UM_KERN_PAGE_SIZE; 534 535 return 0; 536 out_close: 537 close(fd); 538 out: 539 return 1; 540 } 541