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

oom: fix locking for oom_adj and oom_score_adj

The locking order in oom_adjust_write() and oom_score_adj_write() for
task->alloc_lock and task->sighand->siglock is reversed, and lockdep
notices that irqs could encounter an ABBA scenario.

This fixes the locking order so that we always take task_lock(task) prior
to lock_task_sighand(task).

Signed-off-by: David Rientjes <rientjes@google.com>
Reported-by: Andrew Morton <akpm@linux-foundation.org>
Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Rik van Riel <riel@redhat.com>
Cc: Ying Han <yinghan@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

David Rientjes and committed by
Linus Torvalds
d19d5476 723548bf

+26 -24
+26 -24
fs/proc/base.c
··· 1042 1042 err = -ESRCH; 1043 1043 goto out; 1044 1044 } 1045 - if (!lock_task_sighand(task, &flags)) { 1046 - err = -ESRCH; 1047 - goto err_task_struct; 1048 - } 1049 - 1050 - if (oom_adjust < task->signal->oom_adj && !capable(CAP_SYS_RESOURCE)) { 1051 - err = -EACCES; 1052 - goto err_sighand; 1053 - } 1054 1045 1055 1046 task_lock(task); 1056 1047 if (!task->mm) { 1057 1048 err = -EINVAL; 1058 1049 goto err_task_lock; 1050 + } 1051 + 1052 + if (!lock_task_sighand(task, &flags)) { 1053 + err = -ESRCH; 1054 + goto err_task_lock; 1055 + } 1056 + 1057 + if (oom_adjust < task->signal->oom_adj && !capable(CAP_SYS_RESOURCE)) { 1058 + err = -EACCES; 1059 + goto err_sighand; 1059 1060 } 1060 1061 1061 1062 if (oom_adjust != task->signal->oom_adj) { ··· 1084 1083 else 1085 1084 task->signal->oom_score_adj = (oom_adjust * OOM_SCORE_ADJ_MAX) / 1086 1085 -OOM_DISABLE; 1087 - err_task_lock: 1088 - task_unlock(task); 1089 1086 err_sighand: 1090 1087 unlock_task_sighand(task, &flags); 1091 - err_task_struct: 1088 + err_task_lock: 1089 + task_unlock(task); 1092 1090 put_task_struct(task); 1093 1091 out: 1094 1092 return err < 0 ? err : count; ··· 1150 1150 err = -ESRCH; 1151 1151 goto out; 1152 1152 } 1153 - if (!lock_task_sighand(task, &flags)) { 1154 - err = -ESRCH; 1155 - goto err_task_struct; 1156 - } 1157 - if (oom_score_adj < task->signal->oom_score_adj && 1158 - !capable(CAP_SYS_RESOURCE)) { 1159 - err = -EACCES; 1160 - goto err_sighand; 1161 - } 1162 1153 1163 1154 task_lock(task); 1164 1155 if (!task->mm) { 1165 1156 err = -EINVAL; 1166 1157 goto err_task_lock; 1167 1158 } 1159 + 1160 + if (!lock_task_sighand(task, &flags)) { 1161 + err = -ESRCH; 1162 + goto err_task_lock; 1163 + } 1164 + 1165 + if (oom_score_adj < task->signal->oom_score_adj && 1166 + !capable(CAP_SYS_RESOURCE)) { 1167 + err = -EACCES; 1168 + goto err_sighand; 1169 + } 1170 + 1168 1171 if (oom_score_adj != task->signal->oom_score_adj) { 1169 1172 if (oom_score_adj == OOM_SCORE_ADJ_MIN) 1170 1173 atomic_inc(&task->mm->oom_disable_count); ··· 1184 1181 else 1185 1182 task->signal->oom_adj = (oom_score_adj * OOM_ADJUST_MAX) / 1186 1183 OOM_SCORE_ADJ_MAX; 1187 - err_task_lock: 1188 - task_unlock(task); 1189 1184 err_sighand: 1190 1185 unlock_task_sighand(task, &flags); 1191 - err_task_struct: 1186 + err_task_lock: 1187 + task_unlock(task); 1192 1188 put_task_struct(task); 1193 1189 out: 1194 1190 return err < 0 ? err : count;