linux/arch/um/os-Linux/start_up.c
<<
>>
Prefs
   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
  27static 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
  66static void fatal_perror(const char *str)
  67{
  68        perror(str);
  69        exit(1);
  70}
  71
  72static 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
  83static 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
  92static 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 */
 118static 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 */
 144int ptrace_faultinfo;
 145static int disable_ptrace_faultinfo;
 146
 147int ptrace_ldt;
 148static int disable_ptrace_ldt;
 149
 150int proc_mm;
 151static int disable_proc_mm;
 152
 153int have_switch_mm;
 154static int disable_switch_mm;
 155
 156int skas_needs_stub;
 157
 158static 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
 170static 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 */
 182static int force_sysemu_disabled = 0;
 183
 184static 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
 199static 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
 288fail:
 289        stop_ptraced_child(pid, 1, 0);
 290fail_stopped:
 291        non_fatal("missing\n");
 292}
 293
 294static 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
 334extern void check_tmpexec(void);
 335
 336static 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
 357void __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
 377static 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
 389static 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
 401static 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
 413static 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
 437static 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
 467static 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
 480void 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
 492int __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
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.