mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
ovl: check that the parents of volatile/dirty are dirs
An unprivileged user crashes the kernel by mounting overlayfs with the
volatile option.
A dentry that serves as the parent of a lookup must be a directory.
ovl_create_volatile_dirty() walks work/incompat/volatile/dirty by name,
and ovl_lookup_or_create() returns an existing entry whatever its type.
A file or a symlink that another task creates during the mount becomes
the parent of the next lookup, which calls a NULL ->lookup.
An unprivileged user mounted overlayfs with "volatile" in a user
namespace while a second process created a symlink named work/incompat,
and the mount task oopsed on a NULL ->lookup call.
Fix this by returning -ENOTDIR from ovl_lookup_or_create() when the
caller asked for a directory and the existing entry is a non-dir.
Fixes: c86243b090 ("ovl: provide a mount option "volatile"")
Cc: stable@vger.kernel.org
Signed-off-by: Chris Mason <mason@kernel.org>
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
This commit is contained in:
parent
ba227ed05b
commit
e34d2ef818
|
|
@ -621,16 +621,21 @@ static int ovl_check_rename_whiteout(struct ovl_fs *ofs)
|
|||
|
||||
static struct dentry *ovl_lookup_or_create(struct ovl_fs *ofs,
|
||||
struct dentry *parent,
|
||||
const char *name, umode_t mode)
|
||||
const char *name, bool is_dir)
|
||||
{
|
||||
struct dentry *child;
|
||||
|
||||
child = ovl_start_creating_upper(ofs, parent, &QSTR(name));
|
||||
if (!IS_ERR(child)) {
|
||||
if (!child->d_inode)
|
||||
if (!child->d_inode) {
|
||||
child = ovl_create_real(ofs, parent, child,
|
||||
&QSTR(name),
|
||||
OVL_CATTR(mode));
|
||||
OVL_CATTR(is_dir ? S_IFDIR :
|
||||
S_IFREG));
|
||||
} else if (is_dir && !d_can_lookup(child)) {
|
||||
end_creating(child);
|
||||
child = ERR_PTR(-ENOTDIR);
|
||||
}
|
||||
end_creating_keep(child);
|
||||
}
|
||||
dput(parent);
|
||||
|
|
@ -652,7 +657,7 @@ static int ovl_create_volatile_dirty(struct ovl_fs *ofs)
|
|||
const char *const *name = volatile_path;
|
||||
|
||||
for (ctr = ARRAY_SIZE(volatile_path); ctr; ctr--, name++) {
|
||||
d = ovl_lookup_or_create(ofs, d, *name, ctr > 1 ? S_IFDIR : S_IFREG);
|
||||
d = ovl_lookup_or_create(ofs, d, *name, ctr > 1);
|
||||
if (IS_ERR(d))
|
||||
return PTR_ERR(d);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user