]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blobdiff - kernel/fork.c
signal: In get_signal test for signal_group_exit every time through the loop
[mirror_ubuntu-jammy-kernel.git] / kernel / fork.c
index 38681ad44c76bc71ce3795ff052f7eb218769643..05c8c4df847c2fff25426c835ee87747449a883e 100644 (file)
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/task.h>
+#ifdef CONFIG_USER_NS
+extern int unprivileged_userns_clone;
+#else
+#define unprivileged_userns_clone 0
+#endif
 
 /*
  * Minimum number of threads to boot the kernel
@@ -573,7 +578,7 @@ static __latent_entropy int dup_mmap(struct mm_struct *mm,
                if (file) {
                        struct address_space *mapping = file->f_mapping;
 
-                       get_file(file);
+                       vma_get_file(tmp);
                        i_mmap_lock_write(mapping);
                        if (tmp->vm_flags & VM_SHARED)
                                mapping_allow_writable(mapping);
@@ -1153,6 +1158,7 @@ void mmput_async(struct mm_struct *mm)
                schedule_work(&mm->async_put_work);
        }
 }
+EXPORT_SYMBOL(mmput_async);
 #endif
 
 /**
@@ -1950,6 +1956,10 @@ static __latent_entropy struct task_struct *copy_process(
        if ((clone_flags & (CLONE_NEWUSER|CLONE_FS)) == (CLONE_NEWUSER|CLONE_FS))
                return ERR_PTR(-EINVAL);
 
+       if ((clone_flags & CLONE_NEWUSER) && !unprivileged_userns_clone)
+               if (!capable(CAP_SYS_ADMIN))
+                       return ERR_PTR(-EPERM);
+
        /*
         * Thread groups must share signals as well, and detached threads
         * can only be started up within the thread group.
@@ -2055,18 +2065,18 @@ static __latent_entropy struct task_struct *copy_process(
 #ifdef CONFIG_PROVE_LOCKING
        DEBUG_LOCKS_WARN_ON(!p->softirqs_enabled);
 #endif
+       retval = copy_creds(p, clone_flags);
+       if (retval < 0)
+               goto bad_fork_free;
+
        retval = -EAGAIN;
        if (is_ucounts_overlimit(task_ucounts(p), UCOUNT_RLIMIT_NPROC, rlimit(RLIMIT_NPROC))) {
                if (p->real_cred->user != INIT_USER &&
                    !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN))
-                       goto bad_fork_free;
+                       goto bad_fork_cleanup_count;
        }
        current->flags &= ~PF_NPROC_EXCEEDED;
 
-       retval = copy_creds(p, clone_flags);
-       if (retval < 0)
-               goto bad_fork_free;
-
        /*
         * If multiple threads are within copy_process(), then this check
         * triggers too late. This doesn't hurt, the check is only there
@@ -2280,6 +2290,7 @@ static __latent_entropy struct task_struct *copy_process(
        p->pdeath_signal = 0;
        INIT_LIST_HEAD(&p->thread_group);
        p->task_works = NULL;
+       clear_posix_cputimers_work(p);
 
 #ifdef CONFIG_KRETPROBES
        p->kretprobe_instances.first = NULL;
@@ -2352,10 +2363,6 @@ static __latent_entropy struct task_struct *copy_process(
                goto bad_fork_cancel_cgroup;
        }
 
-       /* past the last point of failure */
-       if (pidfile)
-               fd_install(pidfd, pidfile);
-
        init_task_pid_links(p);
        if (likely(p->pid)) {
                ptrace_init_task(p, (clone_flags & CLONE_PTRACE) || trace);
@@ -2404,8 +2411,11 @@ static __latent_entropy struct task_struct *copy_process(
        syscall_tracepoint_update(p);
        write_unlock_irq(&tasklist_lock);
 
+       if (pidfile)
+               fd_install(pidfd, pidfile);
+
        proc_fork_connector(p);
-       sched_post_fork(p);
+       sched_post_fork(p, args);
        cgroup_post_fork(p, args);
        perf_event_fork(p);
 
@@ -3055,6 +3065,12 @@ int ksys_unshare(unsigned long unshare_flags)
        if (unshare_flags & CLONE_NEWNS)
                unshare_flags |= CLONE_FS;
 
+       if ((unshare_flags & CLONE_NEWUSER) && !unprivileged_userns_clone) {
+               err = -EPERM;
+               if (!capable(CAP_SYS_ADMIN))
+                       goto bad_unshare_out;
+       }
+
        err = check_unshare_flags(unshare_flags);
        if (err)
                goto bad_unshare_out;