diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-05 16:13:32 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-05 16:13:32 -0400 |
commit | 3bad2f1c676581d01e7645eb03e9b27e28b0a92e (patch) | |
tree | 7e946eb2c7dab8c08e473ee1249be9a814728158 /fs/fcntl.c | |
parent | b4b8cbf679c4866a523a35d1454884a31bd5d8dc (diff) | |
parent | 8c6657cb50cb037ff58b3f6a547c6569568f3527 (diff) |
Merge branch 'work.misc-set_fs' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull misc user access cleanups from Al Viro:
"The first pile is assorted getting rid of cargo-culted access_ok(),
cargo-culted set_fs() and field-by-field copyouts.
The same description applies to a lot of stuff in other branches -
this is just the stuff that didn't fit into a more specific topical
branch"
* 'work.misc-set_fs' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
Switch flock copyin/copyout primitives to copy_{from,to}_user()
fs/fcntl: return -ESRCH in f_setown when pid/pgid can't be found
fs/fcntl: f_setown, avoid undefined behaviour
fs/fcntl: f_setown, allow returning error
lpfc debugfs: get rid of pointless access_ok()
adb: get rid of pointless access_ok()
isdn: get rid of pointless access_ok()
compat statfs: switch to copy_to_user()
fs/locks: don't mess with the address limit in compat_fcntl64
nfsd_readlink(): switch to vfs_get_link()
drbd: ->sendpage() never needed set_fs()
fs/locks: pass kernel struct flock to fcntl_getlk/setlk
fs: locks: Fix some troubles at kernel-doc comments
Diffstat (limited to 'fs/fcntl.c')
-rw-r--r-- | fs/fcntl.c | 231 |
1 files changed, 138 insertions, 93 deletions
diff --git a/fs/fcntl.c b/fs/fcntl.c index ed051f825bad..b6bd89628025 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c | |||
@@ -109,20 +109,34 @@ void __f_setown(struct file *filp, struct pid *pid, enum pid_type type, | |||
109 | } | 109 | } |
110 | EXPORT_SYMBOL(__f_setown); | 110 | EXPORT_SYMBOL(__f_setown); |
111 | 111 | ||
112 | void f_setown(struct file *filp, unsigned long arg, int force) | 112 | int f_setown(struct file *filp, unsigned long arg, int force) |
113 | { | 113 | { |
114 | enum pid_type type; | 114 | enum pid_type type; |
115 | struct pid *pid; | 115 | struct pid *pid = NULL; |
116 | int who = arg; | 116 | int who = arg, ret = 0; |
117 | |||
117 | type = PIDTYPE_PID; | 118 | type = PIDTYPE_PID; |
118 | if (who < 0) { | 119 | if (who < 0) { |
120 | /* avoid overflow below */ | ||
121 | if (who == INT_MIN) | ||
122 | return -EINVAL; | ||
123 | |||
119 | type = PIDTYPE_PGID; | 124 | type = PIDTYPE_PGID; |
120 | who = -who; | 125 | who = -who; |
121 | } | 126 | } |
127 | |||
122 | rcu_read_lock(); | 128 | rcu_read_lock(); |
123 | pid = find_vpid(who); | 129 | if (who) { |
124 | __f_setown(filp, pid, type, force); | 130 | pid = find_vpid(who); |
131 | if (!pid) | ||
132 | ret = -ESRCH; | ||
133 | } | ||
134 | |||
135 | if (!ret) | ||
136 | __f_setown(filp, pid, type, force); | ||
125 | rcu_read_unlock(); | 137 | rcu_read_unlock(); |
138 | |||
139 | return ret; | ||
126 | } | 140 | } |
127 | EXPORT_SYMBOL(f_setown); | 141 | EXPORT_SYMBOL(f_setown); |
128 | 142 | ||
@@ -307,6 +321,8 @@ static long fcntl_rw_hint(struct file *file, unsigned int cmd, | |||
307 | static long do_fcntl(int fd, unsigned int cmd, unsigned long arg, | 321 | static long do_fcntl(int fd, unsigned int cmd, unsigned long arg, |
308 | struct file *filp) | 322 | struct file *filp) |
309 | { | 323 | { |
324 | void __user *argp = (void __user *)arg; | ||
325 | struct flock flock; | ||
310 | long err = -EINVAL; | 326 | long err = -EINVAL; |
311 | 327 | ||
312 | switch (cmd) { | 328 | switch (cmd) { |
@@ -334,7 +350,11 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg, | |||
334 | case F_OFD_GETLK: | 350 | case F_OFD_GETLK: |
335 | #endif | 351 | #endif |
336 | case F_GETLK: | 352 | case F_GETLK: |
337 | err = fcntl_getlk(filp, cmd, (struct flock __user *) arg); | 353 | if (copy_from_user(&flock, argp, sizeof(flock))) |
354 | return -EFAULT; | ||
355 | err = fcntl_getlk(filp, cmd, &flock); | ||
356 | if (!err && copy_to_user(argp, &flock, sizeof(flock))) | ||
357 | return -EFAULT; | ||
338 | break; | 358 | break; |
339 | #if BITS_PER_LONG != 32 | 359 | #if BITS_PER_LONG != 32 |
340 | /* 32-bit arches must use fcntl64() */ | 360 | /* 32-bit arches must use fcntl64() */ |
@@ -344,7 +364,9 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg, | |||
344 | /* Fallthrough */ | 364 | /* Fallthrough */ |
345 | case F_SETLK: | 365 | case F_SETLK: |
346 | case F_SETLKW: | 366 | case F_SETLKW: |
347 | err = fcntl_setlk(fd, filp, cmd, (struct flock __user *) arg); | 367 | if (copy_from_user(&flock, argp, sizeof(flock))) |
368 | return -EFAULT; | ||
369 | err = fcntl_setlk(fd, filp, cmd, &flock); | ||
348 | break; | 370 | break; |
349 | case F_GETOWN: | 371 | case F_GETOWN: |
350 | /* | 372 | /* |
@@ -358,8 +380,7 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg, | |||
358 | force_successful_syscall_return(); | 380 | force_successful_syscall_return(); |
359 | break; | 381 | break; |
360 | case F_SETOWN: | 382 | case F_SETOWN: |
361 | f_setown(filp, arg, 1); | 383 | err = f_setown(filp, arg, 1); |
362 | err = 0; | ||
363 | break; | 384 | break; |
364 | case F_GETOWN_EX: | 385 | case F_GETOWN_EX: |
365 | err = f_getown_ex(filp, arg); | 386 | err = f_getown_ex(filp, arg); |
@@ -450,7 +471,9 @@ out: | |||
450 | SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd, | 471 | SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd, |
451 | unsigned long, arg) | 472 | unsigned long, arg) |
452 | { | 473 | { |
474 | void __user *argp = (void __user *)arg; | ||
453 | struct fd f = fdget_raw(fd); | 475 | struct fd f = fdget_raw(fd); |
476 | struct flock64 flock; | ||
454 | long err = -EBADF; | 477 | long err = -EBADF; |
455 | 478 | ||
456 | if (!f.file) | 479 | if (!f.file) |
@@ -468,14 +491,21 @@ SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd, | |||
468 | switch (cmd) { | 491 | switch (cmd) { |
469 | case F_GETLK64: | 492 | case F_GETLK64: |
470 | case F_OFD_GETLK: | 493 | case F_OFD_GETLK: |
471 | err = fcntl_getlk64(f.file, cmd, (struct flock64 __user *) arg); | 494 | err = -EFAULT; |
495 | if (copy_from_user(&flock, argp, sizeof(flock))) | ||
496 | break; | ||
497 | err = fcntl_getlk64(f.file, cmd, &flock); | ||
498 | if (!err && copy_to_user(argp, &flock, sizeof(flock))) | ||
499 | err = -EFAULT; | ||
472 | break; | 500 | break; |
473 | case F_SETLK64: | 501 | case F_SETLK64: |
474 | case F_SETLKW64: | 502 | case F_SETLKW64: |
475 | case F_OFD_SETLK: | 503 | case F_OFD_SETLK: |
476 | case F_OFD_SETLKW: | 504 | case F_OFD_SETLKW: |
477 | err = fcntl_setlk64(fd, f.file, cmd, | 505 | err = -EFAULT; |
478 | (struct flock64 __user *) arg); | 506 | if (copy_from_user(&flock, argp, sizeof(flock))) |
507 | break; | ||
508 | err = fcntl_setlk64(fd, f.file, cmd, &flock); | ||
479 | break; | 509 | break; |
480 | default: | 510 | default: |
481 | err = do_fcntl(fd, cmd, arg, f.file); | 511 | err = do_fcntl(fd, cmd, arg, f.file); |
@@ -489,57 +519,56 @@ out: | |||
489 | #endif | 519 | #endif |
490 | 520 | ||
491 | #ifdef CONFIG_COMPAT | 521 | #ifdef CONFIG_COMPAT |
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; | ||
529 | |||
492 | static int get_compat_flock(struct flock *kfl, struct compat_flock __user *ufl) | 530 | static int get_compat_flock(struct flock *kfl, struct compat_flock __user *ufl) |
493 | { | 531 | { |
494 | if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) || | 532 | struct compat_flock fl; |
495 | __get_user(kfl->l_type, &ufl->l_type) || | 533 | |
496 | __get_user(kfl->l_whence, &ufl->l_whence) || | 534 | if (copy_from_user(&fl, ufl, sizeof(struct compat_flock))) |
497 | __get_user(kfl->l_start, &ufl->l_start) || | ||
498 | __get_user(kfl->l_len, &ufl->l_len) || | ||
499 | __get_user(kfl->l_pid, &ufl->l_pid)) | ||
500 | return -EFAULT; | 535 | return -EFAULT; |
536 | copy_flock_fields(*kfl, fl); | ||
501 | return 0; | 537 | return 0; |
502 | } | 538 | } |
503 | 539 | ||
504 | static int put_compat_flock(struct flock *kfl, struct compat_flock __user *ufl) | 540 | static int get_compat_flock64(struct flock *kfl, struct compat_flock64 __user *ufl) |
505 | { | 541 | { |
506 | if (!access_ok(VERIFY_WRITE, ufl, sizeof(*ufl)) || | 542 | struct compat_flock64 fl; |
507 | __put_user(kfl->l_type, &ufl->l_type) || | 543 | |
508 | __put_user(kfl->l_whence, &ufl->l_whence) || | 544 | if (copy_from_user(&fl, ufl, sizeof(struct compat_flock64))) |
509 | __put_user(kfl->l_start, &ufl->l_start) || | ||
510 | __put_user(kfl->l_len, &ufl->l_len) || | ||
511 | __put_user(kfl->l_pid, &ufl->l_pid)) | ||
512 | return -EFAULT; | 545 | return -EFAULT; |
546 | copy_flock_fields(*kfl, fl); | ||
513 | return 0; | 547 | return 0; |
514 | } | 548 | } |
515 | 549 | ||
516 | #ifndef HAVE_ARCH_GET_COMPAT_FLOCK64 | 550 | static int put_compat_flock(struct flock *kfl, struct compat_flock __user *ufl) |
517 | static int get_compat_flock64(struct flock *kfl, struct compat_flock64 __user *ufl) | ||
518 | { | 551 | { |
519 | if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) || | 552 | struct compat_flock fl; |
520 | __get_user(kfl->l_type, &ufl->l_type) || | 553 | |
521 | __get_user(kfl->l_whence, &ufl->l_whence) || | 554 | memset(&fl, 0, sizeof(struct compat_flock)); |
522 | __get_user(kfl->l_start, &ufl->l_start) || | 555 | copy_flock_fields(fl, *kfl); |
523 | __get_user(kfl->l_len, &ufl->l_len) || | 556 | if (copy_to_user(ufl, &fl, sizeof(struct compat_flock))) |
524 | __get_user(kfl->l_pid, &ufl->l_pid)) | ||
525 | return -EFAULT; | 557 | return -EFAULT; |
526 | return 0; | 558 | return 0; |
527 | } | 559 | } |
528 | #endif | ||
529 | 560 | ||
530 | #ifndef HAVE_ARCH_PUT_COMPAT_FLOCK64 | ||
531 | static int put_compat_flock64(struct flock *kfl, struct compat_flock64 __user *ufl) | 561 | static int put_compat_flock64(struct flock *kfl, struct compat_flock64 __user *ufl) |
532 | { | 562 | { |
533 | if (!access_ok(VERIFY_WRITE, ufl, sizeof(*ufl)) || | 563 | struct compat_flock64 fl; |
534 | __put_user(kfl->l_type, &ufl->l_type) || | 564 | |
535 | __put_user(kfl->l_whence, &ufl->l_whence) || | 565 | memset(&fl, 0, sizeof(struct compat_flock64)); |
536 | __put_user(kfl->l_start, &ufl->l_start) || | 566 | copy_flock_fields(fl, *kfl); |
537 | __put_user(kfl->l_len, &ufl->l_len) || | 567 | if (copy_to_user(ufl, &fl, sizeof(struct compat_flock64))) |
538 | __put_user(kfl->l_pid, &ufl->l_pid)) | ||
539 | return -EFAULT; | 568 | return -EFAULT; |
540 | return 0; | 569 | return 0; |
541 | } | 570 | } |
542 | #endif | 571 | #undef copy_flock_fields |
543 | 572 | ||
544 | static unsigned int | 573 | static unsigned int |
545 | convert_fcntl_cmd(unsigned int cmd) | 574 | convert_fcntl_cmd(unsigned int cmd) |
@@ -556,76 +585,92 @@ convert_fcntl_cmd(unsigned int cmd) | |||
556 | return cmd; | 585 | return cmd; |
557 | } | 586 | } |
558 | 587 | ||
588 | /* | ||
589 | * GETLK was successful and we need to return the data, but it needs to fit in | ||
590 | * the compat structure. | ||
591 | * l_start shouldn't be too big, unless the original start + end is greater than | ||
592 | * COMPAT_OFF_T_MAX, in which case the app was asking for trouble, so we return | ||
593 | * -EOVERFLOW in that case. l_len could be too big, in which case we just | ||
594 | * truncate it, and only allow the app to see that part of the conflicting lock | ||
595 | * that might make sense to it anyway | ||
596 | */ | ||
597 | static int fixup_compat_flock(struct flock *flock) | ||
598 | { | ||
599 | if (flock->l_start > COMPAT_OFF_T_MAX) | ||
600 | return -EOVERFLOW; | ||
601 | if (flock->l_len > COMPAT_OFF_T_MAX) | ||
602 | flock->l_len = COMPAT_OFF_T_MAX; | ||
603 | return 0; | ||
604 | } | ||
605 | |||
559 | COMPAT_SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd, | 606 | COMPAT_SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd, |
560 | compat_ulong_t, arg) | 607 | compat_ulong_t, arg) |
561 | { | 608 | { |
562 | mm_segment_t old_fs; | 609 | struct fd f = fdget_raw(fd); |
563 | struct flock f; | 610 | struct flock flock; |
564 | long ret; | 611 | long err = -EBADF; |
565 | unsigned int conv_cmd; | 612 | |
613 | if (!f.file) | ||
614 | return err; | ||
615 | |||
616 | if (unlikely(f.file->f_mode & FMODE_PATH)) { | ||
617 | if (!check_fcntl_cmd(cmd)) | ||
618 | goto out_put; | ||
619 | } | ||
620 | |||
621 | err = security_file_fcntl(f.file, cmd, arg); | ||
622 | if (err) | ||
623 | goto out_put; | ||
566 | 624 | ||
567 | switch (cmd) { | 625 | switch (cmd) { |
568 | case F_GETLK: | 626 | case F_GETLK: |
627 | err = get_compat_flock(&flock, compat_ptr(arg)); | ||
628 | if (err) | ||
629 | break; | ||
630 | err = fcntl_getlk(f.file, convert_fcntl_cmd(cmd), &flock); | ||
631 | if (err) | ||
632 | break; | ||
633 | err = fixup_compat_flock(&flock); | ||
634 | if (err) | ||
635 | return err; | ||
636 | err = put_compat_flock(&flock, compat_ptr(arg)); | ||
637 | break; | ||
638 | case F_GETLK64: | ||
639 | case F_OFD_GETLK: | ||
640 | err = get_compat_flock64(&flock, compat_ptr(arg)); | ||
641 | if (err) | ||
642 | break; | ||
643 | err = fcntl_getlk(f.file, convert_fcntl_cmd(cmd), &flock); | ||
644 | if (err) | ||
645 | break; | ||
646 | err = fixup_compat_flock(&flock); | ||
647 | if (err) | ||
648 | return err; | ||
649 | err = put_compat_flock64(&flock, compat_ptr(arg)); | ||
650 | break; | ||
569 | case F_SETLK: | 651 | case F_SETLK: |
570 | case F_SETLKW: | 652 | case F_SETLKW: |
571 | ret = get_compat_flock(&f, compat_ptr(arg)); | 653 | err = get_compat_flock(&flock, compat_ptr(arg)); |
572 | if (ret != 0) | 654 | if (err) |
573 | break; | 655 | break; |
574 | old_fs = get_fs(); | 656 | err = fcntl_setlk(fd, f.file, convert_fcntl_cmd(cmd), &flock); |
575 | set_fs(KERNEL_DS); | ||
576 | ret = sys_fcntl(fd, cmd, (unsigned long)&f); | ||
577 | set_fs(old_fs); | ||
578 | if (cmd == F_GETLK && ret == 0) { | ||
579 | /* GETLK was successful and we need to return the data... | ||
580 | * but it needs to fit in the compat structure. | ||
581 | * l_start shouldn't be too big, unless the original | ||
582 | * start + end is greater than COMPAT_OFF_T_MAX, in which | ||
583 | * case the app was asking for trouble, so we return | ||
584 | * -EOVERFLOW in that case. | ||
585 | * l_len could be too big, in which case we just truncate it, | ||
586 | * and only allow the app to see that part of the conflicting | ||
587 | * lock that might make sense to it anyway | ||
588 | */ | ||
589 | |||
590 | if (f.l_start > COMPAT_OFF_T_MAX) | ||
591 | ret = -EOVERFLOW; | ||
592 | if (f.l_len > COMPAT_OFF_T_MAX) | ||
593 | f.l_len = COMPAT_OFF_T_MAX; | ||
594 | if (ret == 0) | ||
595 | ret = put_compat_flock(&f, compat_ptr(arg)); | ||
596 | } | ||
597 | break; | 657 | break; |
598 | |||
599 | case F_GETLK64: | ||
600 | case F_SETLK64: | 658 | case F_SETLK64: |
601 | case F_SETLKW64: | 659 | case F_SETLKW64: |
602 | case F_OFD_GETLK: | ||
603 | case F_OFD_SETLK: | 660 | case F_OFD_SETLK: |
604 | case F_OFD_SETLKW: | 661 | case F_OFD_SETLKW: |
605 | ret = get_compat_flock64(&f, compat_ptr(arg)); | 662 | err = get_compat_flock64(&flock, compat_ptr(arg)); |
606 | if (ret != 0) | 663 | if (err) |
607 | break; | 664 | break; |
608 | old_fs = get_fs(); | 665 | err = fcntl_setlk(fd, f.file, convert_fcntl_cmd(cmd), &flock); |
609 | set_fs(KERNEL_DS); | ||
610 | conv_cmd = convert_fcntl_cmd(cmd); | ||
611 | ret = sys_fcntl(fd, conv_cmd, (unsigned long)&f); | ||
612 | set_fs(old_fs); | ||
613 | if ((conv_cmd == F_GETLK || conv_cmd == F_OFD_GETLK) && ret == 0) { | ||
614 | /* need to return lock information - see above for commentary */ | ||
615 | if (f.l_start > COMPAT_LOFF_T_MAX) | ||
616 | ret = -EOVERFLOW; | ||
617 | if (f.l_len > COMPAT_LOFF_T_MAX) | ||
618 | f.l_len = COMPAT_LOFF_T_MAX; | ||
619 | if (ret == 0) | ||
620 | ret = put_compat_flock64(&f, compat_ptr(arg)); | ||
621 | } | ||
622 | break; | 666 | break; |
623 | |||
624 | default: | 667 | default: |
625 | ret = sys_fcntl(fd, cmd, arg); | 668 | err = do_fcntl(fd, cmd, arg, f.file); |
626 | break; | 669 | break; |
627 | } | 670 | } |
628 | return ret; | 671 | out_put: |
672 | fdput(f); | ||
673 | return err; | ||
629 | } | 674 | } |
630 | 675 | ||
631 | COMPAT_SYSCALL_DEFINE3(fcntl, unsigned int, fd, unsigned int, cmd, | 676 | COMPAT_SYSCALL_DEFINE3(fcntl, unsigned int, fd, unsigned int, cmd, |