From: Miklos Szeredi Date: Fri, 16 Dec 2016 10:02:56 +0000 (+0100) Subject: ovl: check namelen X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=6b2d5fe46fa8f4fc1c5262c73930b9a2a94db2e3;p=linux-beck.git ovl: check namelen 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 --- diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c index f4057fcb0246..2e0b84c68ef6 100644 --- a/fs/overlayfs/namei.c +++ b/fs/overlayfs/namei.c @@ -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)) { diff --git a/fs/overlayfs/ovl_entry.h b/fs/overlayfs/ovl_entry.h index 3b7ba59ad27e..b10745edfc93 100644 --- a/fs/overlayfs/ovl_entry.h +++ b/fs/overlayfs/ovl_entry.h @@ -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 */ diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index 011482e74096..e19e2ed6a4fd 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -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;