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

Configure Feed

Select the types of activity you want to include in your feed.

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

+63 -6
+63 -6
kernel/futex.c
··· 1148 1148 return ret; 1149 1149 } 1150 1150 1151 + static 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 1206 * Lookup the task for the TID provided from user space and attach to 1153 1207 * it after doing proper sanity checks. 1154 1208 */ 1155 - static int attach_to_pi_owner(u32 uval, union futex_key *key, 1209 + static int attach_to_pi_owner(u32 __user *uaddr, u32 uval, union futex_key *key, 1156 1210 struct futex_pi_state **ps) 1157 1211 { 1158 1212 pid_t pid = uval & FUTEX_TID_MASK; ··· 1216 1162 /* 1217 1163 * We are the first waiter - try to look up the real owner and attach 1218 1164 * the new pi_state to it, but bail out when TID = 0 [1] 1165 + * 1166 + * The !pid check is paranoid. None of the call sites should end up 1167 + * with pid == 0, but better safe than sorry. Let the caller retry 1219 1168 */ 1220 1169 if (!pid) 1221 - return -ESRCH; 1170 + return -EAGAIN; 1222 1171 p = find_get_task_by_vpid(pid); 1223 1172 if (!p) 1224 - return -ESRCH; 1173 + return handle_exit_race(uaddr, uval, NULL); 1225 1174 1226 1175 if (unlikely(p->flags & PF_KTHREAD)) { 1227 1176 put_task_struct(p); ··· 1244 1187 * set, we know that the task has finished the 1245 1188 * cleanup: 1246 1189 */ 1247 - int ret = (p->flags & PF_EXITPIDONE) ? -ESRCH : -EAGAIN; 1190 + int ret = handle_exit_race(uaddr, uval, p); 1248 1191 1249 1192 raw_spin_unlock_irq(&p->pi_lock); 1250 1193 put_task_struct(p); ··· 1301 1244 * We are the first waiter - try to look up the owner based on 1302 1245 * @uval and attach to it. 1303 1246 */ 1304 - return attach_to_pi_owner(uval, key, ps); 1247 + return attach_to_pi_owner(uaddr, uval, key, ps); 1305 1248 } 1306 1249 1307 1250 static int lock_pi_update_atomic(u32 __user *uaddr, u32 uval, u32 newval) ··· 1409 1352 * attach to the owner. If that fails, no harm done, we only 1410 1353 * set the FUTEX_WAITERS bit in the user space variable. 1411 1354 */ 1412 - return attach_to_pi_owner(uval, key, ps); 1355 + return attach_to_pi_owner(uaddr, newval, key, ps); 1413 1356 } 1414 1357 1415 1358 /**