aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/futex.c
diff options
context:
space:
mode:
authorDavidlohr Bueso <dave@stgolabs.net>2015-06-30 02:26:02 -0400
committerThomas Gleixner <tglx@linutronix.de>2015-07-20 05:45:45 -0400
commitab51fbab39d864f3223e44a2600fd951df261f0b (patch)
treecd8106193d0d15b9690a8e80ceec85d202f8e1cb /kernel/futex.c
parent767f509ca11269c2bcd92e3972a93096f2173ac0 (diff)
futex: Fault/error injection capabilities
Although futexes are well known for being a royal pita, we really have very little debugging capabilities - except for relying on tglx's eye half the time. By simply making use of the existing fault-injection machinery, we can improve this situation, allowing generating artificial uaddress faults and deadlock scenarios. Of course, when this is disabled in production systems, the overhead for failure checks is practically zero -- so this is very cheap at the same time. Future work would be nice to now enhance trinity to make use of this. There is a special tunable 'ignore-private', which can filter out private futexes. Given the tsk->make_it_fail filter and this option, pi futexes can be narrowed down pretty closely. Signed-off-by: Davidlohr Bueso <dbueso@suse.de> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Darren Hart <darren@dvhart.com> Cc: Davidlohr Bueso <dave@stgolabs.net> Link: http://lkml.kernel.org/r/1435645562-975-3-git-send-email-dave@stgolabs.net Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel/futex.c')
-rw-r--r--kernel/futex.c89
1 files changed, 87 insertions, 2 deletions
diff --git a/kernel/futex.c b/kernel/futex.c
index 153eb22b0fc0..6ea31bb703c9 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -64,6 +64,7 @@
64#include <linux/hugetlb.h> 64#include <linux/hugetlb.h>
65#include <linux/freezer.h> 65#include <linux/freezer.h>
66#include <linux/bootmem.h> 66#include <linux/bootmem.h>
67#include <linux/fault-inject.h>
67 68
68#include <asm/futex.h> 69#include <asm/futex.h>
69 70
@@ -258,6 +259,66 @@ static unsigned long __read_mostly futex_hashsize;
258 259
259static struct futex_hash_bucket *futex_queues; 260static struct futex_hash_bucket *futex_queues;
260 261
262/*
263 * Fault injections for futexes.
264 */
265#ifdef CONFIG_FAIL_FUTEX
266
267static struct {
268 struct fault_attr attr;
269
270 u32 ignore_private;
271} fail_futex = {
272 .attr = FAULT_ATTR_INITIALIZER,
273 .ignore_private = 0,
274};
275
276static int __init setup_fail_futex(char *str)
277{
278 return setup_fault_attr(&fail_futex.attr, str);
279}
280__setup("fail_futex=", setup_fail_futex);
281
282bool should_fail_futex(bool fshared)
283{
284 if (fail_futex.ignore_private && !fshared)
285 return false;
286
287 return should_fail(&fail_futex.attr, 1);
288}
289
290#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
291
292static int __init fail_futex_debugfs(void)
293{
294 umode_t mode = S_IFREG | S_IRUSR | S_IWUSR;
295 struct dentry *dir;
296
297 dir = fault_create_debugfs_attr("fail_futex", NULL,
298 &fail_futex.attr);
299 if (IS_ERR(dir))
300 return PTR_ERR(dir);
301
302 if (!debugfs_create_bool("ignore-private", mode, dir,
303 &fail_futex.ignore_private)) {
304 debugfs_remove_recursive(dir);
305 return -ENOMEM;
306 }
307
308 return 0;
309}
310
311late_initcall(fail_futex_debugfs);
312
313#endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */
314
315#else
316static inline bool should_fail_futex(bool fshared)
317{
318 return false;
319}
320#endif /* CONFIG_FAIL_FUTEX */
321
261static inline void futex_get_mm(union futex_key *key) 322static inline void futex_get_mm(union futex_key *key)
262{ 323{
263 atomic_inc(&key->private.mm->mm_count); 324 atomic_inc(&key->private.mm->mm_count);
@@ -413,6 +474,9 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, int rw)
413 if (unlikely(!access_ok(rw, uaddr, sizeof(u32)))) 474 if (unlikely(!access_ok(rw, uaddr, sizeof(u32))))
414 return -EFAULT; 475 return -EFAULT;
415 476
477 if (unlikely(should_fail_futex(fshared)))
478 return -EFAULT;
479
416 /* 480 /*
417 * PROCESS_PRIVATE futexes are fast. 481 * PROCESS_PRIVATE futexes are fast.
418 * As the mm cannot disappear under us and the 'key' only needs 482 * As the mm cannot disappear under us and the 'key' only needs
@@ -428,6 +492,10 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, int rw)
428 } 492 }
429 493
430again: 494again:
495 /* Ignore any VERIFY_READ mapping (futex common case) */
496 if (unlikely(should_fail_futex(fshared)))
497 return -EFAULT;
498
431 err = get_user_pages_fast(address, 1, 1, &page); 499 err = get_user_pages_fast(address, 1, 1, &page);
432 /* 500 /*
433 * If write access is not required (eg. FUTEX_WAIT), try 501 * If write access is not required (eg. FUTEX_WAIT), try
@@ -516,7 +584,7 @@ again:
516 * A RO anonymous page will never change and thus doesn't make 584 * A RO anonymous page will never change and thus doesn't make
517 * sense for futex operations. 585 * sense for futex operations.
518 */ 586 */
519 if (ro) { 587 if (unlikely(should_fail_futex(fshared)) || ro) {
520 err = -EFAULT; 588 err = -EFAULT;
521 goto out; 589 goto out;
522 } 590 }
@@ -974,6 +1042,9 @@ static int lock_pi_update_atomic(u32 __user *uaddr, u32 uval, u32 newval)
974{ 1042{
975 u32 uninitialized_var(curval); 1043 u32 uninitialized_var(curval);
976 1044
1045 if (unlikely(should_fail_futex(true)))
1046 return -EFAULT;
1047
977 if (unlikely(cmpxchg_futex_value_locked(&curval, uaddr, uval, newval))) 1048 if (unlikely(cmpxchg_futex_value_locked(&curval, uaddr, uval, newval)))
978 return -EFAULT; 1049 return -EFAULT;
979 1050
@@ -1015,12 +1086,18 @@ static int futex_lock_pi_atomic(u32 __user *uaddr, struct futex_hash_bucket *hb,
1015 if (get_futex_value_locked(&uval, uaddr)) 1086 if (get_futex_value_locked(&uval, uaddr))
1016 return -EFAULT; 1087 return -EFAULT;
1017 1088
1089 if (unlikely(should_fail_futex(true)))
1090 return -EFAULT;
1091
1018 /* 1092 /*
1019 * Detect deadlocks. 1093 * Detect deadlocks.
1020 */ 1094 */
1021 if ((unlikely((uval & FUTEX_TID_MASK) == vpid))) 1095 if ((unlikely((uval & FUTEX_TID_MASK) == vpid)))
1022 return -EDEADLK; 1096 return -EDEADLK;
1023 1097
1098 if ((unlikely(should_fail_futex(true))))
1099 return -EDEADLK;
1100
1024 /* 1101 /*
1025 * Lookup existing state first. If it exists, try to attach to 1102 * Lookup existing state first. If it exists, try to attach to
1026 * its pi_state. 1103 * its pi_state.
@@ -1155,6 +1232,9 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this,
1155 */ 1232 */
1156 newval = FUTEX_WAITERS | task_pid_vnr(new_owner); 1233 newval = FUTEX_WAITERS | task_pid_vnr(new_owner);
1157 1234
1235 if (unlikely(should_fail_futex(true)))
1236 ret = -EFAULT;
1237
1158 if (cmpxchg_futex_value_locked(&curval, uaddr, uval, newval)) 1238 if (cmpxchg_futex_value_locked(&curval, uaddr, uval, newval))
1159 ret = -EFAULT; 1239 ret = -EFAULT;
1160 else if (curval != uval) 1240 else if (curval != uval)
@@ -1457,6 +1537,9 @@ static int futex_proxy_trylock_atomic(u32 __user *pifutex,
1457 if (get_futex_value_locked(&curval, pifutex)) 1537 if (get_futex_value_locked(&curval, pifutex))
1458 return -EFAULT; 1538 return -EFAULT;
1459 1539
1540 if (unlikely(should_fail_futex(true)))
1541 return -EFAULT;
1542
1460 /* 1543 /*
1461 * Find the top_waiter and determine if there are additional waiters. 1544 * Find the top_waiter and determine if there are additional waiters.
1462 * If the caller intends to requeue more than 1 waiter to pifutex, 1545 * If the caller intends to requeue more than 1 waiter to pifutex,
@@ -2537,7 +2620,7 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb,
2537 * futex_wait_requeue_pi() - Wait on uaddr and take uaddr2 2620 * futex_wait_requeue_pi() - Wait on uaddr and take uaddr2
2538 * @uaddr: the futex we initially wait on (non-pi) 2621 * @uaddr: the futex we initially wait on (non-pi)
2539 * @flags: futex flags (FLAGS_SHARED, FLAGS_CLOCKRT, etc.), they must be 2622 * @flags: futex flags (FLAGS_SHARED, FLAGS_CLOCKRT, etc.), they must be
2540 * the same type, no requeueing from private to shared, etc. 2623 * the same type, no requeueing from private to shared, etc.
2541 * @val: the expected value of uaddr 2624 * @val: the expected value of uaddr
2542 * @abs_time: absolute timeout 2625 * @abs_time: absolute timeout
2543 * @bitset: 32 bit wakeup bitset set by userspace, defaults to all 2626 * @bitset: 32 bit wakeup bitset set by userspace, defaults to all
@@ -3012,6 +3095,8 @@ SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val,
3012 if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI || 3095 if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI ||
3013 cmd == FUTEX_WAIT_BITSET || 3096 cmd == FUTEX_WAIT_BITSET ||
3014 cmd == FUTEX_WAIT_REQUEUE_PI)) { 3097 cmd == FUTEX_WAIT_REQUEUE_PI)) {
3098 if (unlikely(should_fail_futex(!(op & FUTEX_PRIVATE_FLAG))))
3099 return -EFAULT;
3015 if (copy_from_user(&ts, utime, sizeof(ts)) != 0) 3100 if (copy_from_user(&ts, utime, sizeof(ts)) != 0)
3016 return -EFAULT; 3101 return -EFAULT;
3017 if (!timespec_valid(&ts)) 3102 if (!timespec_valid(&ts))