Merge tag 'threads-v5.5' of git://git.kernel.org/pub/scm/linux/kernel/git/brauner...
[linux-2.6-microblaze.git] / kernel / fork.c
index 13b3879..35f91ee 100644 (file)
@@ -1517,6 +1517,11 @@ static int copy_sighand(unsigned long clone_flags, struct task_struct *tsk)
        spin_lock_irq(&current->sighand->siglock);
        memcpy(sig->action, current->sighand->action, sizeof(sig->action));
        spin_unlock_irq(&current->sighand->siglock);
+
+       /* Reset all signal handler not set to SIG_IGN to SIG_DFL. */
+       if (clone_flags & CLONE_CLEAR_SIGHAND)
+               flush_signal_handlers(tsk, 0);
+
        return 0;
 }
 
@@ -1695,12 +1700,68 @@ static int pidfd_release(struct inode *inode, struct file *file)
 }
 
 #ifdef CONFIG_PROC_FS
+/**
+ * pidfd_show_fdinfo - print information about a pidfd
+ * @m: proc fdinfo file
+ * @f: file referencing a pidfd
+ *
+ * Pid:
+ * This function will print the pid that a given pidfd refers to in the
+ * pid namespace of the procfs instance.
+ * If the pid namespace of the process is not a descendant of the pid
+ * namespace of the procfs instance 0 will be shown as its pid. This is
+ * similar to calling getppid() on a process whose parent is outside of
+ * its pid namespace.
+ *
+ * NSpid:
+ * If pid namespaces are supported then this function will also print
+ * the pid of a given pidfd refers to for all descendant pid namespaces
+ * starting from the current pid namespace of the instance, i.e. the
+ * Pid field and the first entry in the NSpid field will be identical.
+ * If the pid namespace of the process is not a descendant of the pid
+ * namespace of the procfs instance 0 will be shown as its first NSpid
+ * entry and no others will be shown.
+ * Note that this differs from the Pid and NSpid fields in
+ * /proc/<pid>/status where Pid and NSpid are always shown relative to
+ * the  pid namespace of the procfs instance. The difference becomes
+ * obvious when sending around a pidfd between pid namespaces from a
+ * different branch of the tree, i.e. where no ancestoral relation is
+ * present between the pid namespaces:
+ * - create two new pid namespaces ns1 and ns2 in the initial pid
+ *   namespace (also take care to create new mount namespaces in the
+ *   new pid namespace and mount procfs)
+ * - create a process with a pidfd in ns1
+ * - send pidfd from ns1 to ns2
+ * - read /proc/self/fdinfo/<pidfd> and observe that both Pid and NSpid
+ *   have exactly one entry, which is 0
+ */
 static void pidfd_show_fdinfo(struct seq_file *m, struct file *f)
 {
-       struct pid_namespace *ns = proc_pid_ns(file_inode(m->file));
        struct pid *pid = f->private_data;
+       struct pid_namespace *ns;
+       pid_t nr = -1;
+
+       if (likely(pid_has_task(pid, PIDTYPE_PID))) {
+               ns = proc_pid_ns(file_inode(m->file));
+               nr = pid_nr_ns(pid, ns);
+       }
+
+       seq_put_decimal_ll(m, "Pid:\t", nr);
+
+#ifdef CONFIG_PID_NS
+       seq_put_decimal_ll(m, "\nNSpid:\t", nr);
+       if (nr > 0) {
+               int i;
 
-       seq_put_decimal_ull(m, "Pid:\t", pid_nr_ns(pid, ns));
+               /* If nr is non-zero it means that 'pid' is valid and that
+                * ns, i.e. the pid namespace associated with the procfs
+                * instance, is in the pid namespace hierarchy of pid.
+                * Start at one below the already printed level.
+                */
+               for (i = ns->level + 1; i <= pid->level; i++)
+                       seq_put_decimal_ll(m, "\t", pid->numbers[i].nr);
+       }
+#endif
        seq_putc(m, '\n');
 }
 #endif
@@ -2026,7 +2087,8 @@ static __latent_entropy struct task_struct *copy_process(
        stackleak_task_init(p);
 
        if (pid != &init_struct_pid) {
-               pid = alloc_pid(p->nsproxy->pid_ns_for_children);
+               pid = alloc_pid(p->nsproxy->pid_ns_for_children, args->set_tid,
+                               args->set_tid_size);
                if (IS_ERR(pid)) {
                        retval = PTR_ERR(pid);
                        goto bad_fork_cleanup_thread;
@@ -2529,6 +2591,7 @@ noinline static int copy_clone_args_from_user(struct kernel_clone_args *kargs,
 {
        int err;
        struct clone_args args;
+       pid_t *kset_tid = kargs->set_tid;
 
        if (unlikely(usize > PAGE_SIZE))
                return -E2BIG;
@@ -2539,6 +2602,15 @@ noinline static int copy_clone_args_from_user(struct kernel_clone_args *kargs,
        if (err)
                return err;
 
+       if (unlikely(args.set_tid_size > MAX_PID_NS_LEVEL))
+               return -EINVAL;
+
+       if (unlikely(!args.set_tid && args.set_tid_size > 0))
+               return -EINVAL;
+
+       if (unlikely(args.set_tid && args.set_tid_size == 0))
+               return -EINVAL;
+
        /*
         * Verify that higher 32bits of exit_signal are unset and that
         * it is a valid signal
@@ -2556,8 +2628,16 @@ noinline static int copy_clone_args_from_user(struct kernel_clone_args *kargs,
                .stack          = args.stack,
                .stack_size     = args.stack_size,
                .tls            = args.tls,
+               .set_tid_size   = args.set_tid_size,
        };
 
+       if (args.set_tid &&
+               copy_from_user(kset_tid, u64_to_user_ptr(args.set_tid),
+                       (kargs->set_tid_size * sizeof(pid_t))))
+               return -EFAULT;
+
+       kargs->set_tid = kset_tid;
+
        return 0;
 }
 
@@ -2591,11 +2671,8 @@ static inline bool clone3_stack_valid(struct kernel_clone_args *kargs)
 
 static bool clone3_args_valid(struct kernel_clone_args *kargs)
 {
-       /*
-        * All lower bits of the flag word are taken.
-        * Verify that no other unknown flags are passed along.
-        */
-       if (kargs->flags & ~CLONE_LEGACY_FLAGS)
+       /* Verify that no unknown flags are passed along. */
+       if (kargs->flags & ~(CLONE_LEGACY_FLAGS | CLONE_CLEAR_SIGHAND))
                return false;
 
        /*
@@ -2605,6 +2682,10 @@ static bool clone3_args_valid(struct kernel_clone_args *kargs)
        if (kargs->flags & (CLONE_DETACHED | CSIGNAL))
                return false;
 
+       if ((kargs->flags & (CLONE_SIGHAND | CLONE_CLEAR_SIGHAND)) ==
+           (CLONE_SIGHAND | CLONE_CLEAR_SIGHAND))
+               return false;
+
        if ((kargs->flags & (CLONE_THREAD | CLONE_PARENT)) &&
            kargs->exit_signal)
                return false;
@@ -2631,6 +2712,9 @@ SYSCALL_DEFINE2(clone3, struct clone_args __user *, uargs, size_t, size)
        int err;
 
        struct kernel_clone_args kargs;
+       pid_t set_tid[MAX_PID_NS_LEVEL];
+
+       kargs.set_tid = set_tid;
 
        err = copy_clone_args_from_user(&kargs, uargs, size);
        if (err)