diff options
Diffstat (limited to 'arch/um')
| -rw-r--r-- | arch/um/os-Linux/start_up.c | 154 |
1 files changed, 92 insertions, 62 deletions
diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c index 735d035a7f33..5178eba9afa5 100644 --- a/arch/um/os-Linux/start_up.c +++ b/arch/um/os-Linux/start_up.c | |||
| @@ -73,6 +73,34 @@ static int ptrace_child(void *arg) | |||
| 73 | _exit(ret); | 73 | _exit(ret); |
| 74 | } | 74 | } |
| 75 | 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 | |||
| 76 | static int start_ptraced_child(void **stack_out) | 104 | static int start_ptraced_child(void **stack_out) |
| 77 | { | 105 | { |
| 78 | void *stack; | 106 | void *stack; |
| @@ -82,16 +110,16 @@ static int start_ptraced_child(void **stack_out) | |||
| 82 | stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, | 110 | stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, |
| 83 | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | 111 | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); |
| 84 | if(stack == MAP_FAILED) | 112 | if(stack == MAP_FAILED) |
| 85 | panic("check_ptrace : mmap failed, errno = %d", errno); | 113 | fatal_perror("check_ptrace : mmap failed"); |
| 86 | sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *); | 114 | sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *); |
| 87 | pid = clone(ptrace_child, (void *) sp, SIGCHLD, NULL); | 115 | pid = clone(ptrace_child, (void *) sp, SIGCHLD, NULL); |
| 88 | if(pid < 0) | 116 | if(pid < 0) |
| 89 | panic("start_ptraced_child : clone failed, errno = %d", errno); | 117 | fatal_perror("start_ptraced_child : clone failed"); |
| 90 | CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); | 118 | CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); |
| 91 | if(n < 0) | 119 | if(n < 0) |
| 92 | panic("check_ptrace : clone failed, errno = %d", errno); | 120 | fatal_perror("check_ptrace : clone failed"); |
| 93 | if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) | 121 | if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) |
| 94 | panic("check_ptrace : expected SIGSTOP, got status = %d", | 122 | fatal("check_ptrace : expected SIGSTOP, got status = %d", |
| 95 | status); | 123 | status); |
| 96 | 124 | ||
| 97 | *stack_out = stack; | 125 | *stack_out = stack; |
| @@ -105,31 +133,30 @@ static int start_ptraced_child(void **stack_out) | |||
| 105 | * must work anyway! | 133 | * must work anyway! |
| 106 | */ | 134 | */ |
| 107 | static int stop_ptraced_child(int pid, void *stack, int exitcode, | 135 | static int stop_ptraced_child(int pid, void *stack, int exitcode, |
| 108 | int mustpanic) | 136 | int mustexit) |
| 109 | { | 137 | { |
| 110 | int status, n, ret = 0; | 138 | int status, n, ret = 0; |
| 111 | 139 | ||
| 112 | if(ptrace(PTRACE_CONT, pid, 0, 0) < 0) | 140 | if(ptrace(PTRACE_CONT, pid, 0, 0) < 0) |
| 113 | panic("check_ptrace : ptrace failed, errno = %d", errno); | 141 | fatal_perror("stop_ptraced_child : ptrace failed"); |
| 114 | CATCH_EINTR(n = waitpid(pid, &status, 0)); | 142 | CATCH_EINTR(n = waitpid(pid, &status, 0)); |
| 115 | if(!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) { | 143 | if(!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) { |
| 116 | int exit_with = WEXITSTATUS(status); | 144 | int exit_with = WEXITSTATUS(status); |
| 117 | if (exit_with == 2) | 145 | if (exit_with == 2) |
| 118 | printf("check_ptrace : child exited with status 2. " | 146 | non_fatal("check_ptrace : child exited with status 2. " |
| 119 | "Serious trouble happening! Try updating your " | 147 | "Serious trouble happening! Try updating " |
| 120 | "host skas patch!\nDisabling SYSEMU support."); | 148 | "your host skas patch!\nDisabling SYSEMU " |
| 121 | printf("check_ptrace : child exited with exitcode %d, while " | 149 | "support."); |
| 122 | "expecting %d; status 0x%x", exit_with, | 150 | non_fatal("check_ptrace : child exited with exitcode %d, while " |
| 123 | exitcode, status); | 151 | "expecting %d; status 0x%x\n", exit_with, |
| 124 | if (mustpanic) | 152 | exitcode, status); |
| 125 | panic("\n"); | 153 | if (mustexit) |
| 126 | else | 154 | exit(1); |
| 127 | printf("\n"); | ||
| 128 | ret = -1; | 155 | ret = -1; |
| 129 | } | 156 | } |
| 130 | 157 | ||
| 131 | if(munmap(stack, PAGE_SIZE) < 0) | 158 | if(munmap(stack, PAGE_SIZE) < 0) |
| 132 | panic("check_ptrace : munmap failed, errno = %d", errno); | 159 | fatal_perror("check_ptrace : munmap failed"); |
| 133 | return ret; | 160 | return ret; |
| 134 | } | 161 | } |
| 135 | 162 | ||
| @@ -184,7 +211,7 @@ static void __init check_sysemu(void) | |||
| 184 | void *stack; | 211 | void *stack; |
| 185 | int pid, n, status, count=0; | 212 | int pid, n, status, count=0; |
| 186 | 213 | ||
| 187 | printf("Checking syscall emulation patch for ptrace..."); | 214 | non_fatal("Checking syscall emulation patch for ptrace..."); |
| 188 | sysemu_supported = 0; | 215 | sysemu_supported = 0; |
| 189 | pid = start_ptraced_child(&stack); | 216 | pid = start_ptraced_child(&stack); |
| 190 | 217 | ||
| @@ -193,31 +220,30 @@ static void __init check_sysemu(void) | |||
| 193 | 220 | ||
| 194 | CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); | 221 | CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); |
| 195 | if (n < 0) | 222 | if (n < 0) |
| 196 | panic("check_sysemu : wait failed, errno = %d", errno); | 223 | fatal_perror("check_sysemu : wait failed"); |
| 197 | if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP)) | 224 | if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP)) |
| 198 | panic("check_sysemu : expected SIGTRAP, " | 225 | fatal("check_sysemu : expected SIGTRAP, got status = %d", |
| 199 | "got status = %d", status); | 226 | status); |
| 200 | 227 | ||
| 201 | n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET, | 228 | n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET, |
| 202 | os_getpid()); | 229 | os_getpid()); |
| 203 | if(n < 0) | 230 | if(n < 0) |
| 204 | panic("check_sysemu : failed to modify system " | 231 | fatal_perror("check_sysemu : failed to modify system call " |
| 205 | "call return, errno = %d", errno); | 232 | "return"); |
| 206 | 233 | ||
| 207 | if (stop_ptraced_child(pid, stack, 0, 0) < 0) | 234 | if (stop_ptraced_child(pid, stack, 0, 0) < 0) |
| 208 | goto fail_stopped; | 235 | goto fail_stopped; |
| 209 | 236 | ||
| 210 | sysemu_supported = 1; | 237 | sysemu_supported = 1; |
| 211 | printf("OK\n"); | 238 | non_fatal("OK\n"); |
| 212 | set_using_sysemu(!force_sysemu_disabled); | 239 | set_using_sysemu(!force_sysemu_disabled); |
| 213 | 240 | ||
| 214 | printf("Checking advanced syscall emulation patch for ptrace..."); | 241 | non_fatal("Checking advanced syscall emulation patch for ptrace..."); |
| 215 | pid = start_ptraced_child(&stack); | 242 | pid = start_ptraced_child(&stack); |
| 216 | 243 | ||
| 217 | if(ptrace(PTRACE_OLDSETOPTIONS, pid, 0, | 244 | if((ptrace(PTRACE_OLDSETOPTIONS, pid, 0, |
| 218 | (void *) PTRACE_O_TRACESYSGOOD) < 0) | 245 | (void *) PTRACE_O_TRACESYSGOOD) < 0)) |
| 219 | panic("check_ptrace: PTRACE_OLDSETOPTIONS failed, errno = %d", | 246 | fatal_perror("check_ptrace: PTRACE_OLDSETOPTIONS failed"); |
| 220 | errno); | ||
| 221 | 247 | ||
| 222 | while(1){ | 248 | while(1){ |
| 223 | count++; | 249 | count++; |
| @@ -225,29 +251,30 @@ static void __init check_sysemu(void) | |||
| 225 | goto fail; | 251 | goto fail; |
| 226 | CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); | 252 | CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); |
| 227 | if(n < 0) | 253 | if(n < 0) |
| 228 | panic("check_ptrace : wait failed, errno = %d", errno); | 254 | fatal_perror("check_ptrace : wait failed"); |
| 255 | |||
| 229 | if(WIFSTOPPED(status) && (WSTOPSIG(status) == (SIGTRAP|0x80))){ | 256 | if(WIFSTOPPED(status) && (WSTOPSIG(status) == (SIGTRAP|0x80))){ |
| 230 | if (!count) | 257 | if (!count) |
| 231 | panic("check_ptrace : SYSEMU_SINGLESTEP " | 258 | fatal("check_ptrace : SYSEMU_SINGLESTEP " |
| 232 | "doesn't singlestep"); | 259 | "doesn't singlestep"); |
| 233 | n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET, | 260 | n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET, |
| 234 | os_getpid()); | 261 | os_getpid()); |
| 235 | if(n < 0) | 262 | if(n < 0) |
| 236 | panic("check_sysemu : failed to modify system " | 263 | fatal_perror("check_sysemu : failed to modify " |
| 237 | "call return, errno = %d", errno); | 264 | "system call return"); |
| 238 | break; | 265 | break; |
| 239 | } | 266 | } |
| 240 | else if(WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP)) | 267 | else if(WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP)) |
| 241 | count++; | 268 | count++; |
| 242 | else | 269 | else |
| 243 | panic("check_ptrace : expected SIGTRAP or " | 270 | fatal("check_ptrace : expected SIGTRAP or " |
| 244 | "(SIGTRAP|0x80), got status = %d", status); | 271 | "(SIGTRAP | 0x80), got status = %d", status); |
| 245 | } | 272 | } |
| 246 | if (stop_ptraced_child(pid, stack, 0, 0) < 0) | 273 | if (stop_ptraced_child(pid, stack, 0, 0) < 0) |
| 247 | goto fail_stopped; | 274 | goto fail_stopped; |
| 248 | 275 | ||
| 249 | sysemu_supported = 2; | 276 | sysemu_supported = 2; |
| 250 | printf("OK\n"); | 277 | non_fatal("OK\n"); |
| 251 | 278 | ||
| 252 | if ( !force_sysemu_disabled ) | 279 | if ( !force_sysemu_disabled ) |
| 253 | set_using_sysemu(sysemu_supported); | 280 | set_using_sysemu(sysemu_supported); |
| @@ -256,7 +283,7 @@ static void __init check_sysemu(void) | |||
| 256 | fail: | 283 | fail: |
| 257 | stop_ptraced_child(pid, stack, 1, 0); | 284 | stop_ptraced_child(pid, stack, 1, 0); |
| 258 | fail_stopped: | 285 | fail_stopped: |
| 259 | printf("missing\n"); | 286 | non_fatal("missing\n"); |
| 260 | } | 287 | } |
| 261 | 288 | ||
| 262 | static void __init check_ptrace(void) | 289 | static void __init check_ptrace(void) |
| @@ -264,22 +291,25 @@ static void __init check_ptrace(void) | |||
| 264 | void *stack; | 291 | void *stack; |
| 265 | int pid, syscall, n, status; | 292 | int pid, syscall, n, status; |
| 266 | 293 | ||
| 267 | printf("Checking that ptrace can change system call numbers..."); | 294 | non_fatal("Checking that ptrace can change system call numbers..."); |
| 268 | pid = start_ptraced_child(&stack); | 295 | pid = start_ptraced_child(&stack); |
| 269 | 296 | ||
| 270 | if(ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0) | 297 | if((ptrace(PTRACE_OLDSETOPTIONS, pid, 0, |
| 271 | panic("check_ptrace: PTRACE_OLDSETOPTIONS failed, errno = %d", errno); | 298 | (void *) PTRACE_O_TRACESYSGOOD) < 0)) |
| 299 | fatal_perror("check_ptrace: PTRACE_OLDSETOPTIONS failed"); | ||
| 272 | 300 | ||
| 273 | while(1){ | 301 | while(1){ |
| 274 | if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) | 302 | if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) |
| 275 | panic("check_ptrace : ptrace failed, errno = %d", | 303 | fatal_perror("check_ptrace : ptrace failed"); |
| 276 | errno); | 304 | |
| 277 | CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); | 305 | CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); |
| 278 | if(n < 0) | 306 | if(n < 0) |
| 279 | panic("check_ptrace : wait failed, errno = %d", errno); | 307 | fatal_perror("check_ptrace : wait failed"); |
| 280 | if(!WIFSTOPPED(status) || (WSTOPSIG(status) != (SIGTRAP|0x80))) | 308 | |
| 281 | panic("check_ptrace : expected (SIGTRAP|0x80), " | 309 | if(!WIFSTOPPED(status) || |
| 282 | "got status = %d", status); | 310 | (WSTOPSIG(status) != (SIGTRAP | 0x80))) |
| 311 | fatal("check_ptrace : expected (SIGTRAP|0x80), " | ||
| 312 | "got status = %d", status); | ||
| 283 | 313 | ||
| 284 | syscall = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_NR_OFFSET, | 314 | syscall = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_NR_OFFSET, |
| 285 | 0); | 315 | 0); |
| @@ -287,13 +317,13 @@ static void __init check_ptrace(void) | |||
| 287 | n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET, | 317 | n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET, |
| 288 | __NR_getppid); | 318 | __NR_getppid); |
| 289 | if(n < 0) | 319 | if(n < 0) |
| 290 | panic("check_ptrace : failed to modify system " | 320 | fatal_perror("check_ptrace : failed to modify " |
| 291 | "call, errno = %d", errno); | 321 | "system call"); |
| 292 | break; | 322 | break; |
| 293 | } | 323 | } |
| 294 | } | 324 | } |
| 295 | stop_ptraced_child(pid, stack, 0, 1); | 325 | stop_ptraced_child(pid, stack, 0, 1); |
| 296 | printf("OK\n"); | 326 | non_fatal("OK\n"); |
| 297 | check_sysemu(); | 327 | check_sysemu(); |
| 298 | } | 328 | } |
| 299 | 329 | ||
| @@ -352,22 +382,22 @@ static inline void check_skas3_ptrace_faultinfo(void) | |||
| 352 | void *stack; | 382 | void *stack; |
| 353 | int pid, n; | 383 | int pid, n; |
| 354 | 384 | ||
| 355 | printf(" - PTRACE_FAULTINFO..."); | 385 | non_fatal(" - PTRACE_FAULTINFO..."); |
| 356 | pid = start_ptraced_child(&stack); | 386 | pid = start_ptraced_child(&stack); |
| 357 | 387 | ||
| 358 | n = ptrace(PTRACE_FAULTINFO, pid, 0, &fi); | 388 | n = ptrace(PTRACE_FAULTINFO, pid, 0, &fi); |
| 359 | if (n < 0) { | 389 | if (n < 0) { |
| 360 | ptrace_faultinfo = 0; | 390 | ptrace_faultinfo = 0; |
| 361 | if(errno == EIO) | 391 | if(errno == EIO) |
| 362 | printf("not found\n"); | 392 | non_fatal("not found\n"); |
| 363 | else | 393 | else |
| 364 | perror("not found"); | 394 | perror("not found"); |
| 365 | } | 395 | } |
| 366 | else { | 396 | else { |
| 367 | if (!ptrace_faultinfo) | 397 | if (!ptrace_faultinfo) |
| 368 | printf("found but disabled on command line\n"); | 398 | non_fatal("found but disabled on command line\n"); |
| 369 | else | 399 | else |
| 370 | printf("found\n"); | 400 | non_fatal("found\n"); |
| 371 | } | 401 | } |
| 372 | 402 | ||
| 373 | init_registers(pid); | 403 | init_registers(pid); |
| @@ -385,13 +415,13 @@ static inline void check_skas3_ptrace_ldt(void) | |||
| 385 | .ptr = ldtbuf, | 415 | .ptr = ldtbuf, |
| 386 | .bytecount = sizeof(ldtbuf)}; | 416 | .bytecount = sizeof(ldtbuf)}; |
| 387 | 417 | ||
| 388 | printf(" - PTRACE_LDT..."); | 418 | non_fatal(" - PTRACE_LDT..."); |
| 389 | pid = start_ptraced_child(&stack); | 419 | pid = start_ptraced_child(&stack); |
| 390 | 420 | ||
| 391 | n = ptrace(PTRACE_LDT, pid, 0, (unsigned long) &ldt_op); | 421 | n = ptrace(PTRACE_LDT, pid, 0, (unsigned long) &ldt_op); |
| 392 | if (n < 0) { | 422 | if (n < 0) { |
| 393 | if(errno == EIO) | 423 | if(errno == EIO) |
| 394 | printf("not found\n"); | 424 | non_fatal("not found\n"); |
| 395 | else { | 425 | else { |
| 396 | perror("not found"); | 426 | perror("not found"); |
| 397 | } | 427 | } |
| @@ -399,9 +429,9 @@ static inline void check_skas3_ptrace_ldt(void) | |||
| 399 | } | 429 | } |
| 400 | else { | 430 | else { |
| 401 | if(ptrace_ldt) | 431 | if(ptrace_ldt) |
| 402 | printf("found\n"); | 432 | non_fatal("found\n"); |
| 403 | else | 433 | else |
| 404 | printf("found, but use is disabled\n"); | 434 | non_fatal("found, but use is disabled\n"); |
| 405 | } | 435 | } |
| 406 | 436 | ||
| 407 | stop_ptraced_child(pid, stack, 1, 1); | 437 | stop_ptraced_child(pid, stack, 1, 1); |
| @@ -416,22 +446,22 @@ static inline void check_skas3_ptrace_ldt(void) | |||
| 416 | 446 | ||
| 417 | static inline void check_skas3_proc_mm(void) | 447 | static inline void check_skas3_proc_mm(void) |
| 418 | { | 448 | { |
| 419 | printf(" - /proc/mm..."); | 449 | non_fatal(" - /proc/mm..."); |
| 420 | if (access("/proc/mm", W_OK) < 0) { | 450 | if (access("/proc/mm", W_OK) < 0) { |
| 421 | proc_mm = 0; | 451 | proc_mm = 0; |
| 422 | printf("not found\n"); | 452 | perror("not found"); |
| 423 | } | 453 | } |
| 424 | else { | 454 | else { |
| 425 | if (!proc_mm) | 455 | if (!proc_mm) |
| 426 | printf("found but disabled on command line\n"); | 456 | non_fatal("found but disabled on command line\n"); |
| 427 | else | 457 | else |
| 428 | printf("found\n"); | 458 | non_fatal("found\n"); |
| 429 | } | 459 | } |
| 430 | } | 460 | } |
| 431 | 461 | ||
| 432 | int can_do_skas(void) | 462 | int can_do_skas(void) |
| 433 | { | 463 | { |
| 434 | printf("Checking for the skas3 patch in the host:\n"); | 464 | non_fatal("Checking for the skas3 patch in the host:\n"); |
| 435 | 465 | ||
| 436 | check_skas3_proc_mm(); | 466 | check_skas3_proc_mm(); |
| 437 | check_skas3_ptrace_faultinfo(); | 467 | check_skas3_ptrace_faultinfo(); |
