source:
trunk/server/common/patches/cve-2014-3153-0.patch
@
2557
Last change on this file since 2557 was 2557, checked in by achernya, 10 years ago | |
---|---|
File size: 5.6 KB |
-
kernel/futex.c
From cabef9fee397081ec3dfbde2955d4db675a96a4a Mon Sep 17 00:00:00 2001 From: Thomas Gleixner <tglx@linutronix.de> Date: Mon, 12 May 2014 20:45:34 +0000 Subject: [PATCH 1/1] futex: Add another early deadlock detection check commit 866293ee54227584ffcb4a42f69c1f365974ba7f upstream. Dave Jones trinity syscall fuzzer exposed an issue in the deadlock detection code of rtmutex: http://lkml.kernel.org/r/20140429151655.GA14277@redhat.com That underlying issue has been fixed with a patch to the rtmutex code, but the futex code must not call into rtmutex in that case because - it can detect that issue early - it avoids a different and more complex fixup for backing out If the user space variable got manipulated to 0x80000000 which means no lock holder, but the waiters bit set and an active pi_state in the kernel is found we can figure out the recursive locking issue by looking at the pi_state owner. If that is the current task, then we can safely return -EDEADLK. The check should have been added in commit 59fa62451 (futex: Handle futex_pi OWNER_DIED take over correctly) already, but I did not see the above issue caused by user space manipulation back then. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Cc: Dave Jones <davej@redhat.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Darren Hart <darren@dvhart.com> Cc: Davidlohr Bueso <davidlohr@hp.com> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Clark Williams <williams@redhat.com> Cc: Paul McKenney <paulmck@linux.vnet.ibm.com> Cc: Lai Jiangshan <laijs@cn.fujitsu.com> Cc: Roland McGrath <roland@hack.frob.com> Cc: Carlos ODonell <carlos@redhat.com> Cc: Jakub Jelinek <jakub@redhat.com> Cc: Michael Kerrisk <mtk.manpages@gmail.com> Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Link: http://lkml.kernel.org/r/20140512201701.097349971@linutronix.de Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- kernel/futex.c | 47 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/kernel/futex.c b/kernel/futex.c index 3bc18bf..66af37d 100644
a b void exit_pi_state_list(struct task_struct *curr) 594 594 595 595 static int 596 596 lookup_pi_state(u32 uval, struct futex_hash_bucket *hb, 597 union futex_key *key, struct futex_pi_state **ps) 597 union futex_key *key, struct futex_pi_state **ps, 598 struct task_struct *task) 598 599 { 599 600 struct futex_pi_state *pi_state = NULL; 600 601 struct futex_q *this, *next; … … lookup_pi_state(u32 uval, struct futex_hash_bucket *hb, 638 639 return -EINVAL; 639 640 } 640 641 642 /* 643 * Protect against a corrupted uval. If uval 644 * is 0x80000000 then pid is 0 and the waiter 645 * bit is set. So the deadlock check in the 646 * calling code has failed and we did not fall 647 * into the check above due to !pid. 648 */ 649 if (task && pi_state->owner == task) 650 return -EDEADLK; 651 641 652 atomic_inc(&pi_state->refcount); 642 653 *ps = pi_state; 643 654 … … retry: 787 798 * We dont have the lock. Look up the PI state (or create it if 788 799 * we are the first waiter): 789 800 */ 790 ret = lookup_pi_state(uval, hb, key, ps );801 ret = lookup_pi_state(uval, hb, key, ps, task); 791 802 792 803 if (unlikely(ret)) { 793 804 switch (ret) { … … void requeue_pi_wake_futex(struct futex_q *q, union futex_key *key, 1197 1208 * 1198 1209 * Return: 1199 1210 * 0 - failed to acquire the lock atomically; 1200 * 1 - acquired the lock;1211 * >0 - acquired the lock, return value is vpid of the top_waiter 1201 1212 * <0 - error 1202 1213 */ 1203 1214 static int futex_proxy_trylock_atomic(u32 __user *pifutex, … … static int futex_proxy_trylock_atomic(u32 __user *pifutex, 1208 1219 { 1209 1220 struct futex_q *top_waiter = NULL; 1210 1221 u32 curval; 1211 int ret ;1222 int ret, vpid; 1212 1223 1213 1224 if (get_futex_value_locked(&curval, pifutex)) 1214 1225 return -EFAULT; … … static int futex_proxy_trylock_atomic(u32 __user *pifutex, 1236 1247 * the contended case or if set_waiters is 1. The pi_state is returned 1237 1248 * in ps in contended cases. 1238 1249 */ 1250 vpid = task_pid_vnr(top_waiter->task); 1239 1251 ret = futex_lock_pi_atomic(pifutex, hb2, key2, ps, top_waiter->task, 1240 1252 set_waiters); 1241 if (ret == 1) 1253 if (ret == 1) { 1242 1254 requeue_pi_wake_futex(top_waiter, key2, hb2); 1243 1255 return vpid; 1256 } 1244 1257 return ret; 1245 1258 } 1246 1259 … … static int futex_requeue(u32 __user *uaddr1, unsigned int flags, 1272 1285 struct futex_hash_bucket *hb1, *hb2; 1273 1286 struct plist_head *head1; 1274 1287 struct futex_q *this, *next; 1275 u32 curval2;1276 1288 1277 1289 if (requeue_pi) { 1278 1290 /* … … retry_private: 1358 1370 * At this point the top_waiter has either taken uaddr2 or is 1359 1371 * waiting on it. If the former, then the pi_state will not 1360 1372 * exist yet, look it up one more time to ensure we have a 1361 * reference to it. 1373 * reference to it. If the lock was taken, ret contains the 1374 * vpid of the top waiter task. 1362 1375 */ 1363 if (ret == 1) {1376 if (ret > 0) { 1364 1377 WARN_ON(pi_state); 1365 1378 drop_count++; 1366 1379 task_count++; 1367 ret = get_futex_value_locked(&curval2, uaddr2); 1368 if (!ret) 1369 ret = lookup_pi_state(curval2, hb2, &key2, 1370 &pi_state); 1380 /* 1381 * If we acquired the lock, then the user 1382 * space value of uaddr2 should be vpid. It 1383 * cannot be changed by the top waiter as it 1384 * is blocked on hb2 lock if it tries to do 1385 * so. If something fiddled with it behind our 1386 * back the pi state lookup might unearth 1387 * it. So we rather use the known value than 1388 * rereading and handing potential crap to 1389 * lookup_pi_state. 1390 */ 1391 ret = lookup_pi_state(ret, hb2, &key2, &pi_state, NULL); 1371 1392 } 1372 1393 1373 1394 switch (ret) {
Note: See TracBrowser
for help on using the repository browser.