ovl: check namelen
authorMiklos Szeredi <mszeredi@redhat.com>
Fri, 16 Dec 2016 10:02:56 +0000 (11:02 +0100)
committerMiklos Szeredi <mszeredi@redhat.com>
Fri, 16 Dec 2016 10:02:56 +0000 (11:02 +0100)
We already calculate f_namelen in statfs as the maximum of the name lengths
provided by the filesystems taking part in the overlay.

Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
fs/overlayfs/namei.c
fs/overlayfs/ovl_entry.h
fs/overlayfs/super.c

index f4057fcb0246fa437e44993fc0d4e514a901b10a..2e0b84c68ef638bc255cd23558dccfe0f416b4a1 100644 (file)
@@ -20,7 +20,8 @@ static struct dentry *ovl_lookup_real(struct dentry *dir,
 
        dentry = lookup_one_len_unlocked(name->name, dir, name->len);
        if (IS_ERR(dentry)) {
-               if (PTR_ERR(dentry) == -ENOENT)
+               if (PTR_ERR(dentry) == -ENOENT ||
+                   PTR_ERR(dentry) == -ENAMETOOLONG)
                        dentry = NULL;
        } else if (!dentry->d_inode) {
                dput(dentry);
@@ -74,6 +75,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
 {
        struct ovl_entry *oe;
        const struct cred *old_cred;
+       struct ovl_fs *ofs = dentry->d_sb->s_fs_info;
        struct ovl_entry *poe = dentry->d_parent->d_fsdata;
        struct path *stack = NULL;
        struct dentry *upperdir, *upperdentry = NULL;
@@ -86,6 +88,9 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
        unsigned int i;
        int err;
 
+       if (dentry->d_name.len > ofs->namelen)
+               return ERR_PTR(-ENAMETOOLONG);
+
        old_cred = ovl_override_creds(dentry->d_sb);
        upperdir = ovl_upperdentry_dereference(poe);
        if (upperdir) {
@@ -127,14 +132,9 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
 
                this = ovl_lookup_real(lowerpath.dentry, &dentry->d_name);
                err = PTR_ERR(this);
-               if (IS_ERR(this)) {
-                       /*
-                        * If it's positive, then treat ENAMETOOLONG as ENOENT.
-                        */
-                       if (err == -ENAMETOOLONG && (upperdentry || ctr))
-                               continue;
+               if (IS_ERR(this))
                        goto out_put;
-               }
+
                if (!this)
                        continue;
                if (ovl_is_whiteout(this)) {
index 3b7ba59ad27e9b5f2a59a2c3c643a202337a2036..b10745edfc9361256bc988baf26d591ae9f8495c 100644 (file)
@@ -21,7 +21,7 @@ struct ovl_fs {
        unsigned numlower;
        struct vfsmount **lower_mnt;
        struct dentry *workdir;
-       long lower_namelen;
+       long namelen;
        /* pathnames of lower and upper dirs, for show_options */
        struct ovl_config config;
        /* creds of process who forced instantiation of super block */
index 011482e74096f8849675cfe3e05ec5e38084e34e..e19e2ed6a4fdccb7266f4b722e297da5a145da67 100644 (file)
@@ -174,7 +174,7 @@ static int ovl_statfs(struct dentry *dentry, struct kstatfs *buf)
 
        err = vfs_statfs(&path, buf);
        if (!err) {
-               buf->f_namelen = max(buf->f_namelen, ofs->lower_namelen);
+               buf->f_namelen = ofs->namelen;
                buf->f_type = OVERLAYFS_SUPER_MAGIC;
        }
 
@@ -461,22 +461,33 @@ static int ovl_mount_dir(const char *name, struct path *path)
        return err;
 }
 
-static int ovl_lower_dir(const char *name, struct path *path, long *namelen,
-                        int *stack_depth, bool *remote)
+static int ovl_check_namelen(struct path *path, struct ovl_fs *ofs,
+                            const char *name)
 {
-       int err;
        struct kstatfs statfs;
+       int err = vfs_statfs(path, &statfs);
+
+       if (err)
+               pr_err("overlayfs: statfs failed on '%s'\n", name);
+       else
+               ofs->namelen = max(ofs->namelen, statfs.f_namelen);
+
+       return err;
+}
+
+static int ovl_lower_dir(const char *name, struct path *path,
+                        struct ovl_fs *ofs, int *stack_depth, bool *remote)
+{
+       int err;
 
        err = ovl_mount_dir_noesc(name, path);
        if (err)
                goto out;
 
-       err = vfs_statfs(path, &statfs);
-       if (err) {
-               pr_err("overlayfs: statfs failed on '%s'\n", name);
+       err = ovl_check_namelen(path, ofs, name);
+       if (err)
                goto out_put;
-       }
-       *namelen = max(*namelen, statfs.f_namelen);
+
        *stack_depth = max(*stack_depth, path->mnt->mnt_sb->s_stack_depth);
 
        if (ovl_dentry_remote(path->dentry))
@@ -708,6 +719,10 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
                        goto out_put_upperpath;
                }
 
+               err = ovl_check_namelen(&upperpath, ufs, ufs->config.upperdir);
+               if (err)
+                       goto out_put_upperpath;
+
                err = ovl_mount_dir(ufs->config.workdir, &workpath);
                if (err)
                        goto out_put_upperpath;
@@ -745,9 +760,8 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
 
        lower = lowertmp;
        for (numlower = 0; numlower < stacklen; numlower++) {
-               err = ovl_lower_dir(lower, &stack[numlower],
-                                   &ufs->lower_namelen, &sb->s_stack_depth,
-                                   &remote);
+               err = ovl_lower_dir(lower, &stack[numlower], ufs,
+                                   &sb->s_stack_depth, &remote);
                if (err)
                        goto out_put_lowerpath;