LCOV - code coverage report
Current view: top level - arch/um/os-Linux/skas - process.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 42 267 15.7 %
Date: 2022-12-09 01:23:36 Functions: 6 17 35.3 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0
       2             : /*
       3             :  * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de)
       4             :  * Copyright (C) 2002- 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
       5             :  */
       6             : 
       7             : #include <stdlib.h>
       8             : #include <unistd.h>
       9             : #include <sched.h>
      10             : #include <errno.h>
      11             : #include <string.h>
      12             : #include <sys/mman.h>
      13             : #include <sys/wait.h>
      14             : #include <asm/unistd.h>
      15             : #include <as-layout.h>
      16             : #include <init.h>
      17             : #include <kern_util.h>
      18             : #include <mem.h>
      19             : #include <os.h>
      20             : #include <ptrace_user.h>
      21             : #include <registers.h>
      22             : #include <skas.h>
      23             : #include <sysdep/stub.h>
      24             : #include <linux/threads.h>
      25             : 
      26           0 : int is_skas_winch(int pid, int fd, void *data)
      27             : {
      28           0 :         return pid == getpgrp();
      29             : }
      30             : 
      31             : static const char *ptrace_reg_name(int idx)
      32             : {
      33             : #define R(n) case HOST_##n: return #n
      34             : 
      35             :         switch (idx) {
      36             : #ifdef __x86_64__
      37             :         R(BX);
      38             :         R(CX);
      39             :         R(DI);
      40             :         R(SI);
      41             :         R(DX);
      42             :         R(BP);
      43             :         R(AX);
      44             :         R(R8);
      45             :         R(R9);
      46             :         R(R10);
      47             :         R(R11);
      48             :         R(R12);
      49             :         R(R13);
      50             :         R(R14);
      51             :         R(R15);
      52             :         R(ORIG_AX);
      53             :         R(CS);
      54             :         R(SS);
      55             :         R(EFLAGS);
      56             : #elif defined(__i386__)
      57             :         R(IP);
      58             :         R(SP);
      59             :         R(EFLAGS);
      60             :         R(AX);
      61             :         R(BX);
      62             :         R(CX);
      63             :         R(DX);
      64             :         R(SI);
      65             :         R(DI);
      66             :         R(BP);
      67             :         R(CS);
      68             :         R(SS);
      69             :         R(DS);
      70             :         R(FS);
      71             :         R(ES);
      72             :         R(GS);
      73             :         R(ORIG_AX);
      74             : #endif
      75             :         }
      76             :         return "";
      77             : }
      78             : 
      79           0 : static int ptrace_dump_regs(int pid)
      80             : {
      81             :         unsigned long regs[MAX_REG_NR];
      82             :         int i;
      83             : 
      84           0 :         if (ptrace(PTRACE_GETREGS, pid, 0, regs) < 0)
      85           0 :                 return -errno;
      86             : 
      87           0 :         printk(UM_KERN_ERR "Stub registers -\n");
      88           0 :         for (i = 0; i < ARRAY_SIZE(regs); i++) {
      89           0 :                 const char *regname = ptrace_reg_name(i);
      90             : 
      91           0 :                 printk(UM_KERN_ERR "\t%s\t(%2d): %lx\n", regname, i, regs[i]);
      92             :         }
      93             : 
      94             :         return 0;
      95             : }
      96             : 
      97             : /*
      98             :  * Signals that are OK to receive in the stub - we'll just continue it.
      99             :  * SIGWINCH will happen when UML is inside a detached screen.
     100             :  */
     101             : #define STUB_SIG_MASK ((1 << SIGALRM) | (1 << SIGWINCH))
     102             : 
     103             : /* Signals that the stub will finish with - anything else is an error */
     104             : #define STUB_DONE_MASK (1 << SIGTRAP)
     105             : 
     106           0 : void wait_stub_done(int pid)
     107             : {
     108             :         int n, status, err;
     109             : 
     110             :         while (1) {
     111           0 :                 CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED | __WALL));
     112           0 :                 if ((n < 0) || !WIFSTOPPED(status))
     113             :                         goto bad_wait;
     114             : 
     115           0 :                 if (((1 << WSTOPSIG(status)) & STUB_SIG_MASK) == 0)
     116             :                         break;
     117             : 
     118           0 :                 err = ptrace(PTRACE_CONT, pid, 0, 0);
     119           0 :                 if (err) {
     120           0 :                         printk(UM_KERN_ERR "wait_stub_done : continue failed, "
     121             :                                "errno = %d\n", errno);
     122           0 :                         fatal_sigsegv();
     123             :                 }
     124             :         }
     125             : 
     126           0 :         if (((1 << WSTOPSIG(status)) & STUB_DONE_MASK) != 0)
     127           0 :                 return;
     128             : 
     129             : bad_wait:
     130           0 :         err = ptrace_dump_regs(pid);
     131           0 :         if (err)
     132           0 :                 printk(UM_KERN_ERR "Failed to get registers from stub, "
     133             :                        "errno = %d\n", -err);
     134           0 :         printk(UM_KERN_ERR "wait_stub_done : failed to wait for SIGTRAP, "
     135             :                "pid = %d, n = %d, errno = %d, status = 0x%x\n", pid, n, errno,
     136             :                status);
     137           0 :         fatal_sigsegv();
     138             : }
     139             : 
     140             : extern unsigned long current_stub_stack(void);
     141             : 
     142           0 : static void get_skas_faultinfo(int pid, struct faultinfo *fi, unsigned long *aux_fp_regs)
     143             : {
     144             :         int err;
     145             : 
     146           0 :         err = get_fp_registers(pid, aux_fp_regs);
     147           0 :         if (err < 0) {
     148           0 :                 printk(UM_KERN_ERR "save_fp_registers returned %d\n",
     149             :                        err);
     150           0 :                 fatal_sigsegv();
     151             :         }
     152           0 :         err = ptrace(PTRACE_CONT, pid, 0, SIGSEGV);
     153           0 :         if (err) {
     154           0 :                 printk(UM_KERN_ERR "Failed to continue stub, pid = %d, "
     155             :                        "errno = %d\n", pid, errno);
     156           0 :                 fatal_sigsegv();
     157             :         }
     158           0 :         wait_stub_done(pid);
     159             : 
     160             :         /*
     161             :          * faultinfo is prepared by the stub_segv_handler at start of
     162             :          * the stub stack page. We just have to copy it.
     163             :          */
     164           0 :         memcpy(fi, (void *)current_stub_stack(), sizeof(*fi));
     165             : 
     166           0 :         err = put_fp_registers(pid, aux_fp_regs);
     167           0 :         if (err < 0) {
     168           0 :                 printk(UM_KERN_ERR "put_fp_registers returned %d\n",
     169             :                        err);
     170           0 :                 fatal_sigsegv();
     171             :         }
     172           0 : }
     173             : 
     174             : static void handle_segv(int pid, struct uml_pt_regs *regs, unsigned long *aux_fp_regs)
     175             : {
     176             :         get_skas_faultinfo(pid, &regs->faultinfo, aux_fp_regs);
     177             :         segv(regs->faultinfo, 0, 1, NULL);
     178             : }
     179             : 
     180             : /*
     181             :  * To use the same value of using_sysemu as the caller, ask it that value
     182             :  * (in local_using_sysemu
     183             :  */
     184           0 : static void handle_trap(int pid, struct uml_pt_regs *regs,
     185             :                         int local_using_sysemu)
     186             : {
     187             :         int err, status;
     188             : 
     189           0 :         if ((UPT_IP(regs) >= STUB_START) && (UPT_IP(regs) < STUB_END))
     190           0 :                 fatal_sigsegv();
     191             : 
     192           0 :         if (!local_using_sysemu)
     193             :         {
     194           0 :                 err = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET,
     195             :                              __NR_getpid);
     196           0 :                 if (err < 0) {
     197           0 :                         printk(UM_KERN_ERR "handle_trap - nullifying syscall "
     198             :                                "failed, errno = %d\n", errno);
     199           0 :                         fatal_sigsegv();
     200             :                 }
     201             : 
     202           0 :                 err = ptrace(PTRACE_SYSCALL, pid, 0, 0);
     203           0 :                 if (err < 0) {
     204           0 :                         printk(UM_KERN_ERR "handle_trap - continuing to end of "
     205             :                                "syscall failed, errno = %d\n", errno);
     206           0 :                         fatal_sigsegv();
     207             :                 }
     208             : 
     209           0 :                 CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED | __WALL));
     210           0 :                 if ((err < 0) || !WIFSTOPPED(status) ||
     211           0 :                     (WSTOPSIG(status) != SIGTRAP + 0x80)) {
     212           0 :                         err = ptrace_dump_regs(pid);
     213           0 :                         if (err)
     214           0 :                                 printk(UM_KERN_ERR "Failed to get registers "
     215             :                                        "from process, errno = %d\n", -err);
     216           0 :                         printk(UM_KERN_ERR "handle_trap - failed to wait at "
     217             :                                "end of syscall, errno = %d, status = %d\n",
     218             :                                errno, status);
     219           0 :                         fatal_sigsegv();
     220             :                 }
     221             :         }
     222             : 
     223           0 :         handle_syscall(regs);
     224           0 : }
     225             : 
     226             : extern char __syscall_stub_start[];
     227             : 
     228             : /**
     229             :  * userspace_tramp() - userspace trampoline
     230             :  * @stack:      pointer to the new userspace stack page, can be NULL, if? FIXME:
     231             :  *
     232             :  * The userspace trampoline is used to setup a new userspace process in start_userspace() after it was clone()'ed.
     233             :  * This function will run on a temporary stack page.
     234             :  * It ptrace()'es itself, then
     235             :  * Two pages are mapped into the userspace address space:
     236             :  * - STUB_CODE (with EXEC), which contains the skas stub code
     237             :  * - STUB_DATA (with R/W), which contains a data page that is used to transfer certain data between the UML userspace process and the UML kernel.
     238             :  * Also for the userspace process a SIGSEGV handler is installed to catch pagefaults in the userspace process.
     239             :  * And last the process stops itself to give control to the UML kernel for this userspace process.
     240             :  *
     241             :  * Return: Always zero, otherwise the current userspace process is ended with non null exit() call
     242             :  */
     243           0 : static int userspace_tramp(void *stack)
     244             : {
     245             :         void *addr;
     246             :         int fd;
     247             :         unsigned long long offset;
     248             : 
     249           0 :         ptrace(PTRACE_TRACEME, 0, 0, 0);
     250             : 
     251           0 :         signal(SIGTERM, SIG_DFL);
     252           0 :         signal(SIGWINCH, SIG_IGN);
     253             : 
     254           0 :         fd = phys_mapping(to_phys(__syscall_stub_start), &offset);
     255           0 :         addr = mmap64((void *) STUB_CODE, UM_KERN_PAGE_SIZE,
     256             :                       PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, offset);
     257           0 :         if (addr == MAP_FAILED) {
     258           0 :                 printk(UM_KERN_ERR "mapping mmap stub at 0x%lx failed, "
     259             :                        "errno = %d\n", STUB_CODE, errno);
     260           0 :                 exit(1);
     261             :         }
     262             : 
     263           0 :         if (stack != NULL) {
     264           0 :                 fd = phys_mapping(to_phys(stack), &offset);
     265           0 :                 addr = mmap((void *) STUB_DATA,
     266             :                             UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE,
     267             :                             MAP_FIXED | MAP_SHARED, fd, offset);
     268           0 :                 if (addr == MAP_FAILED) {
     269           0 :                         printk(UM_KERN_ERR "mapping segfault stack "
     270             :                                "at 0x%lx failed, errno = %d\n",
     271             :                                STUB_DATA, errno);
     272           0 :                         exit(1);
     273             :                 }
     274             :         }
     275           0 :         if (stack != NULL) {
     276             :                 struct sigaction sa;
     277             : 
     278           0 :                 unsigned long v = STUB_CODE +
     279           0 :                                   (unsigned long) stub_segv_handler -
     280             :                                   (unsigned long) __syscall_stub_start;
     281             : 
     282           0 :                 set_sigstack((void *) STUB_DATA, UM_KERN_PAGE_SIZE);
     283           0 :                 sigemptyset(&sa.sa_mask);
     284           0 :                 sa.sa_flags = SA_ONSTACK | SA_NODEFER | SA_SIGINFO;
     285           0 :                 sa.sa_sigaction = (void *) v;
     286           0 :                 sa.sa_restorer = NULL;
     287           0 :                 if (sigaction(SIGSEGV, &sa, NULL) < 0) {
     288           0 :                         printk(UM_KERN_ERR "userspace_tramp - setting SIGSEGV "
     289             :                                "handler failed - errno = %d\n", errno);
     290           0 :                         exit(1);
     291             :                 }
     292             :         }
     293             : 
     294           0 :         kill(os_getpid(), SIGSTOP);
     295           0 :         return 0;
     296             : }
     297             : 
     298             : int userspace_pid[NR_CPUS];
     299             : int kill_userspace_mm[NR_CPUS];
     300             : 
     301             : /**
     302             :  * start_userspace() - prepare a new userspace process
     303             :  * @stub_stack: pointer to the stub stack. Can be NULL, if? FIXME:
     304             :  *
     305             :  * Setups a new temporary stack page that is used while userspace_tramp() runs
     306             :  * Clones the kernel process into a new userspace process, with FDs only.
     307             :  *
     308             :  * Return: When positive: the process id of the new userspace process,
     309             :  *         when negative: an error number.
     310             :  * FIXME: can PIDs become negative?!
     311             :  */
     312           0 : int start_userspace(unsigned long stub_stack)
     313             : {
     314             :         void *stack;
     315             :         unsigned long sp;
     316             :         int pid, status, n, flags, err;
     317             : 
     318             :         /* setup a temporary stack page */
     319           0 :         stack = mmap(NULL, UM_KERN_PAGE_SIZE,
     320             :                      PROT_READ | PROT_WRITE | PROT_EXEC,
     321             :                      MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
     322           0 :         if (stack == MAP_FAILED) {
     323           0 :                 err = -errno;
     324           0 :                 printk(UM_KERN_ERR "start_userspace : mmap failed, "
     325             :                        "errno = %d\n", errno);
     326           0 :                 return err;
     327             :         }
     328             : 
     329             :         /* set stack pointer to the end of the stack page, so it can grow downwards */
     330           0 :         sp = (unsigned long)stack + UM_KERN_PAGE_SIZE;
     331             : 
     332           0 :         flags = CLONE_FILES | SIGCHLD;
     333             : 
     334             :         /* clone into new userspace process */
     335           0 :         pid = clone(userspace_tramp, (void *) sp, flags, (void *) stub_stack);
     336           0 :         if (pid < 0) {
     337           0 :                 err = -errno;
     338           0 :                 printk(UM_KERN_ERR "start_userspace : clone failed, "
     339             :                        "errno = %d\n", errno);
     340           0 :                 return err;
     341             :         }
     342             : 
     343             :         do {
     344           0 :                 CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED | __WALL));
     345           0 :                 if (n < 0) {
     346           0 :                         err = -errno;
     347           0 :                         printk(UM_KERN_ERR "start_userspace : wait failed, "
     348             :                                "errno = %d\n", errno);
     349           0 :                         goto out_kill;
     350             :                 }
     351           0 :         } while (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGALRM));
     352             : 
     353           0 :         if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) {
     354           0 :                 err = -EINVAL;
     355           0 :                 printk(UM_KERN_ERR "start_userspace : expected SIGSTOP, got "
     356             :                        "status = %d\n", status);
     357           0 :                 goto out_kill;
     358             :         }
     359             : 
     360           0 :         if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL,
     361             :                    (void *) PTRACE_O_TRACESYSGOOD) < 0) {
     362           0 :                 err = -errno;
     363           0 :                 printk(UM_KERN_ERR "start_userspace : PTRACE_OLDSETOPTIONS "
     364             :                        "failed, errno = %d\n", errno);
     365           0 :                 goto out_kill;
     366             :         }
     367             : 
     368           0 :         if (munmap(stack, UM_KERN_PAGE_SIZE) < 0) {
     369           0 :                 err = -errno;
     370           0 :                 printk(UM_KERN_ERR "start_userspace : munmap failed, "
     371             :                        "errno = %d\n", errno);
     372           0 :                 goto out_kill;
     373             :         }
     374             : 
     375             :         return pid;
     376             : 
     377             :  out_kill:
     378           0 :         os_kill_ptraced_process(pid, 1);
     379           0 :         return err;
     380             : }
     381             : 
     382           0 : void userspace(struct uml_pt_regs *regs, unsigned long *aux_fp_regs)
     383             : {
     384           0 :         int err, status, op, pid = userspace_pid[0];
     385             :         /* To prevent races if using_sysemu changes under us.*/
     386             :         int local_using_sysemu;
     387             :         siginfo_t si;
     388             : 
     389             :         /* Handle any immediate reschedules or signals */
     390           0 :         interrupt_end();
     391             : 
     392             :         while (1) {
     393           0 :                 if (kill_userspace_mm[0])
     394           0 :                         fatal_sigsegv();
     395             : 
     396             :                 /*
     397             :                  * This can legitimately fail if the process loads a
     398             :                  * bogus value into a segment register.  It will
     399             :                  * segfault and PTRACE_GETREGS will read that value
     400             :                  * out of the process.  However, PTRACE_SETREGS will
     401             :                  * fail.  In this case, there is nothing to do but
     402             :                  * just kill the process.
     403             :                  */
     404           0 :                 if (ptrace(PTRACE_SETREGS, pid, 0, regs->gp)) {
     405           0 :                         printk(UM_KERN_ERR "userspace - ptrace set regs "
     406             :                                "failed, errno = %d\n", errno);
     407           0 :                         fatal_sigsegv();
     408             :                 }
     409             : 
     410           0 :                 if (put_fp_registers(pid, regs->fp)) {
     411           0 :                         printk(UM_KERN_ERR "userspace - ptrace set fp regs "
     412             :                                "failed, errno = %d\n", errno);
     413           0 :                         fatal_sigsegv();
     414             :                 }
     415             : 
     416             :                 /* Now we set local_using_sysemu to be used for one loop */
     417           0 :                 local_using_sysemu = get_using_sysemu();
     418             : 
     419           0 :                 op = SELECT_PTRACE_OPERATION(local_using_sysemu,
     420             :                                              singlestepping(NULL));
     421             : 
     422           0 :                 if (ptrace(op, pid, 0, 0)) {
     423           0 :                         printk(UM_KERN_ERR "userspace - ptrace continue "
     424             :                                "failed, op = %d, errno = %d\n", op, errno);
     425           0 :                         fatal_sigsegv();
     426             :                 }
     427             : 
     428           0 :                 CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED | __WALL));
     429           0 :                 if (err < 0) {
     430           0 :                         printk(UM_KERN_ERR "userspace - wait failed, "
     431             :                                "errno = %d\n", errno);
     432           0 :                         fatal_sigsegv();
     433             :                 }
     434             : 
     435           0 :                 regs->is_user = 1;
     436           0 :                 if (ptrace(PTRACE_GETREGS, pid, 0, regs->gp)) {
     437           0 :                         printk(UM_KERN_ERR "userspace - PTRACE_GETREGS failed, "
     438             :                                "errno = %d\n", errno);
     439           0 :                         fatal_sigsegv();
     440             :                 }
     441             : 
     442           0 :                 if (get_fp_registers(pid, regs->fp)) {
     443           0 :                         printk(UM_KERN_ERR "userspace -  get_fp_registers failed, "
     444             :                                "errno = %d\n", errno);
     445           0 :                         fatal_sigsegv();
     446             :                 }
     447             : 
     448           0 :                 UPT_SYSCALL_NR(regs) = -1; /* Assume: It's not a syscall */
     449             : 
     450           0 :                 if (WIFSTOPPED(status)) {
     451           0 :                         int sig = WSTOPSIG(status);
     452             : 
     453             :                         /* These signal handlers need the si argument.
     454             :                          * The SIGIO and SIGALARM handlers which constitute the
     455             :                          * majority of invocations, do not use it.
     456             :                          */
     457             :                         switch (sig) {
     458             :                         case SIGSEGV:
     459             :                         case SIGTRAP:
     460             :                         case SIGILL:
     461             :                         case SIGBUS:
     462             :                         case SIGFPE:
     463             :                         case SIGWINCH:
     464           0 :                                 ptrace(PTRACE_GETSIGINFO, pid, 0, (struct siginfo *)&si);
     465           0 :                                 break;
     466             :                         }
     467             : 
     468           0 :                         switch (sig) {
     469             :                         case SIGSEGV:
     470             :                                 if (PTRACE_FULL_FAULTINFO) {
     471           0 :                                         get_skas_faultinfo(pid,
     472             :                                                            &regs->faultinfo, aux_fp_regs);
     473           0 :                                         (*sig_info[SIGSEGV])(SIGSEGV, (struct siginfo *)&si,
     474             :                                                              regs);
     475             :                                 }
     476             :                                 else handle_segv(pid, regs, aux_fp_regs);
     477           0 :                                 break;
     478             :                         case SIGTRAP + 0x80:
     479           0 :                                 handle_trap(pid, regs, local_using_sysemu);
     480           0 :                                 break;
     481             :                         case SIGTRAP:
     482           0 :                                 relay_signal(SIGTRAP, (struct siginfo *)&si, regs);
     483           0 :                                 break;
     484             :                         case SIGALRM:
     485             :                                 break;
     486             :                         case SIGIO:
     487             :                         case SIGILL:
     488             :                         case SIGBUS:
     489             :                         case SIGFPE:
     490             :                         case SIGWINCH:
     491           0 :                                 block_signals_trace();
     492           0 :                                 (*sig_info[sig])(sig, (struct siginfo *)&si, regs);
     493           0 :                                 unblock_signals_trace();
     494           0 :                                 break;
     495             :                         default:
     496           0 :                                 printk(UM_KERN_ERR "userspace - child stopped "
     497             :                                        "with signal %d\n", sig);
     498           0 :                                 fatal_sigsegv();
     499             :                         }
     500           0 :                         pid = userspace_pid[0];
     501           0 :                         interrupt_end();
     502             : 
     503             :                         /* Avoid -ERESTARTSYS handling in host */
     504             :                         if (PT_SYSCALL_NR_OFFSET != PT_SYSCALL_RET_OFFSET)
     505           0 :                                 PT_SYSCALL_NR(regs->gp) = -1;
     506             :                 }
     507             :         }
     508             : }
     509             : 
     510             : static unsigned long thread_regs[MAX_REG_NR];
     511             : static unsigned long thread_fp_regs[FP_SIZE];
     512             : 
     513           1 : static int __init init_thread_regs(void)
     514             : {
     515           1 :         get_safe_registers(thread_regs, thread_fp_regs);
     516             :         /* Set parent's instruction pointer to start of clone-stub */
     517           1 :         thread_regs[REGS_IP_INDEX] = STUB_CODE +
     518           1 :                                 (unsigned long) stub_clone_handler -
     519             :                                 (unsigned long) __syscall_stub_start;
     520           1 :         thread_regs[REGS_SP_INDEX] = STUB_DATA + UM_KERN_PAGE_SIZE -
     521             :                 sizeof(void *);
     522             : #ifdef __SIGNAL_FRAMESIZE
     523             :         thread_regs[REGS_SP_INDEX] -= __SIGNAL_FRAMESIZE;
     524             : #endif
     525           1 :         return 0;
     526             : }
     527             : 
     528             : __initcall(init_thread_regs);
     529             : 
     530           0 : int copy_context_skas0(unsigned long new_stack, int pid)
     531             : {
     532             :         int err;
     533           0 :         unsigned long current_stack = current_stub_stack();
     534           0 :         struct stub_data *data = (struct stub_data *) current_stack;
     535           0 :         struct stub_data *child_data = (struct stub_data *) new_stack;
     536             :         unsigned long long new_offset;
     537           0 :         int new_fd = phys_mapping(to_phys((void *)new_stack), &new_offset);
     538             : 
     539             :         /*
     540             :          * prepare offset and fd of child's stack as argument for parent's
     541             :          * and child's mmap2 calls
     542             :          */
     543           0 :         *data = ((struct stub_data) {
     544             :                 .offset = MMAP_OFFSET(new_offset),
     545             :                 .fd     = new_fd,
     546             :                 .parent_err = -ESRCH,
     547             :                 .child_err = 0,
     548             :         });
     549             : 
     550           0 :         *child_data = ((struct stub_data) {
     551             :                 .child_err = -ESRCH,
     552             :         });
     553             : 
     554           0 :         err = ptrace_setregs(pid, thread_regs);
     555           0 :         if (err < 0) {
     556           0 :                 err = -errno;
     557           0 :                 printk(UM_KERN_ERR "copy_context_skas0 : PTRACE_SETREGS "
     558             :                        "failed, pid = %d, errno = %d\n", pid, -err);
     559           0 :                 return err;
     560             :         }
     561             : 
     562           0 :         err = put_fp_registers(pid, thread_fp_regs);
     563           0 :         if (err < 0) {
     564           0 :                 printk(UM_KERN_ERR "copy_context_skas0 : put_fp_registers "
     565             :                        "failed, pid = %d, err = %d\n", pid, err);
     566           0 :                 return err;
     567             :         }
     568             : 
     569             :         /*
     570             :          * Wait, until parent has finished its work: read child's pid from
     571             :          * parent's stack, and check, if bad result.
     572             :          */
     573           0 :         err = ptrace(PTRACE_CONT, pid, 0, 0);
     574           0 :         if (err) {
     575           0 :                 err = -errno;
     576           0 :                 printk(UM_KERN_ERR "Failed to continue new process, pid = %d, "
     577             :                        "errno = %d\n", pid, errno);
     578           0 :                 return err;
     579             :         }
     580             : 
     581           0 :         wait_stub_done(pid);
     582             : 
     583           0 :         pid = data->parent_err;
     584           0 :         if (pid < 0) {
     585           0 :                 printk(UM_KERN_ERR "copy_context_skas0 - stub-parent reports "
     586             :                        "error %d\n", -pid);
     587           0 :                 return pid;
     588             :         }
     589             : 
     590             :         /*
     591             :          * Wait, until child has finished too: read child's result from
     592             :          * child's stack and check it.
     593             :          */
     594           0 :         wait_stub_done(pid);
     595           0 :         if (child_data->child_err != STUB_DATA) {
     596           0 :                 printk(UM_KERN_ERR "copy_context_skas0 - stub-child %d reports "
     597             :                        "error %ld\n", pid, data->child_err);
     598           0 :                 err = data->child_err;
     599           0 :                 goto out_kill;
     600             :         }
     601             : 
     602           0 :         if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL,
     603             :                    (void *)PTRACE_O_TRACESYSGOOD) < 0) {
     604           0 :                 err = -errno;
     605           0 :                 printk(UM_KERN_ERR "copy_context_skas0 : PTRACE_OLDSETOPTIONS "
     606             :                        "failed, errno = %d\n", errno);
     607           0 :                 goto out_kill;
     608             :         }
     609             : 
     610             :         return pid;
     611             : 
     612             :  out_kill:
     613           0 :         os_kill_ptraced_process(pid, 1);
     614           0 :         return err;
     615             : }
     616             : 
     617         107 : void new_thread(void *stack, jmp_buf *buf, void (*handler)(void))
     618             : {
     619         107 :         (*buf)[0].JB_IP = (unsigned long) handler;
     620         107 :         (*buf)[0].JB_SP = (unsigned long) stack + UM_THREAD_SIZE -
     621             :                 sizeof(void *);
     622         107 : }
     623             : 
     624             : #define INIT_JMP_NEW_THREAD 0
     625             : #define INIT_JMP_CALLBACK 1
     626             : #define INIT_JMP_HALT 2
     627             : #define INIT_JMP_REBOOT 3
     628             : 
     629         618 : void switch_threads(jmp_buf *me, jmp_buf *you)
     630             : {
     631         618 :         if (UML_SETJMP(me) == 0)
     632         618 :                 UML_LONGJMP(you, 1);
     633         511 : }
     634             : 
     635             : static jmp_buf initial_jmpbuf;
     636             : 
     637             : /* XXX Make these percpu */
     638             : static void (*cb_proc)(void *arg);
     639             : static void *cb_arg;
     640             : static jmp_buf *cb_back;
     641             : 
     642           1 : int start_idle_thread(void *stack, jmp_buf *switch_buf)
     643             : {
     644             :         int n;
     645             : 
     646           1 :         set_handler(SIGWINCH);
     647             : 
     648             :         /*
     649             :          * Can't use UML_SETJMP or UML_LONGJMP here because they save
     650             :          * and restore signals, with the possible side-effect of
     651             :          * trying to handle any signals which came when they were
     652             :          * blocked, which can't be done on this stack.
     653             :          * Signals must be blocked when jumping back here and restored
     654             :          * after returning to the jumper.
     655             :          */
     656           1 :         n = setjmp(initial_jmpbuf);
     657           3 :         switch (n) {
     658             :         case INIT_JMP_NEW_THREAD:
     659           1 :                 (*switch_buf)[0].JB_IP = (unsigned long) uml_finishsetup;
     660           2 :                 (*switch_buf)[0].JB_SP = (unsigned long) stack +
     661           1 :                         UM_THREAD_SIZE - sizeof(void *);
     662           1 :                 break;
     663             :         case INIT_JMP_CALLBACK:
     664           1 :                 (*cb_proc)(cb_arg);
     665           1 :                 longjmp(*cb_back, 1);
     666           0 :                 break;
     667             :         case INIT_JMP_HALT:
     668           1 :                 kmalloc_ok = 0;
     669           1 :                 return 0;
     670             :         case INIT_JMP_REBOOT:
     671           0 :                 kmalloc_ok = 0;
     672           0 :                 return 1;
     673             :         default:
     674           0 :                 printk(UM_KERN_ERR "Bad sigsetjmp return in "
     675             :                        "start_idle_thread - %d\n", n);
     676           0 :                 fatal_sigsegv();
     677             :         }
     678           1 :         longjmp(*switch_buf, 1);
     679             : 
     680             :         /* unreachable */
     681           0 :         printk(UM_KERN_ERR "impossible long jump!");
     682           0 :         fatal_sigsegv();
     683             :         return 0;
     684             : }
     685             : 
     686           1 : void initial_thread_cb_skas(void (*proc)(void *), void *arg)
     687             : {
     688             :         jmp_buf here;
     689             : 
     690           1 :         cb_proc = proc;
     691           1 :         cb_arg = arg;
     692           1 :         cb_back = &here;
     693             : 
     694           1 :         block_signals_trace();
     695           1 :         if (UML_SETJMP(&here) == 0)
     696           1 :                 UML_LONGJMP(&initial_jmpbuf, INIT_JMP_CALLBACK);
     697           1 :         unblock_signals_trace();
     698             : 
     699           1 :         cb_proc = NULL;
     700           1 :         cb_arg = NULL;
     701           1 :         cb_back = NULL;
     702           1 : }
     703             : 
     704           1 : void halt_skas(void)
     705             : {
     706           1 :         block_signals_trace();
     707           1 :         UML_LONGJMP(&initial_jmpbuf, INIT_JMP_HALT);
     708           0 : }
     709             : 
     710           0 : void reboot_skas(void)
     711             : {
     712           0 :         block_signals_trace();
     713           0 :         UML_LONGJMP(&initial_jmpbuf, INIT_JMP_REBOOT);
     714           0 : }
     715             : 
     716           0 : void __switch_mm(struct mm_id *mm_idp)
     717             : {
     718           0 :         userspace_pid[0] = mm_idp->u.pid;
     719           0 :         kill_userspace_mm[0] = mm_idp->kill;
     720           0 : }

Generated by: LCOV version 1.14