Commit 4aceccd6 authored by Eric W. Biederman's avatar Eric W. Biederman

userns: Simpilify MNT_NODEV handling.

- Consolidate the testing if a device node may be opened in a new
  function may_open_dev.

- Move the check for allowing access to device nodes on filesystems
  not mounted in the initial user namespace from mount time to open
  time and include it in may_open_dev.

This set of changes removes the implicit adding of MNT_NODEV which
simplifies the logic in fs/namespace.c and removes a potentially
problematic difference in how normal and unprivileged mount
namespaces work.  This is a user visible change in behavior for
remount in unpriviliged mount namespaces but is unlikely to cause
problems for existing software.
Signed-off-by: default avatar"Eric W. Biederman" <ebiederm@xmission.com>
parent b2bc2ff7
......@@ -1730,7 +1730,7 @@ struct block_device *lookup_bdev(const char *pathname)
if (!S_ISBLK(inode->i_mode))
goto fail;
error = -EACCES;
if (path.mnt->mnt_flags & MNT_NODEV)
if (!may_open_dev(&path))
goto fail;
error = -ENOMEM;
bdev = bd_acquire(inode);
......
......@@ -2663,6 +2663,13 @@ int vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
}
EXPORT_SYMBOL(vfs_create);
bool may_open_dev(const struct path *path)
{
return !(path->mnt->mnt_flags & MNT_NODEV) &&
((path->mnt->mnt_sb->s_user_ns == &init_user_ns) ||
(path->mnt->mnt_sb->s_type->fs_flags & FS_USERNS_DEV_MOUNT));
}
static int may_open(struct path *path, int acc_mode, int flag)
{
struct dentry *dentry = path->dentry;
......@@ -2685,7 +2692,7 @@ static int may_open(struct path *path, int acc_mode, int flag)
break;
case S_IFBLK:
case S_IFCHR:
if (path->mnt->mnt_flags & MNT_NODEV)
if (!may_open_dev(path))
return -EACCES;
/*FALLTHRU*/
case S_IFIFO:
......
......@@ -2177,14 +2177,8 @@ static int do_remount(struct path *path, int flags, int mnt_flags,
}
if ((mnt->mnt.mnt_flags & MNT_LOCK_NODEV) &&
!(mnt_flags & MNT_NODEV)) {
/* Was the nodev implicitly added in mount? */
if ((mnt->mnt_ns->user_ns != &init_user_ns) &&
!(sb->s_type->fs_flags & FS_USERNS_DEV_MOUNT)) {
mnt_flags |= MNT_NODEV;
} else {
return -EPERM;
}
}
if ((mnt->mnt.mnt_flags & MNT_LOCK_NOSUID) &&
!(mnt_flags & MNT_NOSUID)) {
return -EPERM;
......@@ -2396,13 +2390,6 @@ static int do_new_mount(struct path *path, const char *fstype, int flags,
put_filesystem(type);
return -EPERM;
}
/* Only in special cases allow devices from mounts
* created outside the initial user namespace.
*/
if (!(type->fs_flags & FS_USERNS_DEV_MOUNT)) {
flags |= MS_NODEV;
mnt_flags |= MNT_NODEV | MNT_LOCK_NODEV;
}
if (type->fs_flags & FS_USERNS_VISIBLE) {
if (!fs_fully_visible(type, &mnt_flags))
return -EPERM;
......@@ -3238,6 +3225,9 @@ static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags)
mnt_flags = mnt->mnt.mnt_flags;
if (mnt->mnt.mnt_sb->s_iflags & SB_I_NOEXEC)
mnt_flags &= ~(MNT_LOCK_NOSUID | MNT_LOCK_NOEXEC);
if (mnt->mnt.mnt_sb->s_user_ns != &init_user_ns &&
!(mnt->mnt.mnt_sb->s_type->fs_flags & FS_USERNS_DEV_MOUNT))
mnt_flags &= ~(MNT_LOCK_NODEV);
/* Verify the mount flags are equal to or more permissive
* than the proposed new mount.
......
......@@ -1542,6 +1542,7 @@ extern void dentry_unhash(struct dentry *dentry);
*/
extern void inode_init_owner(struct inode *inode, const struct inode *dir,
umode_t mode);
extern bool may_open_dev(const struct path *path);
/*
* VFS FS_IOC_FIEMAP helper definitions.
*/
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment