summaryrefslogtreecommitdiffstats
path: root/kernel/pid_namespace.c
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2020-03-02 16:00:33 -0600
committerEric W. Biederman <ebiederm@xmission.com>2020-03-02 16:00:33 -0600
commita0d4a141750df51135499f96c355c4d76add5505 (patch)
treeca1a72db5f1bb4725807c466fc4ef4914201f3db /kernel/pid_namespace.c
parenta13ae6971599dd01a5fa8da9ee1bd5bb3efa01b3 (diff)
parentaf9fe6d607c9f456fb6c1cb87e1dc66a43846efd (diff)
downloadlinux-a0d4a141750df51135499f96c355c4d76add5505.tar.bz2
Proc mount option handling is broken, and it has been since I
accidentally broke it in the middle 2016. The problem is that because we perform an internal mount of proc before user space mounts proc all of the mount options that user specifies when mounting proc are ignored. You can set those mount options with a remount but that is rather surprising. This most directly affects android which is using hidpid=2 by default. Now that the sysctl system call support has been removed, and we have settled on way of flushing proc dentries when a process exits without using proc_mnt, there is an simple and easy fix. a) Give UML mconsole it's own private mount of proc to use. b) Stop creating the internal mount of proc We still need Alexey Gladkov's full patch to get proc mount options to work inside of UML, and to be generally useful. This set of changes is just enough to get them working as well as they have in the past. If anyone sees any problem with this code please let me know. Otherwise I plan to merge these set of fixes through my tree. Link: https://lore.kernel.org/lkml/87r21tuulj.fsf@x220.int.ebiederm.org/ Link: https://lore.kernel.org/lkml/871rqk2brn.fsf_-_@x220.int.ebiederm.org/ Link: https://lore.kernel.org/lkml/20200210150519.538333-1-gladkov.alexey@gmail.com/ Link: https://lore.kernel.org/lkml/20180611195744.154962-1-astrachan@google.com/ Fixes: e94591d0d90c ("proc: Convert proc_mount to use mount_ns.") Eric W. Biederman (4): uml: Don't consult current to find the proc_mnt in mconsole_proc uml: Create a private mount of proc for mconsole proc: Remove the now unnecessary internal mount of proc pid: Improve the comment about waiting in zap_pid_ns_processes arch/um/drivers/mconsole_kern.c | 28 +++++++++++++++++++++++++++- fs/proc/root.c | 36 ------------------------------------ include/linux/pid_namespace.h | 2 -- include/linux/proc_ns.h | 5 ----- kernel/pid.c | 8 -------- kernel/pid_namespace.c | 38 +++++++++++++++++++------------------- 6 files changed, 46 insertions(+), 71 deletions(-)
Diffstat (limited to 'kernel/pid_namespace.c')
-rw-r--r--kernel/pid_namespace.c38
1 files changed, 19 insertions, 19 deletions
diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c
index d40017e79ebe..01f8ba32cc0c 100644
--- a/kernel/pid_namespace.c
+++ b/kernel/pid_namespace.c
@@ -57,12 +57,6 @@ static struct kmem_cache *create_pid_cachep(unsigned int level)
return READ_ONCE(*pkc);
}
-static void proc_cleanup_work(struct work_struct *work)
-{
- struct pid_namespace *ns = container_of(work, struct pid_namespace, proc_work);
- pid_ns_release_proc(ns);
-}
-
static struct ucounts *inc_pid_namespaces(struct user_namespace *ns)
{
return inc_ucount(ns, current_euid(), UCOUNT_PID_NAMESPACES);
@@ -114,7 +108,6 @@ static struct pid_namespace *create_pid_namespace(struct user_namespace *user_ns
ns->user_ns = get_user_ns(user_ns);
ns->ucounts = ucounts;
ns->pid_allocated = PIDNS_ADDING;
- INIT_WORK(&ns->proc_work, proc_cleanup_work);
return ns;
@@ -231,20 +224,27 @@ void zap_pid_ns_processes(struct pid_namespace *pid_ns)
} while (rc != -ECHILD);
/*
- * kernel_wait4() above can't reap the EXIT_DEAD children but we do not
- * really care, we could reparent them to the global init. We could
- * exit and reap ->child_reaper even if it is not the last thread in
- * this pid_ns, free_pid(pid_allocated == 0) calls proc_cleanup_work(),
- * pid_ns can not go away until proc_kill_sb() drops the reference.
+ * kernel_wait4() misses EXIT_DEAD children, and EXIT_ZOMBIE
+ * process whose parents processes are outside of the pid
+ * namespace. Such processes are created with setns()+fork().
+ *
+ * If those EXIT_ZOMBIE processes are not reaped by their
+ * parents before their parents exit, they will be reparented
+ * to pid_ns->child_reaper. Thus pidns->child_reaper needs to
+ * stay valid until they all go away.
+ *
+ * The code relies on the the pid_ns->child_reaper ignoring
+ * SIGCHILD to cause those EXIT_ZOMBIE processes to be
+ * autoreaped if reparented.
*
- * But this ns can also have other tasks injected by setns()+fork().
- * Again, ignoring the user visible semantics we do not really need
- * to wait until they are all reaped, but they can be reparented to
- * us and thus we need to ensure that pid->child_reaper stays valid
- * until they all go away. See free_pid()->wake_up_process().
+ * Semantically it is also desirable to wait for EXIT_ZOMBIE
+ * processes before allowing the child_reaper to be reaped, as
+ * that gives the invariant that when the init process of a
+ * pid namespace is reaped all of the processes in the pid
+ * namespace are gone.
*
- * We rely on ignored SIGCHLD, an injected zombie must be autoreaped
- * if reparented.
+ * Once all of the other tasks are gone from the pid_namespace
+ * free_pid() will awaken this task.
*/
for (;;) {
set_current_state(TASK_INTERRUPTIBLE);