From 8d657eb3b43861064d36241e88d9d61c709f33f0 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Fri, 13 Jul 2012 13:35:36 -0400 Subject: Remove easily user-triggerable BUG from generic_setlease This can be trivially triggered from userspace by passing in something unexpected. kernel BUG at fs/locks.c:1468! invalid opcode: 0000 [#1] SMP RIP: 0010:generic_setlease+0xc2/0x100 Call Trace: __vfs_setlease+0x35/0x40 fcntl_setlease+0x76/0x150 sys_fcntl+0x1c6/0x810 system_call_fastpath+0x1a/0x1f Signed-off-by: Dave Jones Cc: stable@kernel.org # 3.2+ Signed-off-by: Linus Torvalds --- fs/locks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/locks.c') diff --git a/fs/locks.c b/fs/locks.c index 814c51d0de47..fce6238d52c1 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -1465,7 +1465,7 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp) case F_WRLCK: return generic_add_lease(filp, arg, flp); default: - BUG(); + return -EINVAL; } } EXPORT_SYMBOL(generic_setlease); -- cgit v1.2.3 From 0ec4f431eb56d633da3a55da67d5c4b88886ccc7 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Mon, 23 Jul 2012 15:17:17 -0400 Subject: locks: fix checking of fcntl_setlease argument The only checks of the long argument passed to fcntl(fd,F_SETLEASE,.) are done after converting the long to an int. Thus some illegal values may be let through and cause problems in later code. [ They actually *don't* cause problems in mainline, as of Dave Jones's commit 8d657eb3b438 "Remove easily user-triggerable BUG from generic_setlease", but we should fix this anyway. And this patch will be necessary to fix real bugs on earlier kernels. ] Cc: stable@vger.kernel.org Signed-off-by: J. Bruce Fields Signed-off-by: Linus Torvalds --- fs/locks.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'fs/locks.c') diff --git a/fs/locks.c b/fs/locks.c index fce6238d52c1..82c353304f9e 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -308,7 +308,7 @@ static int flock_make_lock(struct file *filp, struct file_lock **lock, return 0; } -static int assign_type(struct file_lock *fl, int type) +static int assign_type(struct file_lock *fl, long type) { switch (type) { case F_RDLCK: @@ -445,7 +445,7 @@ static const struct lock_manager_operations lease_manager_ops = { /* * Initialize a lease, use the default lock manager operations */ -static int lease_init(struct file *filp, int type, struct file_lock *fl) +static int lease_init(struct file *filp, long type, struct file_lock *fl) { if (assign_type(fl, type) != 0) return -EINVAL; @@ -463,7 +463,7 @@ static int lease_init(struct file *filp, int type, struct file_lock *fl) } /* Allocate a file_lock initialised to this type of lease */ -static struct file_lock *lease_alloc(struct file *filp, int type) +static struct file_lock *lease_alloc(struct file *filp, long type) { struct file_lock *fl = locks_alloc_lock(); int error = -ENOMEM; -- cgit v1.2.3 From 3b6e2723f32de42028617f2c99b244ccd72cd959 Mon Sep 17 00:00:00 2001 From: Filipe Brandenburger Date: Fri, 27 Jul 2012 00:42:52 -0400 Subject: locks: prevent side-effects of locks_release_private before file_lock is initialized When calling fcntl(fd, F_SETLEASE, lck) [with lck=F_WRLCK or F_RDLCK], the custom signal or owner (if any were previously set using F_SETSIG or F_SETOWN fcntls) would be reset when F_SETLEASE was called for the second time on the same file descriptor. This bug is a regression of 2.6.37 and is described here: https://bugzilla.kernel.org/show_bug.cgi?id=43336 This patch reverts a commit from Oct 2004 (with subject "nfs4 lease: move the f_delown processing") which originally introduced the lm_release_private callback. Signed-off-by: Filipe Brandenburger Signed-off-by: J. Bruce Fields --- fs/locks.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) (limited to 'fs/locks.c') diff --git a/fs/locks.c b/fs/locks.c index 814c51d0de47..86668dd211ae 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -427,18 +427,8 @@ static void lease_break_callback(struct file_lock *fl) kill_fasync(&fl->fl_fasync, SIGIO, POLL_MSG); } -static void lease_release_private_callback(struct file_lock *fl) -{ - if (!fl->fl_file) - return; - - f_delown(fl->fl_file); - fl->fl_file->f_owner.signum = 0; -} - static const struct lock_manager_operations lease_manager_ops = { .lm_break = lease_break_callback, - .lm_release_private = lease_release_private_callback, .lm_change = lease_modify, }; @@ -1155,8 +1145,13 @@ int lease_modify(struct file_lock **before, int arg) return error; lease_clear_pending(fl, arg); locks_wake_up_blocks(fl); - if (arg == F_UNLCK) + if (arg == F_UNLCK) { + struct file *filp = fl->fl_file; + + f_delown(filp); + filp->f_owner.signum = 0; locks_delete_lock(before); + } return 0; } -- cgit v1.2.3 From 96d6d59ceaeaacba4088862f3c57fcd011f52832 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Fri, 27 Jul 2012 16:18:00 -0400 Subject: locks: move lease-specific code out of locks_delete_lock No point putting something only used by one caller into common code. Signed-off-by: J. Bruce Fields --- fs/locks.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'fs/locks.c') diff --git a/fs/locks.c b/fs/locks.c index 86668dd211ae..541075a41527 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -570,12 +570,6 @@ static void locks_delete_lock(struct file_lock **thisfl_p) fl->fl_next = NULL; list_del_init(&fl->fl_link); - fasync_helper(0, fl->fl_file, 0, &fl->fl_fasync); - if (fl->fl_fasync != NULL) { - printk(KERN_ERR "locks_delete_lock: fasync == %p\n", fl->fl_fasync); - fl->fl_fasync = NULL; - } - if (fl->fl_nspid) { put_pid(fl->fl_nspid); fl->fl_nspid = NULL; @@ -1150,6 +1144,11 @@ int lease_modify(struct file_lock **before, int arg) f_delown(filp); filp->f_owner.signum = 0; + fasync_helper(0, fl->fl_file, 0, &fl->fl_fasync); + if (fl->fl_fasync != NULL) { + printk(KERN_ERR "locks_delete_lock: fasync == %p\n", fl->fl_fasync); + fl->fl_fasync = NULL; + } locks_delete_lock(before); } return 0; -- cgit v1.2.3 From 068535f1fef4c90aee23eb7b9b9a71c5b72d7cd0 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Wed, 1 Aug 2012 07:56:16 -0400 Subject: locks: remove unused lm_release_private In commit 3b6e2723f32d ("locks: prevent side-effects of locks_release_private before file_lock is initialized") we removed the last user of lm_release_private without removing the field itself. Signed-off-by: J. Bruce Fields Signed-off-by: Linus Torvalds --- fs/locks.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'fs/locks.c') diff --git a/fs/locks.c b/fs/locks.c index cdcf219a7391..7e81bfc75164 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -200,11 +200,7 @@ void locks_release_private(struct file_lock *fl) fl->fl_ops->fl_release_private(fl); fl->fl_ops = NULL; } - if (fl->fl_lmops) { - if (fl->fl_lmops->lm_release_private) - fl->fl_lmops->lm_release_private(fl); - fl->fl_lmops = NULL; - } + fl->fl_lmops = NULL; } EXPORT_SYMBOL_GPL(locks_release_private); -- cgit v1.2.3