Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'exec-update-lock-for-v5.11' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace

Pull exec-update-lock update from Eric Biederman:
"The key point of this is to transform exec_update_mutex into a
rw_semaphore so readers can be separated from writers.

This makes it easier to understand what the holders of the lock are
doing, and makes it harder to contend or deadlock on the lock.

The real deadlock fix wound up in perf_event_open"

* 'exec-update-lock-for-v5.11' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace:
exec: Transform exec_update_mutex into a rw_semaphore

+44 -43
+6 -6
fs/exec.c
··· 966 966 967 967 /* 968 968 * Maps the mm_struct mm into the current task struct. 969 - * On success, this function returns with the mutex 970 - * exec_update_mutex locked. 969 + * On success, this function returns with exec_update_lock 970 + * held for writing. 971 971 */ 972 972 static int exec_mmap(struct mm_struct *mm) 973 973 { ··· 982 982 if (old_mm) 983 983 sync_mm_rss(old_mm); 984 984 985 - ret = mutex_lock_killable(&tsk->signal->exec_update_mutex); 985 + ret = down_write_killable(&tsk->signal->exec_update_lock); 986 986 if (ret) 987 987 return ret; 988 988 ··· 996 996 mmap_read_lock(old_mm); 997 997 if (unlikely(old_mm->core_state)) { 998 998 mmap_read_unlock(old_mm); 999 - mutex_unlock(&tsk->signal->exec_update_mutex); 999 + up_write(&tsk->signal->exec_update_lock); 1000 1000 return -EINTR; 1001 1001 } 1002 1002 } ··· 1395 1395 return 0; 1396 1396 1397 1397 out_unlock: 1398 - mutex_unlock(&me->signal->exec_update_mutex); 1398 + up_write(&me->signal->exec_update_lock); 1399 1399 out: 1400 1400 return retval; 1401 1401 } ··· 1436 1436 * some architectures like powerpc 1437 1437 */ 1438 1438 me->mm->task_size = TASK_SIZE; 1439 - mutex_unlock(&me->signal->exec_update_mutex); 1439 + up_write(&me->signal->exec_update_lock); 1440 1440 mutex_unlock(&me->signal->cred_guard_mutex); 1441 1441 } 1442 1442 EXPORT_SYMBOL(setup_new_exec);
+5 -5
fs/proc/base.c
··· 405 405 406 406 static int lock_trace(struct task_struct *task) 407 407 { 408 - int err = mutex_lock_killable(&task->signal->exec_update_mutex); 408 + int err = down_read_killable(&task->signal->exec_update_lock); 409 409 if (err) 410 410 return err; 411 411 if (!ptrace_may_access(task, PTRACE_MODE_ATTACH_FSCREDS)) { 412 - mutex_unlock(&task->signal->exec_update_mutex); 412 + up_read(&task->signal->exec_update_lock); 413 413 return -EPERM; 414 414 } 415 415 return 0; ··· 417 417 418 418 static void unlock_trace(struct task_struct *task) 419 419 { 420 - mutex_unlock(&task->signal->exec_update_mutex); 420 + up_read(&task->signal->exec_update_lock); 421 421 } 422 422 423 423 #ifdef CONFIG_STACKTRACE ··· 2930 2930 unsigned long flags; 2931 2931 int result; 2932 2932 2933 - result = mutex_lock_killable(&task->signal->exec_update_mutex); 2933 + result = down_read_killable(&task->signal->exec_update_lock); 2934 2934 if (result) 2935 2935 return result; 2936 2936 ··· 2966 2966 result = 0; 2967 2967 2968 2968 out_unlock: 2969 - mutex_unlock(&task->signal->exec_update_mutex); 2969 + up_read(&task->signal->exec_update_lock); 2970 2970 return result; 2971 2971 } 2972 2972
+6 -5
include/linux/sched/signal.h
··· 228 228 * credential calculations 229 229 * (notably. ptrace) 230 230 * Deprecated do not use in new code. 231 - * Use exec_update_mutex instead. 231 + * Use exec_update_lock instead. 232 232 */ 233 - struct mutex exec_update_mutex; /* Held while task_struct is being 234 - * updated during exec, and may have 235 - * inconsistent permissions. 236 - */ 233 + struct rw_semaphore exec_update_lock; /* Held while task_struct is 234 + * being updated during exec, 235 + * and may have inconsistent 236 + * permissions. 237 + */ 237 238 } __randomize_layout; 238 239 239 240 /*
+1 -1
init/init_task.c
··· 26 26 .multiprocess = HLIST_HEAD_INIT, 27 27 .rlim = INIT_RLIMITS, 28 28 .cred_guard_mutex = __MUTEX_INITIALIZER(init_signals.cred_guard_mutex), 29 - .exec_update_mutex = __MUTEX_INITIALIZER(init_signals.exec_update_mutex), 29 + .exec_update_lock = __RWSEM_INITIALIZER(init_signals.exec_update_lock), 30 30 #ifdef CONFIG_POSIX_TIMERS 31 31 .posix_timers = LIST_HEAD_INIT(init_signals.posix_timers), 32 32 .cputimer = {
+6 -6
kernel/events/core.c
··· 1327 1327 * function. 1328 1328 * 1329 1329 * Lock order: 1330 - * exec_update_mutex 1330 + * exec_update_lock 1331 1331 * task_struct::perf_event_mutex 1332 1332 * perf_event_context::mutex 1333 1333 * perf_event::child_mutex; ··· 11959 11959 } 11960 11960 11961 11961 if (task) { 11962 - err = mutex_lock_interruptible(&task->signal->exec_update_mutex); 11962 + err = down_read_interruptible(&task->signal->exec_update_lock); 11963 11963 if (err) 11964 11964 goto err_file; 11965 11965 11966 11966 /* 11967 11967 * Preserve ptrace permission check for backwards compatibility. 11968 11968 * 11969 - * We must hold exec_update_mutex across this and any potential 11969 + * We must hold exec_update_lock across this and any potential 11970 11970 * perf_install_in_context() call for this new event to 11971 11971 * serialize against exec() altering our credentials (and the 11972 11972 * perf_event_exit_task() that could imply). ··· 12129 12129 mutex_unlock(&ctx->mutex); 12130 12130 12131 12131 if (task) { 12132 - mutex_unlock(&task->signal->exec_update_mutex); 12132 + up_read(&task->signal->exec_update_lock); 12133 12133 put_task_struct(task); 12134 12134 } 12135 12135 ··· 12153 12153 mutex_unlock(&ctx->mutex); 12154 12154 err_cred: 12155 12155 if (task) 12156 - mutex_unlock(&task->signal->exec_update_mutex); 12156 + up_read(&task->signal->exec_update_lock); 12157 12157 err_file: 12158 12158 fput(event_file); 12159 12159 err_context: ··· 12470 12470 /* 12471 12471 * When a child task exits, feed back event values to parent events. 12472 12472 * 12473 - * Can be called with exec_update_mutex held when called from 12473 + * Can be called with exec_update_lock held when called from 12474 12474 * setup_new_exec(). 12475 12475 */ 12476 12476 void perf_event_exit_task(struct task_struct *child)
+3 -3
kernel/fork.c
··· 1225 1225 struct mm_struct *mm; 1226 1226 int err; 1227 1227 1228 - err = mutex_lock_killable(&task->signal->exec_update_mutex); 1228 + err = down_read_killable(&task->signal->exec_update_lock); 1229 1229 if (err) 1230 1230 return ERR_PTR(err); 1231 1231 ··· 1235 1235 mmput(mm); 1236 1236 mm = ERR_PTR(-EACCES); 1237 1237 } 1238 - mutex_unlock(&task->signal->exec_update_mutex); 1238 + up_read(&task->signal->exec_update_lock); 1239 1239 1240 1240 return mm; 1241 1241 } ··· 1595 1595 sig->oom_score_adj_min = current->signal->oom_score_adj_min; 1596 1596 1597 1597 mutex_init(&sig->cred_guard_mutex); 1598 - mutex_init(&sig->exec_update_mutex); 1598 + init_rwsem(&sig->exec_update_lock); 1599 1599 1600 1600 return 0; 1601 1601 }
+15 -15
kernel/kcmp.c
··· 70 70 return file; 71 71 } 72 72 73 - static void kcmp_unlock(struct mutex *m1, struct mutex *m2) 73 + static void kcmp_unlock(struct rw_semaphore *l1, struct rw_semaphore *l2) 74 74 { 75 - if (likely(m2 != m1)) 76 - mutex_unlock(m2); 77 - mutex_unlock(m1); 75 + if (likely(l2 != l1)) 76 + up_read(l2); 77 + up_read(l1); 78 78 } 79 79 80 - static int kcmp_lock(struct mutex *m1, struct mutex *m2) 80 + static int kcmp_lock(struct rw_semaphore *l1, struct rw_semaphore *l2) 81 81 { 82 82 int err; 83 83 84 - if (m2 > m1) 85 - swap(m1, m2); 84 + if (l2 > l1) 85 + swap(l1, l2); 86 86 87 - err = mutex_lock_killable(m1); 88 - if (!err && likely(m1 != m2)) { 89 - err = mutex_lock_killable_nested(m2, SINGLE_DEPTH_NESTING); 87 + err = down_read_killable(l1); 88 + if (!err && likely(l1 != l2)) { 89 + err = down_read_killable_nested(l2, SINGLE_DEPTH_NESTING); 90 90 if (err) 91 - mutex_unlock(m1); 91 + up_read(l1); 92 92 } 93 93 94 94 return err; ··· 156 156 /* 157 157 * One should have enough rights to inspect task details. 158 158 */ 159 - ret = kcmp_lock(&task1->signal->exec_update_mutex, 160 - &task2->signal->exec_update_mutex); 159 + ret = kcmp_lock(&task1->signal->exec_update_lock, 160 + &task2->signal->exec_update_lock); 161 161 if (ret) 162 162 goto err; 163 163 if (!ptrace_may_access(task1, PTRACE_MODE_READ_REALCREDS) || ··· 212 212 } 213 213 214 214 err_unlock: 215 - kcmp_unlock(&task1->signal->exec_update_mutex, 216 - &task2->signal->exec_update_mutex); 215 + kcmp_unlock(&task1->signal->exec_update_lock, 216 + &task2->signal->exec_update_lock); 217 217 err: 218 218 put_task_struct(task1); 219 219 put_task_struct(task2);
+2 -2
kernel/pid.c
··· 628 628 struct file *file; 629 629 int ret; 630 630 631 - ret = mutex_lock_killable(&task->signal->exec_update_mutex); 631 + ret = down_read_killable(&task->signal->exec_update_lock); 632 632 if (ret) 633 633 return ERR_PTR(ret); 634 634 ··· 637 637 else 638 638 file = ERR_PTR(-EPERM); 639 639 640 - mutex_unlock(&task->signal->exec_update_mutex); 640 + up_read(&task->signal->exec_update_lock); 641 641 642 642 return file ?: ERR_PTR(-EBADF); 643 643 }