summaryrefslogtreecommitdiffstats
path: root/fs/fcntl.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-07-05 16:13:32 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2017-07-05 16:13:32 -0400
commit3bad2f1c676581d01e7645eb03e9b27e28b0a92e (patch)
tree7e946eb2c7dab8c08e473ee1249be9a814728158 /fs/fcntl.c
parentb4b8cbf679c4866a523a35d1454884a31bd5d8dc (diff)
parent8c6657cb50cb037ff58b3f6a547c6569568f3527 (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.c231
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}
110EXPORT_SYMBOL(__f_setown); 110EXPORT_SYMBOL(__f_setown);
111 111
112void f_setown(struct file *filp, unsigned long arg, int force) 112int 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}
127EXPORT_SYMBOL(f_setown); 141EXPORT_SYMBOL(f_setown);
128 142
@@ -307,6 +321,8 @@ static long fcntl_rw_hint(struct file *file, unsigned int cmd,
307static long do_fcntl(int fd, unsigned int cmd, unsigned long arg, 321static 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:
450SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd, 471SYSCALL_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
492static int get_compat_flock(struct flock *kfl, struct compat_flock __user *ufl) 530static 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
504static int put_compat_flock(struct flock *kfl, struct compat_flock __user *ufl) 540static 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 550static int put_compat_flock(struct flock *kfl, struct compat_flock __user *ufl)
517static 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
531static int put_compat_flock64(struct flock *kfl, struct compat_flock64 __user *ufl) 561static 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
544static unsigned int 573static unsigned int
545convert_fcntl_cmd(unsigned int cmd) 574convert_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 */
597static 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
559COMPAT_SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd, 606COMPAT_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; 671out_put:
672 fdput(f);
673 return err;
629} 674}
630 675
631COMPAT_SYSCALL_DEFINE3(fcntl, unsigned int, fd, unsigned int, cmd, 676COMPAT_SYSCALL_DEFINE3(fcntl, unsigned int, fd, unsigned int, cmd,