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