Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <mpe@ellerman.id.au>
Acked-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

+14 -14
+14 -14
fs/fcntl.c
··· 520 520 521 521 #ifdef CONFIG_COMPAT 522 522 /* careful - don't use anywhere else */ 523 - #define copy_flock_fields(from, to) \ 524 - (to).l_type = (from).l_type; \ 525 - (to).l_whence = (from).l_whence; \ 526 - (to).l_start = (from).l_start; \ 527 - (to).l_len = (from).l_len; \ 528 - (to).l_pid = (from).l_pid; 523 + #define copy_flock_fields(dst, src) \ 524 + (dst)->l_type = (src)->l_type; \ 525 + (dst)->l_whence = (src)->l_whence; \ 526 + (dst)->l_start = (src)->l_start; \ 527 + (dst)->l_len = (src)->l_len; \ 528 + (dst)->l_pid = (src)->l_pid; 529 529 530 - static int get_compat_flock(struct flock *kfl, struct compat_flock __user *ufl) 530 + static int get_compat_flock(struct flock *kfl, const struct compat_flock __user *ufl) 531 531 { 532 532 struct compat_flock fl; 533 533 534 534 if (copy_from_user(&fl, ufl, sizeof(struct compat_flock))) 535 535 return -EFAULT; 536 - copy_flock_fields(*kfl, fl); 536 + copy_flock_fields(kfl, &fl); 537 537 return 0; 538 538 } 539 539 540 - static int get_compat_flock64(struct flock *kfl, struct compat_flock64 __user *ufl) 540 + static int get_compat_flock64(struct flock *kfl, const struct compat_flock64 __user *ufl) 541 541 { 542 542 struct compat_flock64 fl; 543 543 544 544 if (copy_from_user(&fl, ufl, sizeof(struct compat_flock64))) 545 545 return -EFAULT; 546 - copy_flock_fields(*kfl, fl); 546 + copy_flock_fields(kfl, &fl); 547 547 return 0; 548 548 } 549 549 550 - static int put_compat_flock(struct flock *kfl, struct compat_flock __user *ufl) 550 + static int put_compat_flock(const struct flock *kfl, struct compat_flock __user *ufl) 551 551 { 552 552 struct compat_flock fl; 553 553 554 554 memset(&fl, 0, sizeof(struct compat_flock)); 555 - copy_flock_fields(fl, *kfl); 555 + copy_flock_fields(&fl, kfl); 556 556 if (copy_to_user(ufl, &fl, sizeof(struct compat_flock))) 557 557 return -EFAULT; 558 558 return 0; 559 559 } 560 560 561 - static int put_compat_flock64(struct flock *kfl, struct compat_flock64 __user *ufl) 561 + static int put_compat_flock64(const struct flock *kfl, struct compat_flock64 __user *ufl) 562 562 { 563 563 struct compat_flock64 fl; 564 564 565 565 memset(&fl, 0, sizeof(struct compat_flock64)); 566 - copy_flock_fields(fl, *kfl); 566 + copy_flock_fields(&fl, kfl); 567 567 if (copy_to_user(ufl, &fl, sizeof(struct compat_flock64))) 568 568 return -EFAULT; 569 569 return 0;