um: separate child and parent errors in clone stub
authorJohannes Berg <johannes.berg@intel.com>
Wed, 13 Jan 2021 21:09:42 +0000 (22:09 +0100)
committerRichard Weinberger <richard@nod.at>
Fri, 12 Feb 2021 20:34:33 +0000 (21:34 +0100)
If the two are mixed up, then it looks as though the parent
returned an error if the child failed (before) the mmap(),
and then the resulting process never gets killed. Fix this
by splitting the child and parent errors, reporting and
using them appropriately.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Richard Weinberger <richard@nod.at>
arch/um/include/shared/skas/stub-data.h
arch/um/kernel/skas/clone.c
arch/um/os-Linux/skas/process.c
arch/x86/um/shared/sysdep/stub_32.h
arch/x86/um/shared/sysdep/stub_64.h

index 6b01d97a938677f945325e729e911108d2c3311f..5e3ade3fb38b3af9d6dc371c96c169a3db72f150 100644 (file)
@@ -11,7 +11,7 @@
 struct stub_data {
        unsigned long offset;
        int fd;
-       long err;
+       long parent_err, child_err;
 };
 
 #endif
index bfb70c456b302ad8a19cde1869768e8c208573bf..7c592c788cbf4a613f3407496f92a4cba540899e 100644 (file)
 void __attribute__ ((__section__ (".__syscall_stub")))
 stub_clone_handler(void)
 {
-       struct stub_data *data = (struct stub_data *) STUB_DATA;
+       int stack;
+       struct stub_data *data = (void *) ((unsigned long)&stack & ~(UM_KERN_PAGE_SIZE - 1));
        long err;
 
        err = stub_syscall2(__NR_clone, CLONE_PARENT | CLONE_FILES | SIGCHLD,
-                           STUB_DATA + UM_KERN_PAGE_SIZE / 2 - sizeof(void *));
-       if (err != 0)
-               goto out;
+                           (unsigned long)data + UM_KERN_PAGE_SIZE / 2 - sizeof(void *));
+       if (err) {
+               data->parent_err = err;
+               goto done;
+       }
 
        err = stub_syscall4(__NR_ptrace, PTRACE_TRACEME, 0, 0, 0);
-       if (err)
-               goto out;
+       if (err) {
+               data->child_err = err;
+               goto done;
+       }
 
        remap_stack(data->fd, data->offset);
        goto done;
 
- out:
-       /*
-        * save current result.
-        * Parent: pid;
-        * child: retcode of mmap already saved and it jumps around this
-        * assignment
-        */
-       data->err = err;
  done:
        trap_myself();
 }
index d910e25c273e1e4ccabcbae38d53cfc97e86aaf5..623b0aeadf4c7a24c90150d59fe164270d0e0533 100644 (file)
@@ -545,8 +545,14 @@ int copy_context_skas0(unsigned long new_stack, int pid)
         * and child's mmap2 calls
         */
        *data = ((struct stub_data) {
-                       .offset = MMAP_OFFSET(new_offset),
-                       .fd     = new_fd
+               .offset = MMAP_OFFSET(new_offset),
+               .fd     = new_fd,
+               .parent_err = -ESRCH,
+               .child_err = 0,
+       });
+
+       *child_data = ((struct stub_data) {
+               .child_err = -ESRCH,
        });
 
        err = ptrace_setregs(pid, thread_regs);
@@ -564,9 +570,6 @@ int copy_context_skas0(unsigned long new_stack, int pid)
                return err;
        }
 
-       /* set a well known return code for detection of child write failure */
-       child_data->err = 12345678;
-
        /*
         * Wait, until parent has finished its work: read child's pid from
         * parent's stack, and check, if bad result.
@@ -581,7 +584,7 @@ int copy_context_skas0(unsigned long new_stack, int pid)
 
        wait_stub_done(pid);
 
-       pid = data->err;
+       pid = data->parent_err;
        if (pid < 0) {
                printk(UM_KERN_ERR "copy_context_skas0 - stub-parent reports "
                       "error %d\n", -pid);
@@ -593,10 +596,10 @@ int copy_context_skas0(unsigned long new_stack, int pid)
         * child's stack and check it.
         */
        wait_stub_done(pid);
-       if (child_data->err != STUB_DATA) {
-               printk(UM_KERN_ERR "copy_context_skas0 - stub-child reports "
-                      "error %ld\n", child_data->err);
-               err = child_data->err;
+       if (child_data->child_err != STUB_DATA) {
+               printk(UM_KERN_ERR "copy_context_skas0 - stub-child %d reports "
+                      "error %ld\n", pid, data->child_err);
+               err = data->child_err;
                goto out_kill;
        }
 
index 51fd256c75f00f8f268f171f50336fa2db8437bc..8ea69211e53cb80cfc8fb2bcb89acdad3ad5118f 100644 (file)
@@ -86,7 +86,7 @@ static inline void remap_stack(int fd, unsigned long offset)
                            "d" (PROT_READ | PROT_WRITE),
                            "S" (MAP_FIXED | MAP_SHARED), "D" (fd),
                            "a" (offset),
-                           "i" (&((struct stub_data *) STUB_DATA)->err)
+                           "i" (&((struct stub_data *) STUB_DATA)->child_err)
                          : "memory");
 }
 
index 994df93c5ed34b712c416fe95e0e18779d7426ef..b7b8b8e4359dfb0749953eca9dae93796a1685f2 100644 (file)
@@ -92,7 +92,7 @@ static inline void remap_stack(long fd, unsigned long offset)
                            "d" (PROT_READ | PROT_WRITE),
                             "g" (MAP_FIXED | MAP_SHARED), "g" (fd),
                            "g" (offset),
-                           "i" (&((struct stub_data *) STUB_DATA)->err)
+                           "i" (&((struct stub_data *) STUB_DATA)->child_err)
                          : __syscall_clobber, "r10", "r8", "r9" );
 }