diff options
Diffstat (limited to 'kernel/pid_namespace.c')
-rw-r--r-- | kernel/pid_namespace.c | 41 |
1 files changed, 21 insertions, 20 deletions
diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c index fab8ea86fac3..86b3796b0436 100644 --- a/kernel/pid_namespace.c +++ b/kernel/pid_namespace.c | |||
@@ -67,9 +67,10 @@ err_alloc: | |||
67 | return NULL; | 67 | return NULL; |
68 | } | 68 | } |
69 | 69 | ||
70 | static struct pid_namespace *create_pid_namespace(unsigned int level) | 70 | static struct pid_namespace *create_pid_namespace(struct pid_namespace *parent_pid_ns) |
71 | { | 71 | { |
72 | struct pid_namespace *ns; | 72 | struct pid_namespace *ns; |
73 | unsigned int level = parent_pid_ns->level + 1; | ||
73 | int i; | 74 | int i; |
74 | 75 | ||
75 | ns = kmem_cache_zalloc(pid_ns_cachep, GFP_KERNEL); | 76 | ns = kmem_cache_zalloc(pid_ns_cachep, GFP_KERNEL); |
@@ -86,6 +87,7 @@ static struct pid_namespace *create_pid_namespace(unsigned int level) | |||
86 | 87 | ||
87 | kref_init(&ns->kref); | 88 | kref_init(&ns->kref); |
88 | ns->level = level; | 89 | ns->level = level; |
90 | ns->parent = get_pid_ns(parent_pid_ns); | ||
89 | 91 | ||
90 | set_bit(0, ns->pidmap[0].page); | 92 | set_bit(0, ns->pidmap[0].page); |
91 | atomic_set(&ns->pidmap[0].nr_free, BITS_PER_PAGE - 1); | 93 | atomic_set(&ns->pidmap[0].nr_free, BITS_PER_PAGE - 1); |
@@ -114,25 +116,11 @@ static void destroy_pid_namespace(struct pid_namespace *ns) | |||
114 | 116 | ||
115 | struct pid_namespace *copy_pid_ns(unsigned long flags, struct pid_namespace *old_ns) | 117 | struct pid_namespace *copy_pid_ns(unsigned long flags, struct pid_namespace *old_ns) |
116 | { | 118 | { |
117 | struct pid_namespace *new_ns; | ||
118 | |||
119 | BUG_ON(!old_ns); | ||
120 | new_ns = get_pid_ns(old_ns); | ||
121 | if (!(flags & CLONE_NEWPID)) | 119 | if (!(flags & CLONE_NEWPID)) |
122 | goto out; | 120 | return get_pid_ns(old_ns); |
123 | 121 | if (flags & (CLONE_THREAD|CLONE_PARENT)) | |
124 | new_ns = ERR_PTR(-EINVAL); | 122 | return ERR_PTR(-EINVAL); |
125 | if (flags & CLONE_THREAD) | 123 | return create_pid_namespace(old_ns); |
126 | goto out_put; | ||
127 | |||
128 | new_ns = create_pid_namespace(old_ns->level + 1); | ||
129 | if (!IS_ERR(new_ns)) | ||
130 | new_ns->parent = get_pid_ns(old_ns); | ||
131 | |||
132 | out_put: | ||
133 | put_pid_ns(old_ns); | ||
134 | out: | ||
135 | return new_ns; | ||
136 | } | 124 | } |
137 | 125 | ||
138 | void free_pid_ns(struct kref *kref) | 126 | void free_pid_ns(struct kref *kref) |
@@ -152,6 +140,7 @@ void zap_pid_ns_processes(struct pid_namespace *pid_ns) | |||
152 | { | 140 | { |
153 | int nr; | 141 | int nr; |
154 | int rc; | 142 | int rc; |
143 | struct task_struct *task; | ||
155 | 144 | ||
156 | /* | 145 | /* |
157 | * The last thread in the cgroup-init thread group is terminating. | 146 | * The last thread in the cgroup-init thread group is terminating. |
@@ -169,7 +158,19 @@ void zap_pid_ns_processes(struct pid_namespace *pid_ns) | |||
169 | read_lock(&tasklist_lock); | 158 | read_lock(&tasklist_lock); |
170 | nr = next_pidmap(pid_ns, 1); | 159 | nr = next_pidmap(pid_ns, 1); |
171 | while (nr > 0) { | 160 | while (nr > 0) { |
172 | kill_proc_info(SIGKILL, SEND_SIG_PRIV, nr); | 161 | rcu_read_lock(); |
162 | |||
163 | /* | ||
164 | * Use force_sig() since it clears SIGNAL_UNKILLABLE ensuring | ||
165 | * any nested-container's init processes don't ignore the | ||
166 | * signal | ||
167 | */ | ||
168 | task = pid_task(find_vpid(nr), PIDTYPE_PID); | ||
169 | if (task) | ||
170 | force_sig(SIGKILL, task); | ||
171 | |||
172 | rcu_read_unlock(); | ||
173 | |||
173 | nr = next_pidmap(pid_ns, nr); | 174 | nr = next_pidmap(pid_ns, nr); |
174 | } | 175 | } |
175 | read_unlock(&tasklist_lock); | 176 | read_unlock(&tasklist_lock); |