Beispiel #1
0
MRef Prmci6AddressHoldingReg(MutatorFaultContext mfc, unsigned int regnum)
{
  Word *gregs;

  AVER(NONNEGATIVE(regnum));
  AVER(regnum <= 15);

  gregs = (Word *)&mfc->ucontext->uc_mcontext.gregs;

  /* .assume.regref */
  /* The register numbers (REG_RAX etc.) are defined in <ucontext.h>
     but only if _GNU_SOURCE is defined: see .feature.li in
     config.h. */
  switch (regnum) {
    case  0: return &gregs[REG_RAX];
    case  1: return &gregs[REG_RCX];
    case  2: return &gregs[REG_RDX];
    case  3: return &gregs[REG_RBX];
    case  4: return &gregs[REG_RSP];
    case  5: return &gregs[REG_RBP];
    case  6: return &gregs[REG_RSI];
    case  7: return &gregs[REG_RDI];
    case  8: return &gregs[REG_R8];
    case  9: return &gregs[REG_R9];
    case 10: return &gregs[REG_R10];
    case 11: return &gregs[REG_R11];
    case 12: return &gregs[REG_R12];
    case 13: return &gregs[REG_R13];
    case 14: return &gregs[REG_R14];
    case 15: return &gregs[REG_R15];
  }
  NOTREACHED;
  return (MRef)NULL;  /* Avoids compiler warning. */
}
Beispiel #2
0
MRef Prmci6AddressHoldingReg(MutatorFaultContext mfc, unsigned int regnum)
{
  AVER(NONNEGATIVE(regnum));
  AVER(regnum <= 15);

  /* .assume.regref */
  /* The register numbers (REG_RAX etc.) are defined in <ucontext.h>
     but only if _XOPEN_SOURCE is defined: see .feature.xc in
     config.h. */
  /* MRef (a Word *) is not compatible with pointers to the register
     types (actually a __uint64_t).  To avoid aliasing optimization
     problems, The registers are cast through (char *) */
  switch (regnum) {
    case  0: return (MRef)((char *)&mfc->threadState->__rax);
    case  1: return (MRef)((char *)&mfc->threadState->__rcx);
    case  2: return (MRef)((char *)&mfc->threadState->__rdx);
    case  3: return (MRef)((char *)&mfc->threadState->__rbx);
    case  4: return (MRef)((char *)&mfc->threadState->__rsp);
    case  5: return (MRef)((char *)&mfc->threadState->__rbp);
    case  6: return (MRef)((char *)&mfc->threadState->__rsi);
    case  7: return (MRef)((char *)&mfc->threadState->__rdi);
    case  8: return (MRef)((char *)&mfc->threadState->__r8);
    case  9: return (MRef)((char *)&mfc->threadState->__r9);
    case 10: return (MRef)((char *)&mfc->threadState->__r10);
    case 11: return (MRef)((char *)&mfc->threadState->__r11);
    case 12: return (MRef)((char *)&mfc->threadState->__r12);
    case 13: return (MRef)((char *)&mfc->threadState->__r13);
    case 14: return (MRef)((char *)&mfc->threadState->__r14);
    case 15: return (MRef)((char *)&mfc->threadState->__r15);
  }
  NOTREACHED;
  return (MRef)NULL;  /* Avoids compiler warning. */
}
Beispiel #3
0
MRef Prmci6AddressHoldingReg(MutatorFaultContext context, unsigned int regnum)
{
  PCONTEXT wincont;

  AVER(NONNEGATIVE(regnum));
  AVER(regnum <= 16);

  wincont = context->ep->ContextRecord;

  switch (regnum) {
  case  0: return (MRef)&wincont->Rax;
  case  1: return (MRef)&wincont->Rcx;
  case  2: return (MRef)&wincont->Rdx;
  case  3: return (MRef)&wincont->Rbx;
  case  4: return (MRef)&wincont->Rsp;
  case  5: return (MRef)&wincont->Rbp;
  case  6: return (MRef)&wincont->Rsi;
  case  7: return (MRef)&wincont->Rdi;
  case  8: return (MRef)&wincont->R8;
  case  9: return (MRef)&wincont->R9;
  case 10: return (MRef)&wincont->R10;
  case 11: return (MRef)&wincont->R11;
  case 12: return (MRef)&wincont->R12;
  case 13: return (MRef)&wincont->R13;
  case 14: return (MRef)&wincont->R14;
  case 15: return (MRef)&wincont->R15;
  default:
    NOTREACHED;
    return NULL; /* suppress warning */
  }
}
Beispiel #4
0
MRef Prmci3AddressHoldingReg(MutatorFaultContext mfc, unsigned int regnum)
{
  THREAD_STATE_S *threadState;

  AVER(mfc != NULL);
  AVER(NONNEGATIVE(regnum));
  AVER(regnum <= 7);
  AVER(mfc->threadState != NULL);
  threadState = mfc->threadState;

  /* .source.i486 */
  /* .assume.regref */
  /* The register numbers (REG_EAX etc.) are defined in <ucontext.h>
     but only if _GNU_SOURCE is defined: see .feature.li in
     config.h. */
  /* TODO: The current arrangement of the fix operation (taking a Ref *)
     forces us to pun these registers (actually `int` on LII3GC).  We can
     suppress the warning by casting through `void *` and this might make
     it safe, but does it really?  RB 2012-09-10 */
  switch (regnum) {
    case 0: return (void *)&threadState->__eax;
    case 1: return (void *)&threadState->__ecx;
    case 2: return (void *)&threadState->__edx;
    case 3: return (void *)&threadState->__ebx;
    case 4: return (void *)&threadState->__esp;
    case 5: return (void *)&threadState->__ebp;
    case 6: return (void *)&threadState->__esi;
    case 7: return (void *)&threadState->__edi;
    default:
      NOTREACHED;
      return NULL;  /* Avoids compiler warning. */
  }
}
Beispiel #5
0
Bool MutatorContextCheck(MutatorContext context)
{
  CHECKS(MutatorContext, context);
  CHECKL(NONNEGATIVE(context->var));
  CHECKL(context->var < MutatorContextLIMIT);
  return TRUE;
}
Beispiel #6
0
MRef Prmci3AddressHoldingReg(MutatorFaultContext mfc, unsigned int regnum)
{
  MRef gregs;

  AVER(mfc != NULL);
  AVER(NONNEGATIVE(regnum));
  AVER(regnum <= 7);
  AVER(mfc->ucontext != NULL);

  /* TODO: The current arrangement of the fix operation (taking a Ref *)
     forces us to pun these registers (actually `int` on LII3GC).  We can
     suppress the warning by casting through `void *` and this might make
     it safe, but does it really?  RB 2012-09-10 */
  AVER(sizeof(void *) == sizeof(*mfc->ucontext->uc_mcontext.gregs));
  gregs = (void *)mfc->ucontext->uc_mcontext.gregs;

  /* .source.i486 */
  /* .assume.regref */
  /* The register numbers (REG_EAX etc.) are defined in <ucontext.h>
     but only if _GNU_SOURCE is defined: see .feature.li in
     config.h. */
  switch (regnum) {
    case 0: return &gregs[REG_EAX];
    case 1: return &gregs[REG_ECX];
    case 2: return &gregs[REG_EDX];
    case 3: return &gregs[REG_EBX];
    case 4: return &gregs[REG_ESP];
    case 5: return &gregs[REG_EBP];
    case 6: return &gregs[REG_ESI];
    case 7: return &gregs[REG_EDI];
    default:
      NOTREACHED;
      return NULL;  /* Avoids compiler warning. */
  }
}
Beispiel #7
0
MRef Prmci6AddressHoldingReg(MutatorFaultContext mfc, unsigned int regnum)
{
    THREAD_STATE_S *threadState;

    AVER(mfc != NULL);
    AVER(NONNEGATIVE(regnum));
    AVER(regnum <= 15);
    AVER(mfc->threadState != NULL);
    threadState = mfc->threadState;

    /* .assume.regref */
    /* The register numbers (REG_RAX etc.) are defined in <ucontext.h>
       but only if _XOPEN_SOURCE is defined: see .feature.xc in
       config.h. */
    /* MRef (a Word *) is not compatible with pointers to the register
       types (actually a __uint64_t). To avoid aliasing optimization
       problems, the registers are cast through (void *). */
    switch (regnum) {
    case  0:
        return (void *)&threadState->__rax;
    case  1:
        return (void *)&threadState->__rcx;
    case  2:
        return (void *)&threadState->__rdx;
    case  3:
        return (void *)&threadState->__rbx;
    case  4:
        return (void *)&threadState->__rsp;
    case  5:
        return (void *)&threadState->__rbp;
    case  6:
        return (void *)&threadState->__rsi;
    case  7:
        return (void *)&threadState->__rdi;
    case  8:
        return (void *)&threadState->__r8;
    case  9:
        return (void *)&threadState->__r9;
    case 10:
        return (void *)&threadState->__r10;
    case 11:
        return (void *)&threadState->__r11;
    case 12:
        return (void *)&threadState->__r12;
    case 13:
        return (void *)&threadState->__r13;
    case 14:
        return (void *)&threadState->__r14;
    case 15:
        return (void *)&threadState->__r15;
    default:
        NOTREACHED;
        return NULL;  /* Avoids compiler warning. */
    }
}
Beispiel #8
0
static int
stdout_handler(sd_event_source *es, int fd, uint32_t revents, void *vorig_fd)
{
    (void)es;
    (void)revents;
    int orig_fd = *(int *)vorig_fd;
    char buf[BUFSIZ];
    int n;

    n = (int)read(fd, buf, sizeof(buf));
    if (n < 0) {
        if (errno == EAGAIN) {
            return 0;
        } else {
            NONNEGATIVE(n);
        }
    } else {
        NONNEGATIVE(write(STDOUT_FILENO, &orig_fd, sizeof(orig_fd)));
        NONNEGATIVE(write(STDOUT_FILENO, &n, sizeof(n)));
        NONNEGATIVE(write(STDOUT_FILENO, buf, (size_t)n));
    }

    return 0;
}
Beispiel #9
0
void EventFlush(EventKind kind)
{
  AVER(eventInited);
  AVER(NONNEGATIVE(kind));
  AVER(kind < EventKindLIMIT);

  AVER(EventBuffer[kind] <= EventLast[kind]);
  AVER(EventLast[kind] <= EventWritten[kind]);
  AVER(EventWritten[kind] <= EventBuffer[kind] + EventBufferSIZE);

  /* Send all pending events to the event stream. */
  EventSync();

  /* Flush the in-memory buffer whether or not we send this buffer, so
     that we can continue to record recent events. */
  EventLast[kind] = EventWritten[kind] = EventBuffer[kind] + EventBufferSIZE;
}
Beispiel #10
0
Bool ChunkCheck(Chunk chunk)
{
  CHECKS(Chunk, chunk);
  CHECKU(Arena, chunk->arena);
  CHECKL(chunk->serial < chunk->arena->chunkSerial);
  /* Can't use CHECKD_NOSIG because TreeEMPTY is NULL. */
  CHECKL(TreeCheck(&chunk->chunkTree));
  CHECKL(ChunkPagesToSize(chunk, 1) == ChunkPageSize(chunk));
  CHECKL(ShiftCheck(ChunkPageShift(chunk)));

  CHECKL(chunk->base != (Addr)0);
  CHECKL(chunk->base < chunk->limit);
  /* check chunk structure is at its own base: see .chunk.at.base. */
  CHECKL(chunk->base == (Addr)chunk);
  CHECKL((Addr)(chunk+1) <= chunk->limit);
  CHECKL(ChunkSizeToPages(chunk, ChunkSize(chunk)) == chunk->pages);
  /* check that the tables fit in the chunk */
  CHECKL(chunk->allocBase <= chunk->pages);
  CHECKL(chunk->allocBase >= chunk->pageTablePages);

  CHECKD_NOSIG(BT, chunk->allocTable);
  /* check that allocTable is in the chunk overhead */
  CHECKL((Addr)chunk->allocTable >= chunk->base);
  CHECKL(AddrAdd((Addr)chunk->allocTable, BTSize(chunk->pages))
         <= PageIndexBase(chunk, chunk->allocBase));

  /* check they don't overlap (knowing the order) */
  CHECKL(AddrAdd((Addr)chunk->allocTable, BTSize(chunk->pages))
         <= (Addr)chunk->pageTable);

  CHECKL(chunk->pageTable != NULL);
  CHECKL((Addr)chunk->pageTable >= chunk->base);
  CHECKL((Addr)&chunk->pageTable[chunk->pageTablePages]
         <= PageIndexBase(chunk, chunk->allocBase));
  CHECKL(NONNEGATIVE(INDEX_OF_ADDR(chunk, (Addr)chunk->pageTable)));
  /* check there's enough space in the page table */
  CHECKL(INDEX_OF_ADDR(chunk, AddrSub(chunk->limit, 1)) < chunk->pages);
  CHECKL(chunk->pageTablePages < chunk->pages);

  /* Could check the consistency of the tables, but not O(1). */
  return TRUE;
}
Beispiel #11
0
MRef Prmci3AddressHoldingReg(MutatorFaultContext context, unsigned int regnum)
{
  PCONTEXT wincont;

  AVER(NONNEGATIVE(regnum));
  AVER(regnum <= 7);

  wincont = context->ep->ContextRecord;

  switch (regnum) {
  case 0: return (MRef)&wincont->Eax;
  case 1: return (MRef)&wincont->Ecx;
  case 2: return (MRef)&wincont->Edx;
  case 3: return (MRef)&wincont->Ebx;
  case 4: return (MRef)&wincont->Esp;
  case 5: return (MRef)&wincont->Ebp;
  case 6: return (MRef)&wincont->Esi;
  case 7: return (MRef)&wincont->Edi;
  default:
    NOTREACHED;
    return NULL; /* suppress warning */
  }
}
Beispiel #12
0
static int
sigchld_handler(sd_event_source *es, const struct signalfd_siginfo *si, void *vmpid)
{
    (void)es;
    pid_t mpid = *(pid_t *)vmpid;
    if (si->ssi_signo != SIGCHLD) ERROR("parent: unexpected signal");

    while (true) {
        int status;
        pid_t spid = waitpid(-mpid, &status, WNOHANG | __WALL);
        NONNEGATIVE(spid);
        if (!spid) break;

        if (WIFEXITED(status) && spid == mpid) {
            FINISH(POE_SUCCESS, WEXITSTATUS(status), NULL);
        } else if (WIFSIGNALED(status) && spid == mpid) {
            FINISH(POE_SIGNALED, -1, "Program terminated with signal %d (%s)", WTERMSIG(status), strsignal(WTERMSIG(status)));
        } else if (WIFSTOPPED(status)) {
            int e = status >> 16 & 0xff;
            switch (e) {
            case PTRACE_EVENT_SECCOMP:
                handle_syscall(spid);
                break;
            case PTRACE_EVENT_CLONE:
            case PTRACE_EVENT_FORK:
            case PTRACE_EVENT_VFORK:
                ptrace(PTRACE_CONT, spid, 0, 0);
                break;
            default:
                ptrace(PTRACE_CONT, spid, 0, WSTOPSIG(status));
                break;
            }
        }
    }
    return 0;
}
Beispiel #13
0
static void
child(const char *root, char *cmd[])
{
    pid_t pid = (pid_t)syscall(SYS_getpid);
    assert(pid == 1);

    // die when parent dies
    NONNEGATIVE(prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0));

    NONNEGATIVE(sethostname(POE_HOSTNAME, strlen(POE_HOSTNAME)));
    NONNEGATIVE(mount(NULL, "/",        NULL,           MS_PRIVATE | MS_REC, NULL));
    NONNEGATIVE(mount(root, root,       "bind",         MS_BIND | MS_REC, NULL));
    NONNEGATIVE(chroot(root));
    // NONNEGATIVE(mount(NULL, "/proc",    "proc",         MS_NOSUID | MS_NOEXEC | MS_NODEV, NULL));
    // NONNEGATIVE(mount(NULL, "/dev",     "devtmpfs",     MS_NOSUID | MS_NOEXEC, NULL));
    // NONNEGATIVE(mount(NULL, "/dev/shm", "tmpfs",        MS_NOSUID | MS_NODEV, NULL));

    struct passwd *pw = getpwnam(POE_USERNAME);
    if (!pw) ERROR("getpwnam() failed");

    NONNEGATIVE(chdir("/tmp"));
    NONNEGATIVE(setsid());
    NONNEGATIVE(initgroups(POE_USERNAME, pw->pw_gid));
    NONNEGATIVE(setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid));
    NONNEGATIVE(setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid));

    char *env[] = {
        "PATH=/opt/bin:/usr/bin",
        "USER="******"LOGNAME=" POE_USERNAME,
        NULL,
        NULL
    };
    NONNEGATIVE(asprintf(env + 3, "HOME=%s", pw->pw_dir));

    // wait parent
    NONNEGATIVE(kill(pid, SIGSTOP));

    NONNEGATIVE(prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
    poe_init_seccomp(SCMP_ACT_TRACE(0));

    NONNEGATIVE(execvpe(cmd[0], cmd, env));
}
Beispiel #14
0
int
main(int argc, char *argv[])
{
    if (argc < 5) {
        ERROR("usage: %s baseroot envroot program cmdl..", program_invocation_short_name);
    }

    const char *root = poe_init_playground(argv[1], argv[2]);
    const char *prog = copy_program(root, argv[3]);
    char **cmdl = construct_cmdl(argc - 4, argv + 4, prog);

    int stdout_fd[2], stderr_fd[2];
    NONNEGATIVE(pipe2(stdout_fd, O_DIRECT));
    NONNEGATIVE(pipe2(stderr_fd, O_DIRECT));

    // TODO: CLONE_NEWUSER
    pid_t pid = (pid_t)syscall(SYS_clone, SIGCHLD | CLONE_NEWIPC | CLONE_NEWNS | CLONE_NEWPID | CLONE_NEWUTS | CLONE_NEWNET, 0);
    NONNEGATIVE(pid);

    if (pid == 0) {
        dup2(stdout_fd[1], STDOUT_FILENO);
        close(stdout_fd[0]);
        close(stdout_fd[1]);
        dup2(stderr_fd[1], STDERR_FILENO);
        close(stderr_fd[0]);
        close(stderr_fd[1]);

        child(root, cmdl);
    } else {
        sd_event *event = NULL;
        uint64_t now;
        int stdout_fileno = STDOUT_FILENO;
        int stderr_fileno = STDERR_FILENO;

        int fflags;
        fflags = fcntl(stdout_fd[0], F_GETFL, 0);
        NONNEGATIVE(fflags);
        NONNEGATIVE(fcntl(stdout_fd[0], F_SETFL, fflags | O_NONBLOCK));
        fflags = fcntl(stderr_fd[0], F_GETFL, 0);
        NONNEGATIVE(fflags);
        NONNEGATIVE(fcntl(stderr_fd[0], F_SETFL, fflags | O_NONBLOCK));

        sigset_t mask;
        sigemptyset(&mask);
        sigaddset(&mask, SIGCHLD);
        sigaddset(&mask, SIGINT);
        sigaddset(&mask, SIGTERM);
        sigprocmask(SIG_BLOCK, &mask, NULL);

        NONNEGATIVE(sd_event_default(&event));
        NONNEGATIVE(sd_event_add_signal(event, NULL, SIGCHLD, sigchld_handler, &pid));
        NONNEGATIVE(sd_event_add_signal(event, NULL, SIGINT, sigint_handler, &pid));
        NONNEGATIVE(sd_event_add_signal(event, NULL, SIGTERM, sigint_handler, &pid));
        NONNEGATIVE(sd_event_now(event, CLOCK_MONOTONIC, &now));
        NONNEGATIVE(sd_event_add_time(event, NULL, CLOCK_MONOTONIC, now + POE_TIME_LIMIT, 0, timer_handler, &pid));
        NONNEGATIVE(sd_event_add_io(event, NULL, stdout_fd[0], EPOLLIN, stdout_handler, &stdout_fileno));
        NONNEGATIVE(sd_event_add_io(event, NULL, stderr_fd[0], EPOLLIN, stdout_handler, &stderr_fileno));

        NONNEGATIVE(ptrace(PTRACE_SEIZE, pid, NULL, PTRACE_O_TRACECLONE | PTRACE_O_TRACEFORK | PTRACE_O_TRACESECCOMP | PTRACE_O_TRACEVFORK));

        poe_init_systemd(pid);

        NONNEGATIVE(sd_event_loop(event));
    }

    ERROR("unreachable");
}
Beispiel #15
0
char *
poe_init_playground(const char *base, const char *env)
{
    struct stat s;
    if (stat(POE_TEMPORARY_BASE, &s) == -1) {
        NONNEGATIVE(mkdir(POE_TEMPORARY_BASE, 0755));
    }

    // setup base (tmpfs)
    NONNEGATIVE(asprintf(&workbase, POE_TEMPORARY_BASE "/%ld", (long)getpid())); // pid_t is signed, not larger than long
    if (stat(workbase, &s) != -1) {
        NONNEGATIVE(rmrf(workbase));
    }
    NONNEGATIVE(mkdir(workbase, 0755));
    NONNEGATIVE(mount(NULL, workbase, "tmpfs", MS_NOSUID, "size=32m")); // TODO

    NONNEGATIVE(asprintf(&workdir, "%s/work", workbase));
    NONNEGATIVE(mkdir(workdir, 0755));

    NONNEGATIVE(asprintf(&upperdir, "%s/upper", workbase));
    NONNEGATIVE(mkdir(upperdir, 0755));

    NONNEGATIVE(asprintf(&mergeddir, "%s/merged", workbase));
    NONNEGATIVE(mkdir(mergeddir, 0755));

    char *opts = NULL;
    NONNEGATIVE(asprintf(&opts, "lowerdir=%s:%s,upperdir=%s,workdir=%s", env, base, upperdir, workdir));
    NONNEGATIVE(mount(NULL, mergeddir, "overlay", MS_NOSUID, opts));

    return mergeddir;
}