Skip to content

Commit

Permalink
mnt: Modify fs_fully_visible to deal with locked ro nodev and atime
Browse files Browse the repository at this point in the history
Ignore an existing mount if the locked readonly, nodev or atime
attributes are less permissive than the desired attributes
of the new mount.

On success ensure the new mount locks all of the same readonly, nodev and
atime attributes as the old mount.

The nosuid and noexec attributes are not checked here as this change
is destined for stable and enforcing those attributes causes a
regression in lxc and libvirt-lxc where those applications will not
start and there are no known executables on sysfs or proc and no known
way to create exectuables without code modifications

Cc: stable@vger.kernel.org
Fixes: e51db73 ("userns: Better restrictions on when proc and sysfs can be mounted")
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
  • Loading branch information
Eric W. Biederman committed Jun 4, 2015
1 parent 1b852bc commit 8c6cf9c
Showing 1 changed file with 21 additions and 3 deletions.
24 changes: 21 additions & 3 deletions fs/namespace.c
Original file line number Diff line number Diff line change
Expand Up @@ -2332,7 +2332,7 @@ static int do_add_mount(struct mount *newmnt, struct path *path, int mnt_flags)
return err;
}

static bool fs_fully_visible(struct file_system_type *fs_type);
static bool fs_fully_visible(struct file_system_type *fs_type, int *new_mnt_flags);

/*
* create a new mount for userspace and request it to be added into the
Expand Down Expand Up @@ -2366,7 +2366,7 @@ static int do_new_mount(struct path *path, const char *fstype, int flags,
mnt_flags |= MNT_NODEV | MNT_LOCK_NODEV;
}
if (type->fs_flags & FS_USERNS_VISIBLE) {
if (!fs_fully_visible(type))
if (!fs_fully_visible(type, &mnt_flags))
return -EPERM;
}
}
Expand Down Expand Up @@ -3170,9 +3170,10 @@ bool current_chrooted(void)
return chrooted;
}

static bool fs_fully_visible(struct file_system_type *type)
static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags)
{
struct mnt_namespace *ns = current->nsproxy->mnt_ns;
int new_flags = *new_mnt_flags;
struct mount *mnt;
bool visible = false;

Expand All @@ -3191,6 +3192,19 @@ static bool fs_fully_visible(struct file_system_type *type)
if (mnt->mnt.mnt_root != mnt->mnt.mnt_sb->s_root)
continue;

/* Verify the mount flags are equal to or more permissive
* than the proposed new mount.
*/
if ((mnt->mnt.mnt_flags & MNT_LOCK_READONLY) &&
!(new_flags & MNT_READONLY))
continue;
if ((mnt->mnt.mnt_flags & MNT_LOCK_NODEV) &&
!(new_flags & MNT_NODEV))
continue;
if ((mnt->mnt.mnt_flags & MNT_LOCK_ATIME) &&
((mnt->mnt.mnt_flags & MNT_ATIME_MASK) != (new_flags & MNT_ATIME_MASK)))
continue;

/* This mount is not fully visible if there are any child mounts
* that cover anything except for empty directories.
*/
Expand All @@ -3201,6 +3215,10 @@ static bool fs_fully_visible(struct file_system_type *type)
if (inode->i_nlink > 2)
goto next;
}
/* Preserve the locked attributes */
*new_mnt_flags |= mnt->mnt.mnt_flags & (MNT_LOCK_READONLY | \
MNT_LOCK_NODEV | \
MNT_LOCK_ATIME);
visible = true;
goto found;
next: ;
Expand Down

0 comments on commit 8c6cf9c

Please sign in to comment.