Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 73b6fa8e authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull user namespace updates from Eric Biederman:
 "This finishes up the changes to ensure proc and sysfs do not start
  implementing executable files, as the there are application today that
  are only secure because such files do not exist.

  It akso fixes a long standing misfeature of /proc/<pid>/mountinfo that
  did not show the proper source for files bind mounted from
  /proc/<pid>/ns/*.

  It also straightens out the handling of clone flags related to user
  namespaces, fixing an unnecessary failure of unshare(CLONE_NEWUSER)
  when files such as /proc/<pid>/environ are read while <pid> is calling
  unshare.  This winds up fixing a minor bug in unshare flag handling
  that dates back to the first version of unshare in the kernel.

  Finally, this fixes a minor regression caused by the introduction of
  sysfs_create_mount_point, which broke someone's in house application,
  by restoring the size of /sys/fs/cgroup to 0 bytes.  Apparently that
  application uses the directory size to determine if a tmpfs is mounted
  on /sys/fs/cgroup.

  The bind mount escape fixes are present in Al Viros for-next branch.
  and I expect them to come from there.  The bind mount escape is the
  last of the user namespace related security bugs that I am aware of"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace:
  fs: Set the size of empty dirs to 0.
  userns,pidns: Force thread group sharing, not signal handler sharing.
  unshare: Unsharing a thread does not require unsharing a vm
  nsfs: Add a show_path method to fix mountinfo
  mnt: fs_fully_visible enforce noexec and nosuid  if !SB_I_NOEXEC
  vfs: Commit to never having exectuables on proc and sysfs.
parents e713c80a 4b75de86
Loading
Loading
Loading
Loading
+8 −2
Original line number Diff line number Diff line
@@ -98,6 +98,12 @@ static inline void put_binfmt(struct linux_binfmt * fmt)
	module_put(fmt->module);
}

bool path_noexec(const struct path *path)
{
	return (path->mnt->mnt_flags & MNT_NOEXEC) ||
	       (path->mnt->mnt_sb->s_iflags & SB_I_NOEXEC);
}

#ifdef CONFIG_USELIB
/*
 * Note that a shared library must be both readable and executable due to
@@ -132,7 +138,7 @@ SYSCALL_DEFINE1(uselib, const char __user *, library)
		goto exit;

	error = -EACCES;
	if (file->f_path.mnt->mnt_flags & MNT_NOEXEC)
	if (path_noexec(&file->f_path))
		goto exit;

	fsnotify_open(file);
@@ -777,7 +783,7 @@ static struct file *do_open_execat(int fd, struct filename *name, int flags)
	if (!S_ISREG(file_inode(file)->i_mode))
		goto exit;

	if (file->f_path.mnt->mnt_flags & MNT_NOEXEC)
	if (path_noexec(&file->f_path))
		goto exit;

	err = deny_write_access(file);
+1 −1
Original line number Diff line number Diff line
@@ -1185,7 +1185,7 @@ void make_empty_dir_inode(struct inode *inode)
	inode->i_uid = GLOBAL_ROOT_UID;
	inode->i_gid = GLOBAL_ROOT_GID;
	inode->i_rdev = 0;
	inode->i_size = 2;
	inode->i_size = 0;
	inode->i_blkbits = PAGE_SHIFT;
	inode->i_blocks = 0;

+25 −8
Original line number Diff line number Diff line
@@ -3218,6 +3218,8 @@ static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags)
	down_read(&namespace_sem);
	list_for_each_entry(mnt, &ns->list, mnt_list) {
		struct mount *child;
		int mnt_flags;

		if (mnt->mnt.mnt_sb->s_type != type)
			continue;

@@ -3227,17 +3229,30 @@ static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags)
		if (mnt->mnt.mnt_root != mnt->mnt.mnt_sb->s_root)
			continue;

		/* Read the mount flags and filter out flags that
		 * may safely be ignored.
		 */
		mnt_flags = mnt->mnt.mnt_flags;
		if (mnt->mnt.mnt_sb->s_iflags & SB_I_NOEXEC)
			mnt_flags &= ~(MNT_LOCK_NOSUID | MNT_LOCK_NOEXEC);

		/* Verify the mount flags are equal to or more permissive
		 * than the proposed new mount.
		 */
		if ((mnt->mnt.mnt_flags & MNT_LOCK_READONLY) &&
		if ((mnt_flags & MNT_LOCK_READONLY) &&
		    !(new_flags & MNT_READONLY))
			continue;
		if ((mnt->mnt.mnt_flags & MNT_LOCK_NODEV) &&
		if ((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)))
		if ((mnt_flags & MNT_LOCK_NOSUID) &&
		    !(new_flags & MNT_NOSUID))
			continue;
		if ((mnt_flags & MNT_LOCK_NOEXEC) &&
		    !(new_flags & MNT_NOEXEC))
			continue;
		if ((mnt_flags & MNT_LOCK_ATIME) &&
		    ((mnt_flags & MNT_ATIME_MASK) != (new_flags & MNT_ATIME_MASK)))
			continue;

		/* This mount is not fully visible if there are any
@@ -3247,15 +3262,17 @@ static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags)
		list_for_each_entry(child, &mnt->mnt_mounts, mnt_child) {
			struct inode *inode = child->mnt_mountpoint->d_inode;
			/* Only worry about locked mounts */
			if (!(mnt->mnt.mnt_flags & MNT_LOCKED))
			if (!(mnt_flags & MNT_LOCKED))
				continue;
			/* Is the directory permanetly empty? */
			if (!is_empty_dir_inode(inode))
				goto next;
		}
		/* Preserve the locked attributes */
		*new_mnt_flags |= mnt->mnt.mnt_flags & (MNT_LOCK_READONLY | \
		*new_mnt_flags |= mnt_flags & (MNT_LOCK_READONLY | \
					       MNT_LOCK_NODEV    | \
					       MNT_LOCK_NOSUID   | \
					       MNT_LOCK_NOEXEC   | \
					       MNT_LOCK_ATIME);
		visible = true;
		goto found;
+10 −0
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@
#include <linux/proc_ns.h>
#include <linux/magic.h>
#include <linux/ktime.h>
#include <linux/seq_file.h>

static struct vfsmount *nsfs_mnt;

@@ -136,9 +137,18 @@ out_invalid:
	return ERR_PTR(-EINVAL);
}

static int nsfs_show_path(struct seq_file *seq, struct dentry *dentry)
{
	struct inode *inode = d_inode(dentry);
	const struct proc_ns_operations *ns_ops = dentry->d_fsdata;

	return seq_printf(seq, "%s:[%lu]", ns_ops->name, inode->i_ino);
}

static const struct super_operations nsfs_ops = {
	.statfs = simple_statfs,
	.evict_inode = nsfs_evict,
	.show_path = nsfs_show_path,
};
static struct dentry *nsfs_mount(struct file_system_type *fs_type,
			int flags, const char *dev_name, void *data)
+1 −1
Original line number Diff line number Diff line
@@ -377,7 +377,7 @@ retry:
		 * with the "noexec" flag.
		 */
		res = -EACCES;
		if (path.mnt->mnt_flags & MNT_NOEXEC)
		if (path_noexec(&path))
			goto out_path_release;
	}

Loading