aboutsummaryrefslogtreecommitdiffstats
path: root/fs/open.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/open.c')
-rw-r--r--fs/open.c126
1 files changed, 118 insertions, 8 deletions
diff --git a/fs/open.c b/fs/open.c
index 80d430ae3b2..f83ca80cc59 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -573,13 +573,15 @@ SYSCALL_DEFINE5(fchownat, int, dfd, const char __user *, filename, uid_t, user,
573{ 573{
574 struct path path; 574 struct path path;
575 int error = -EINVAL; 575 int error = -EINVAL;
576 int follow; 576 int lookup_flags;
577 577
578 if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0) 578 if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) != 0)
579 goto out; 579 goto out;
580 580
581 follow = (flag & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW; 581 lookup_flags = (flag & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW;
582 error = user_path_at(dfd, filename, follow, &path); 582 if (flag & AT_EMPTY_PATH)
583 lookup_flags |= LOOKUP_EMPTY;
584 error = user_path_at(dfd, filename, lookup_flags, &path);
583 if (error) 585 if (error)
584 goto out; 586 goto out;
585 error = mnt_want_write(path.mnt); 587 error = mnt_want_write(path.mnt);
@@ -669,11 +671,16 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
669 int (*open)(struct inode *, struct file *), 671 int (*open)(struct inode *, struct file *),
670 const struct cred *cred) 672 const struct cred *cred)
671{ 673{
674 static const struct file_operations empty_fops = {};
672 struct inode *inode; 675 struct inode *inode;
673 int error; 676 int error;
674 677
675 f->f_mode = OPEN_FMODE(f->f_flags) | FMODE_LSEEK | 678 f->f_mode = OPEN_FMODE(f->f_flags) | FMODE_LSEEK |
676 FMODE_PREAD | FMODE_PWRITE; 679 FMODE_PREAD | FMODE_PWRITE;
680
681 if (unlikely(f->f_flags & O_PATH))
682 f->f_mode = FMODE_PATH;
683
677 inode = dentry->d_inode; 684 inode = dentry->d_inode;
678 if (f->f_mode & FMODE_WRITE) { 685 if (f->f_mode & FMODE_WRITE) {
679 error = __get_file_write_access(inode, mnt); 686 error = __get_file_write_access(inode, mnt);
@@ -687,9 +694,15 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
687 f->f_path.dentry = dentry; 694 f->f_path.dentry = dentry;
688 f->f_path.mnt = mnt; 695 f->f_path.mnt = mnt;
689 f->f_pos = 0; 696 f->f_pos = 0;
690 f->f_op = fops_get(inode->i_fop);
691 file_sb_list_add(f, inode->i_sb); 697 file_sb_list_add(f, inode->i_sb);
692 698
699 if (unlikely(f->f_mode & FMODE_PATH)) {
700 f->f_op = &empty_fops;
701 return f;
702 }
703
704 f->f_op = fops_get(inode->i_fop);
705
693 error = security_dentry_open(f, cred); 706 error = security_dentry_open(f, cred);
694 if (error) 707 if (error)
695 goto cleanup_all; 708 goto cleanup_all;
@@ -891,15 +904,110 @@ void fd_install(unsigned int fd, struct file *file)
891 904
892EXPORT_SYMBOL(fd_install); 905EXPORT_SYMBOL(fd_install);
893 906
907static inline int build_open_flags(int flags, int mode, struct open_flags *op)
908{
909 int lookup_flags = 0;
910 int acc_mode;
911
912 if (!(flags & O_CREAT))
913 mode = 0;
914 op->mode = mode;
915
916 /* Must never be set by userspace */
917 flags &= ~FMODE_NONOTIFY;
918
919 /*
920 * O_SYNC is implemented as __O_SYNC|O_DSYNC. As many places only
921 * check for O_DSYNC if the need any syncing at all we enforce it's
922 * always set instead of having to deal with possibly weird behaviour
923 * for malicious applications setting only __O_SYNC.
924 */
925 if (flags & __O_SYNC)
926 flags |= O_DSYNC;
927
928 /*
929 * If we have O_PATH in the open flag. Then we
930 * cannot have anything other than the below set of flags
931 */
932 if (flags & O_PATH) {
933 flags &= O_DIRECTORY | O_NOFOLLOW | O_PATH;
934 acc_mode = 0;
935 } else {
936 acc_mode = MAY_OPEN | ACC_MODE(flags);
937 }
938
939 op->open_flag = flags;
940
941 /* O_TRUNC implies we need access checks for write permissions */
942 if (flags & O_TRUNC)
943 acc_mode |= MAY_WRITE;
944
945 /* Allow the LSM permission hook to distinguish append
946 access from general write access. */
947 if (flags & O_APPEND)
948 acc_mode |= MAY_APPEND;
949
950 op->acc_mode = acc_mode;
951
952 op->intent = flags & O_PATH ? 0 : LOOKUP_OPEN;
953
954 if (flags & O_CREAT) {
955 op->intent |= LOOKUP_CREATE;
956 if (flags & O_EXCL)
957 op->intent |= LOOKUP_EXCL;
958 }
959
960 if (flags & O_DIRECTORY)
961 lookup_flags |= LOOKUP_DIRECTORY;
962 if (!(flags & O_NOFOLLOW))
963 lookup_flags |= LOOKUP_FOLLOW;
964 return lookup_flags;
965}
966
967/**
968 * filp_open - open file and return file pointer
969 *
970 * @filename: path to open
971 * @flags: open flags as per the open(2) second argument
972 * @mode: mode for the new file if O_CREAT is set, else ignored
973 *
974 * This is the helper to open a file from kernelspace if you really
975 * have to. But in generally you should not do this, so please move
976 * along, nothing to see here..
977 */
978struct file *filp_open(const char *filename, int flags, int mode)
979{
980 struct open_flags op;
981 int lookup = build_open_flags(flags, mode, &op);
982 return do_filp_open(AT_FDCWD, filename, &op, lookup);
983}
984EXPORT_SYMBOL(filp_open);
985
986struct file *file_open_root(struct dentry *dentry, struct vfsmount *mnt,
987 const char *filename, int flags)
988{
989 struct open_flags op;
990 int lookup = build_open_flags(flags, 0, &op);
991 if (flags & O_CREAT)
992 return ERR_PTR(-EINVAL);
993 if (!filename && (flags & O_DIRECTORY))
994 if (!dentry->d_inode->i_op->lookup)
995 return ERR_PTR(-ENOTDIR);
996 return do_file_open_root(dentry, mnt, filename, &op, lookup);
997}
998EXPORT_SYMBOL(file_open_root);
999
894long do_sys_open(int dfd, const char __user *filename, int flags, int mode) 1000long do_sys_open(int dfd, const char __user *filename, int flags, int mode)
895{ 1001{
1002 struct open_flags op;
1003 int lookup = build_open_flags(flags, mode, &op);
896 char *tmp = getname(filename); 1004 char *tmp = getname(filename);
897 int fd = PTR_ERR(tmp); 1005 int fd = PTR_ERR(tmp);
898 1006
899 if (!IS_ERR(tmp)) { 1007 if (!IS_ERR(tmp)) {
900 fd = get_unused_fd_flags(flags); 1008 fd = get_unused_fd_flags(flags);
901 if (fd >= 0) { 1009 if (fd >= 0) {
902 struct file *f = do_filp_open(dfd, tmp, flags, mode, 0); 1010 struct file *f = do_filp_open(dfd, tmp, &op, lookup);
903 if (IS_ERR(f)) { 1011 if (IS_ERR(f)) {
904 put_unused_fd(fd); 1012 put_unused_fd(fd);
905 fd = PTR_ERR(f); 1013 fd = PTR_ERR(f);
@@ -969,8 +1077,10 @@ int filp_close(struct file *filp, fl_owner_t id)
969 if (filp->f_op && filp->f_op->flush) 1077 if (filp->f_op && filp->f_op->flush)
970 retval = filp->f_op->flush(filp, id); 1078 retval = filp->f_op->flush(filp, id);
971 1079
972 dnotify_flush(filp, id); 1080 if (likely(!(filp->f_mode & FMODE_PATH))) {
973 locks_remove_posix(filp, id); 1081 dnotify_flush(filp, id);
1082 locks_remove_posix(filp, id);
1083 }
974 fput(filp); 1084 fput(filp);
975 return retval; 1085 return retval;
976} 1086}