aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@redhat.com>2013-04-30 18:28:20 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-04-30 20:04:07 -0400
commite56fb2874015370e3b7f8d85051f6dce26051df9 (patch)
tree0820c06eb4a25daf65734412af139e98ac1649c8 /include/linux
parent12eaaf309a798973d215f7f21aa5a67a760ed7c8 (diff)
exec: do not abuse ->cred_guard_mutex in threadgroup_lock()
threadgroup_lock() takes signal->cred_guard_mutex to ensure that thread_group_leader() is stable. This doesn't look nice, the scope of this lock in do_execve() is huge. And as Dave pointed out this can lead to deadlock, we have the following dependencies: do_execve: cred_guard_mutex -> i_mutex cgroup_mount: i_mutex -> cgroup_mutex attach_task_by_pid: cgroup_mutex -> cred_guard_mutex Change de_thread() to take threadgroup_change_begin() around the switch-the-leader code and change threadgroup_lock() to avoid ->cred_guard_mutex. Note that de_thread() can't sleep with ->group_rwsem held, this can obviously deadlock with the exiting leader if the writer is active, so it does threadgroup_change_end() before schedule(). Reported-by: Dave Jones <davej@redhat.com> Acked-by: Tejun Heo <tj@kernel.org> Acked-by: Li Zefan <lizefan@huawei.com> Signed-off-by: Oleg Nesterov <oleg@redhat.com> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'include/linux')
-rw-r--r--include/linux/sched.h18
1 files changed, 4 insertions, 14 deletions
diff --git a/include/linux/sched.h b/include/linux/sched.h
index a22baf83c20c..6f950048b6e9 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -2249,27 +2249,18 @@ static inline void threadgroup_change_end(struct task_struct *tsk)
2249 * 2249 *
2250 * Lock the threadgroup @tsk belongs to. No new task is allowed to enter 2250 * Lock the threadgroup @tsk belongs to. No new task is allowed to enter
2251 * and member tasks aren't allowed to exit (as indicated by PF_EXITING) or 2251 * and member tasks aren't allowed to exit (as indicated by PF_EXITING) or
2252 * perform exec. This is useful for cases where the threadgroup needs to 2252 * change ->group_leader/pid. This is useful for cases where the threadgroup
2253 * stay stable across blockable operations. 2253 * needs to stay stable across blockable operations.
2254 * 2254 *
2255 * fork and exit paths explicitly call threadgroup_change_{begin|end}() for 2255 * fork and exit paths explicitly call threadgroup_change_{begin|end}() for
2256 * synchronization. While held, no new task will be added to threadgroup 2256 * synchronization. While held, no new task will be added to threadgroup
2257 * and no existing live task will have its PF_EXITING set. 2257 * and no existing live task will have its PF_EXITING set.
2258 * 2258 *
2259 * During exec, a task goes and puts its thread group through unusual 2259 * de_thread() does threadgroup_change_{begin|end}() when a non-leader
2260 * changes. After de-threading, exclusive access is assumed to resources 2260 * sub-thread becomes a new leader.
2261 * which are usually shared by tasks in the same group - e.g. sighand may
2262 * be replaced with a new one. Also, the exec'ing task takes over group
2263 * leader role including its pid. Exclude these changes while locked by
2264 * grabbing cred_guard_mutex which is used to synchronize exec path.
2265 */ 2261 */
2266static inline void threadgroup_lock(struct task_struct *tsk) 2262static inline void threadgroup_lock(struct task_struct *tsk)
2267{ 2263{
2268 /*
2269 * exec uses exit for de-threading nesting group_rwsem inside
2270 * cred_guard_mutex. Grab cred_guard_mutex first.
2271 */
2272 mutex_lock(&tsk->signal->cred_guard_mutex);
2273 down_write(&tsk->signal->group_rwsem); 2264 down_write(&tsk->signal->group_rwsem);
2274} 2265}
2275 2266
@@ -2282,7 +2273,6 @@ static inline void threadgroup_lock(struct task_struct *tsk)
2282static inline void threadgroup_unlock(struct task_struct *tsk) 2273static inline void threadgroup_unlock(struct task_struct *tsk)
2283{ 2274{
2284 up_write(&tsk->signal->group_rwsem); 2275 up_write(&tsk->signal->group_rwsem);
2285 mutex_unlock(&tsk->signal->cred_guard_mutex);
2286} 2276}
2287#else 2277#else
2288static inline void threadgroup_change_begin(struct task_struct *tsk) {} 2278static inline void threadgroup_change_begin(struct task_struct *tsk) {}