From b59eea554f57befa2aa3172fcb63e521bdd850dd Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 7 Jul 2017 13:48:18 -0700 Subject: vfs: fix flock compat thinko Michael Ellerman reported that commit 8c6657cb50cb ("Switch flock copyin/copyout primitives to copy_{from,to}_user()") broke his networking on a bunch of PPC machines (64-bit kernel, 32-bit userspace). The reason is a brown-paper bug by that commit, which had the arguments to "copy_flock_fields()" in the wrong order, breaking the compat handling for file locking. Apparently very few people run 32-bit user space on x86 any more, so the PPC people got the honor of noticing this "feature". Michael also sent a minimal diff that just changed the order of the arguments in that macro. This is not that minimal diff. This not only changes the order of the arguments in the macro, it also changes them to be pointers (to be consistent with all the other uses of those pointers), and makes the functions that do all of this also have the proper "const" attribution on the source pointers in order to make issues like that (using the source as a destination) be really obvious. Reported-by: Michael Ellerman Acked-by: Al Viro Signed-off-by: Linus Torvalds --- fs/fcntl.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'fs') diff --git a/fs/fcntl.c b/fs/fcntl.c index b6bd89628025..3b01b646e528 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -520,50 +520,50 @@ out: #ifdef CONFIG_COMPAT /* careful - don't use anywhere else */ -#define copy_flock_fields(from, to) \ - (to).l_type = (from).l_type; \ - (to).l_whence = (from).l_whence; \ - (to).l_start = (from).l_start; \ - (to).l_len = (from).l_len; \ - (to).l_pid = (from).l_pid; - -static int get_compat_flock(struct flock *kfl, struct compat_flock __user *ufl) +#define copy_flock_fields(dst, src) \ + (dst)->l_type = (src)->l_type; \ + (dst)->l_whence = (src)->l_whence; \ + (dst)->l_start = (src)->l_start; \ + (dst)->l_len = (src)->l_len; \ + (dst)->l_pid = (src)->l_pid; + +static int get_compat_flock(struct flock *kfl, const struct compat_flock __user *ufl) { struct compat_flock fl; if (copy_from_user(&fl, ufl, sizeof(struct compat_flock))) return -EFAULT; - copy_flock_fields(*kfl, fl); + copy_flock_fields(kfl, &fl); return 0; } -static int get_compat_flock64(struct flock *kfl, struct compat_flock64 __user *ufl) +static int get_compat_flock64(struct flock *kfl, const struct compat_flock64 __user *ufl) { struct compat_flock64 fl; if (copy_from_user(&fl, ufl, sizeof(struct compat_flock64))) return -EFAULT; - copy_flock_fields(*kfl, fl); + copy_flock_fields(kfl, &fl); return 0; } -static int put_compat_flock(struct flock *kfl, struct compat_flock __user *ufl) +static int put_compat_flock(const struct flock *kfl, struct compat_flock __user *ufl) { struct compat_flock fl; memset(&fl, 0, sizeof(struct compat_flock)); - copy_flock_fields(fl, *kfl); + copy_flock_fields(&fl, kfl); if (copy_to_user(ufl, &fl, sizeof(struct compat_flock))) return -EFAULT; return 0; } -static int put_compat_flock64(struct flock *kfl, struct compat_flock64 __user *ufl) +static int put_compat_flock64(const struct flock *kfl, struct compat_flock64 __user *ufl) { struct compat_flock64 fl; memset(&fl, 0, sizeof(struct compat_flock64)); - copy_flock_fields(fl, *kfl); + copy_flock_fields(&fl, kfl); if (copy_to_user(ufl, &fl, sizeof(struct compat_flock64))) return -EFAULT; return 0; -- cgit v1.2.3