History

Merge branch 'locking-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull futex fix from Ingo Molnar: "A single fix for a robust futexes race between sys_exit() and sys_futex_lock_pi()" * 'locking-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: futex: Cure exit race

Linus Torvalds committed 7 years ago

Commit d5fa0802 parents 70ad636 da791a61 file · +63 −6Browse files

Unified · Split

kernel/futex.c+63−6
@@ -1148,11 +1148,65 @@ out_error: · 1147 unmodified lines
1148 return ret;1148 return ret;
1149}1149}
1150 1150
1151static int handle_exit_race(u32 __user *uaddr, u32 uval,
1152 struct task_struct *tsk)
1153{
1154 u32 uval2;
1155
1156 /*
1157 * If PF_EXITPIDONE is not yet set, then try again.
1158 */
1159 if (tsk && !(tsk->flags & PF_EXITPIDONE))
1160 return -EAGAIN;
1161
1162 /*
1163 * Reread the user space value to handle the following situation:
1164 *
1165 * CPU0 CPU1
1166 *
1167 * sys_exit() sys_futex()
1168 * do_exit() futex_lock_pi()
1169 * futex_lock_pi_atomic()
1170 * exit_signals(tsk) No waiters:
1171 * tsk->flags |= PF_EXITING; *uaddr == 0x00000PID
1172 * mm_release(tsk) Set waiter bit
1173 * exit_robust_list(tsk) { *uaddr = 0x80000PID;
1174 * Set owner died attach_to_pi_owner() {
1175 * *uaddr = 0xC0000000; tsk = get_task(PID);
1176 * } if (!tsk->flags & PF_EXITING) {
1177 * ... attach();
1178 * tsk->flags |= PF_EXITPIDONE; } else {
1179 * if (!(tsk->flags & PF_EXITPIDONE))
1180 * return -EAGAIN;
1181 * return -ESRCH; <--- FAIL
1182 * }
1183 *
1184 * Returning ESRCH unconditionally is wrong here because the
1185 * user space value has been changed by the exiting task.
1186 *
1187 * The same logic applies to the case where the exiting task is
1188 * already gone.
1189 */
1190 if (get_futex_value_locked(&uval2, uaddr))
1191 return -EFAULT;
1192
1193 /* If the user space value has changed, try again. */
1194 if (uval2 != uval)
1195 return -EAGAIN;
1196
1197 /*
1198 * The exiting task did not have a robust list, the robust list was
1199 * corrupted or the user space value in *uaddr is simply bogus.
1200 * Give up and tell user space.
1201 */
1202 return -ESRCH;
1203}
1204
1151/*1205/*
1152 * Lookup the task for the TID provided from user space and attach to1206 * Lookup the task for the TID provided from user space and attach to
1153 * it after doing proper sanity checks.1207 * it after doing proper sanity checks.
1154 */1208 */
1155static int attach_to_pi_owner(u32 uval, union futex_key *key,1209static int attach_to_pi_owner(u32 __user *uaddr, u32 uval, union futex_key *key,
1156 struct futex_pi_state **ps)1210 struct futex_pi_state **ps)
1157{1211{
1158 pid_t pid = uval & FUTEX_TID_MASK;1212 pid_t pid = uval & FUTEX_TID_MASK;
@@ -1162,12 +1216,15 @@ static int attach_to_pi_owner(u32 uval, union futex_key *key, · 3 unmodified lines
1162 /*1216 /*
1163 * We are the first waiter - try to look up the real owner and attach1217 * We are the first waiter - try to look up the real owner and attach
1164 * the new pi_state to it, but bail out when TID = 0 [1]1218 * the new pi_state to it, but bail out when TID = 0 [1]
1219 *
1220 * The !pid check is paranoid. None of the call sites should end up
1221 * with pid == 0, but better safe than sorry. Let the caller retry
1165 */1222 */
1166 if (!pid)1223 if (!pid)
1167 return -ESRCH;1224 return -EAGAIN;
1168 p = find_get_task_by_vpid(pid);1225 p = find_get_task_by_vpid(pid);
1169 if (!p)1226 if (!p)
1170 return -ESRCH;1227 return handle_exit_race(uaddr, uval, NULL);
1171 1228
1172 if (unlikely(p->flags & PF_KTHREAD)) {1229 if (unlikely(p->flags & PF_KTHREAD)) {
1173 put_task_struct(p);1230 put_task_struct(p);
@@ -1187,7 +1244,7 @@ static int attach_to_pi_owner(u32 uval, union futex_key *key, · 13 unmodified lines
1187 * set, we know that the task has finished the1244 * set, we know that the task has finished the
1188 * cleanup:1245 * cleanup:
1189 */1246 */
1190 int ret = (p->flags & PF_EXITPIDONE) ? -ESRCH : -EAGAIN;1247 int ret = handle_exit_race(uaddr, uval, p);
1191 1248
1192 raw_spin_unlock_irq(&p->pi_lock);1249 raw_spin_unlock_irq(&p->pi_lock);
1193 put_task_struct(p);1250 put_task_struct(p);
@@ -1244,7 +1301,7 @@ static int lookup_pi_state(u32 __user *uaddr, u32 uval, · 50 unmodified lines
1244 * We are the first waiter - try to look up the owner based on1301 * We are the first waiter - try to look up the owner based on
1245 * @uval and attach to it.1302 * @uval and attach to it.
1246 */1303 */
1247 return attach_to_pi_owner(uval, key, ps);1304 return attach_to_pi_owner(uaddr, uval, key, ps);
1248}1305}
1249 1306
1250static int lock_pi_update_atomic(u32 __user *uaddr, u32 uval, u32 newval)1307static int lock_pi_update_atomic(u32 __user *uaddr, u32 uval, u32 newval)
@@ -1352,7 +1409,7 @@ static int futex_lock_pi_atomic(u32 __user *uaddr, struct futex_hash_bucket *hb, · 101 unmodified lines
1352 * attach to the owner. If that fails, no harm done, we only1409 * attach to the owner. If that fails, no harm done, we only
1353 * set the FUTEX_WAITERS bit in the user space variable.1410 * set the FUTEX_WAITERS bit in the user space variable.
1354 */1411 */
1355 return attach_to_pi_owner(uval, key, ps);1412 return attach_to_pi_owner(uaddr, newval, key, ps);
1356}1413}
1357 1414
1358/**1415/**