ovl: pass correct flags for opening real directory
authorMiklos Szeredi <mszeredi@redhat.com>
Tue, 2 Jun 2020 20:20:25 +0000 (22:20 +0200)
committerMiklos Szeredi <mszeredi@redhat.com>
Tue, 2 Jun 2020 20:20:25 +0000 (22:20 +0200)
The three instances of ovl_path_open() in overlayfs/readdir.c do three
different things:

 - pass f_flags from overlay file
 - pass O_RDONLY | O_DIRECTORY
 - pass just O_RDONLY

The value of f_flags can be (other than O_RDONLY):

O_WRONLY - not possible for a directory
O_RDWR - not possible for a directory
O_CREAT - masked out by dentry_open()
O_EXCL - masked out by dentry_open()
O_NOCTTY - masked out by dentry_open()
O_TRUNC - masked out by dentry_open()
O_APPEND - no effect on directory ops
O_NDELAY - no effect on directory ops
O_NONBLOCK - no effect on directory ops
__O_SYNC - no effect on directory ops
O_DSYNC - no effect on directory ops
FASYNC - no effect on directory ops
O_DIRECT - no effect on directory ops
O_LARGEFILE - ?
O_DIRECTORY - only affects lookup
O_NOFOLLOW - only affects lookup
O_NOATIME - overlay sets this unconditionally in ovl_path_open()
O_CLOEXEC - only affects fd allocation
O_PATH - no effect on directory ops
__O_TMPFILE - not possible for a directory

Fon non-merge directories we use the underlying filesystem's iterate; in
this case honor O_LARGEFILE from the original file to make sure that open
doesn't get rejected.

For merge directories it's safe to pass O_LARGEFILE unconditionally since
userspace will only see the artificial offsets created by overlayfs.

Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
fs/overlayfs/readdir.c

index a10b21b..3bc9706 100644 (file)
@@ -297,7 +297,7 @@ static inline int ovl_dir_read(struct path *realpath,
        struct file *realfile;
        int err;
 
-       realfile = ovl_path_open(realpath, O_RDONLY | O_DIRECTORY);
+       realfile = ovl_path_open(realpath, O_RDONLY | O_LARGEFILE);
        if (IS_ERR(realfile))
                return PTR_ERR(realfile);
 
@@ -831,6 +831,12 @@ out_unlock:
        return res;
 }
 
+static struct file *ovl_dir_open_realfile(struct file *file,
+                                         struct path *realpath)
+{
+       return ovl_path_open(realpath, O_RDONLY | (file->f_flags & O_LARGEFILE));
+}
+
 static int ovl_dir_fsync(struct file *file, loff_t start, loff_t end,
                         int datasync)
 {
@@ -853,7 +859,7 @@ static int ovl_dir_fsync(struct file *file, loff_t start, loff_t end,
                        struct path upperpath;
 
                        ovl_path_upper(dentry, &upperpath);
-                       realfile = ovl_path_open(&upperpath, O_RDONLY);
+                       realfile = ovl_dir_open_realfile(file, &upperpath);
 
                        inode_lock(inode);
                        if (!od->upperfile) {
@@ -904,7 +910,7 @@ static int ovl_dir_open(struct inode *inode, struct file *file)
                return -ENOMEM;
 
        type = ovl_path_real(file->f_path.dentry, &realpath);
-       realfile = ovl_path_open(&realpath, file->f_flags);
+       realfile = ovl_dir_open_realfile(file, &realpath);
        if (IS_ERR(realfile)) {
                kfree(od);
                return PTR_ERR(realfile);