diff options
Diffstat (limited to 'fs/fcntl.c')
-rw-r--r-- | fs/fcntl.c | 37 |
1 files changed, 32 insertions, 5 deletions
diff --git a/fs/fcntl.c b/fs/fcntl.c index cb1026181bd..6c82e5bac03 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c | |||
@@ -131,7 +131,7 @@ SYSCALL_DEFINE2(dup2, unsigned int, oldfd, unsigned int, newfd) | |||
131 | SYSCALL_DEFINE1(dup, unsigned int, fildes) | 131 | SYSCALL_DEFINE1(dup, unsigned int, fildes) |
132 | { | 132 | { |
133 | int ret = -EBADF; | 133 | int ret = -EBADF; |
134 | struct file *file = fget(fildes); | 134 | struct file *file = fget_raw(fildes); |
135 | 135 | ||
136 | if (file) { | 136 | if (file) { |
137 | ret = get_unused_fd(); | 137 | ret = get_unused_fd(); |
@@ -426,15 +426,35 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg, | |||
426 | return err; | 426 | return err; |
427 | } | 427 | } |
428 | 428 | ||
429 | static int check_fcntl_cmd(unsigned cmd) | ||
430 | { | ||
431 | switch (cmd) { | ||
432 | case F_DUPFD: | ||
433 | case F_DUPFD_CLOEXEC: | ||
434 | case F_GETFD: | ||
435 | case F_SETFD: | ||
436 | case F_GETFL: | ||
437 | return 1; | ||
438 | } | ||
439 | return 0; | ||
440 | } | ||
441 | |||
429 | SYSCALL_DEFINE3(fcntl, unsigned int, fd, unsigned int, cmd, unsigned long, arg) | 442 | SYSCALL_DEFINE3(fcntl, unsigned int, fd, unsigned int, cmd, unsigned long, arg) |
430 | { | 443 | { |
431 | struct file *filp; | 444 | struct file *filp; |
432 | long err = -EBADF; | 445 | long err = -EBADF; |
433 | 446 | ||
434 | filp = fget(fd); | 447 | filp = fget_raw(fd); |
435 | if (!filp) | 448 | if (!filp) |
436 | goto out; | 449 | goto out; |
437 | 450 | ||
451 | if (unlikely(filp->f_mode & FMODE_PATH)) { | ||
452 | if (!check_fcntl_cmd(cmd)) { | ||
453 | fput(filp); | ||
454 | goto out; | ||
455 | } | ||
456 | } | ||
457 | |||
438 | err = security_file_fcntl(filp, cmd, arg); | 458 | err = security_file_fcntl(filp, cmd, arg); |
439 | if (err) { | 459 | if (err) { |
440 | fput(filp); | 460 | fput(filp); |
@@ -456,10 +476,17 @@ SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd, | |||
456 | long err; | 476 | long err; |
457 | 477 | ||
458 | err = -EBADF; | 478 | err = -EBADF; |
459 | filp = fget(fd); | 479 | filp = fget_raw(fd); |
460 | if (!filp) | 480 | if (!filp) |
461 | goto out; | 481 | goto out; |
462 | 482 | ||
483 | if (unlikely(filp->f_mode & FMODE_PATH)) { | ||
484 | if (!check_fcntl_cmd(cmd)) { | ||
485 | fput(filp); | ||
486 | goto out; | ||
487 | } | ||
488 | } | ||
489 | |||
463 | err = security_file_fcntl(filp, cmd, arg); | 490 | err = security_file_fcntl(filp, cmd, arg); |
464 | if (err) { | 491 | if (err) { |
465 | fput(filp); | 492 | fput(filp); |
@@ -808,14 +835,14 @@ static int __init fcntl_init(void) | |||
808 | * Exceptions: O_NONBLOCK is a two bit define on parisc; O_NDELAY | 835 | * Exceptions: O_NONBLOCK is a two bit define on parisc; O_NDELAY |
809 | * is defined as O_NONBLOCK on some platforms and not on others. | 836 | * is defined as O_NONBLOCK on some platforms and not on others. |
810 | */ | 837 | */ |
811 | BUILD_BUG_ON(18 - 1 /* for O_RDONLY being 0 */ != HWEIGHT32( | 838 | BUILD_BUG_ON(19 - 1 /* for O_RDONLY being 0 */ != HWEIGHT32( |
812 | O_RDONLY | O_WRONLY | O_RDWR | | 839 | O_RDONLY | O_WRONLY | O_RDWR | |
813 | O_CREAT | O_EXCL | O_NOCTTY | | 840 | O_CREAT | O_EXCL | O_NOCTTY | |
814 | O_TRUNC | O_APPEND | /* O_NONBLOCK | */ | 841 | O_TRUNC | O_APPEND | /* O_NONBLOCK | */ |
815 | __O_SYNC | O_DSYNC | FASYNC | | 842 | __O_SYNC | O_DSYNC | FASYNC | |
816 | O_DIRECT | O_LARGEFILE | O_DIRECTORY | | 843 | O_DIRECT | O_LARGEFILE | O_DIRECTORY | |
817 | O_NOFOLLOW | O_NOATIME | O_CLOEXEC | | 844 | O_NOFOLLOW | O_NOATIME | O_CLOEXEC | |
818 | __FMODE_EXEC | 845 | __FMODE_EXEC | O_PATH |
819 | )); | 846 | )); |
820 | 847 | ||
821 | fasync_cache = kmem_cache_create("fasync_cache", | 848 | fasync_cache = kmem_cache_create("fasync_cache", |