From 97855b49b6bac0bd25f16b017883634d13591d00 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 30 Oct 2007 11:20:02 -0400 Subject: locks: fix possible infinite loop in posix deadlock detection It's currently possible to send posix_locks_deadlock() into an infinite loop (under the BKL). For now, fix this just by bailing out after a few iterations. We may want to fix this in a way that better clarifies the semantics of deadlock detection. But that will take more time, and this minimal fix is probably adequate for any realistic scenario, and is simple enough to be appropriate for applying to stable kernels now. Thanks to George Davis for reporting the problem. Cc: "George G. Davis" Signed-off-by: J. Bruce Fields Acked-by: Alan Cox Signed-off-by: Linus Torvalds --- fs/locks.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'fs') diff --git a/fs/locks.c b/fs/locks.c index 0127a284681..8b8388eca05 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -696,17 +696,28 @@ EXPORT_SYMBOL(posix_test_lock); * Note: the above assumption may not be true when handling lock requests * from a broken NFS client. But broken NFS clients have a lot more to * worry about than proper deadlock detection anyway... --okir + * + * However, the failure of this assumption (also possible in the case of + * multiple tasks sharing the same open file table) also means there's no + * guarantee that the loop below will terminate. As a hack, we give up + * after a few iterations. */ + +#define MAX_DEADLK_ITERATIONS 10 + static int posix_locks_deadlock(struct file_lock *caller_fl, struct file_lock *block_fl) { struct file_lock *fl; + int i = 0; next_task: if (posix_same_owner(caller_fl, block_fl)) return 1; list_for_each_entry(fl, &blocked_list, fl_link) { if (posix_same_owner(fl, block_fl)) { + if (i++ > MAX_DEADLK_ITERATIONS) + return 0; fl = fl->fl_next; block_fl = fl; goto next_task; -- cgit v1.2.3-70-g09d2