Skip to contentSkip to conversation

Making new mounts of proc and sysfs as safe as bind mounts

PATCH In review Eric W. Biederman 16 participants 142 messages May 14, 2015 – Aug 12, 2015 50 messages not in the archive

Subsystems (15)
lore
Share & tools
lore
#0 lore raw

cover Making new mounts of proc and sysfs as safe as bind mounts

The code is currently available at:

git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace.git for-testing

HEAD: a524faf520600968e58bbc732063fccf2fdf9199 mnt: Update fs_fully_visible to test for permanently empty directories

The problem: Mounting a new instance of proc of sysfs can allow things that a bind mount of those filesystems would not.

That is the cases I am dealing with are:
unshare --user --net --mount ; mount -t sysfs ... unshare --user --pid --mount ; mount -t proc ...

The big change is that this set of changes enforces the preservation of locked mount flags, from the existing mount to the current mount. Which means that if proc was mounted read-only the current current will allow a new instance of proc to be mounted read-write, and this set of changes enforces that proc remain read-only.

The other gotcha is that the current code does not properly detect empty directories so to prevent things slipping through the cracks this set of changes annotates all mount points where nothing will be revealed if the filesystem mounted on top is removed.

Enforcing the administrators policy can actually matter in the real world as has been shown by the recent docker issue.

With this patchset I have two concerns:
- The enforcement of mount flag preservation on proc and sysfs may break things. (I am especially worried about the implicit adding of nodev).

- I missed a filesystem mountpoint on proc or sysfs which would make a fresh copy unmountable for no good reason.

I don't want to break userspace if I can help it, and the code has been this way for a while so I figure there is time to find any pitfalls and address them before this code gets merged.

So if this works for you please give me your Tested-By

The well known mountpoints for pseudo filesystems that I could find are:

/dev/ffs*/                 functionfs
/dev/gadget/               gadgetfs
/dev/mqueue                mqueue
/dev/oprofile/             oprofilefs
/dev/pts/                  devpts
/dlm/                      ocfs2_dlmfs
/ipath/                    ipathfs
/proc/fs/nfsd/             nfsd
/proc/openprom/            openpromfs
/proc/sys/fs/binfmt_misc/  binfmt_misc
/spu/                      spufs
/sys/firmware/efi/efivars/ efivarfs
/sys/fs/cgroup/            cgroup
/sys/fs/fuse/connections/  fusectl
/sys/fs/pstore/            pstore
/sys/fs/selinux/           selinuxfs
/sys/fs/smackfs/           smackfs
/sys/hypervisor/s390/      s390_hypfs
/sys/kernel/config/        configfs
/sys/kernel/debug/         debugfs
/sys/kernel/security/      securityfs
/sys/kernel/tracing/       tracefs
/var/lib/ibmasm/           ibmasmfs
/var/lib/nfs/rpc_pipefs/   rpc_pipefs

Eric W. Biederman (10):
mnt: Refactor the logic for mounting sysfs and proc in a user namespace
mnt: Modify fs_fully_visible to deal with mount attributes
vfs: Ignore unlocked mounts in fs_fully_visible
fs: Add helper functions for permanently empty directories.
sysctl: Allow creating permanently empty directories.
proc: Allow creating permanently empty directories.
kernfs: Add support for always empty directories.
sysfs: Add support for permanently empty directories.
sysfs: Create mountpoints with sysfs_create_empty_dir
mnt: Update fs_fully_visible to test for permanently empty directories

 arch/s390/hypfs/inode.c      | 12 ++----
 drivers/firmware/efi/efi.c   |  6 +--
 fs/configfs/mount.c          | 10 ++---
 fs/debugfs/inode.c           | 11 ++---
 fs/fuse/inode.c              |  9 ++---
 fs/kernfs/dir.c              | 38 +++++++++++++++++-
 fs/kernfs/inode.c            |  2 +
 fs/libfs.c                   | 96 ++++++++++++++++++++++++++++++++++++++++++++
 fs/namespace.c               | 47 +++++++++++++++++++---
 fs/proc/generic.c            | 23 +++++++++++
 fs/proc/inode.c              |  3 ++
 fs/proc/internal.h           |  1 +
 fs/proc/proc_sysctl.c        | 37 +++++++++++++++++
 fs/proc/root.c               |  9 ++---
 fs/pstore/inode.c            | 12 ++----
 fs/sysfs/dir.c               | 34 ++++++++++++++++
 fs/sysfs/mount.c             |  5 +--
 fs/tracefs/inode.c           |  6 +--
 include/linux/fs.h           |  4 +-
 include/linux/kernfs.h       |  3 ++
 include/linux/sysctl.h       |  3 ++
 include/linux/sysfs.h        | 16 ++++++++
 kernel/cgroup.c              | 10 ++---
 kernel/sysctl.c              |  8 +---
 security/inode.c             | 10 ++---
 security/selinux/selinuxfs.c | 11 +++--
 security/smack/smackfs.c     |  8 ++--
 27 files changed, 344 insertions(+), 90 deletions(-)

A message that is not in the archive (sent off-list or not yet received): [email protected]

#2 lore raw

PATCH 1/10 mnt: Refactor the logic for mounting sysfs and proc in a user namespace

Fresh mounts of proc and sysfs are a very special case that works very much like a bind mount. Unfortunately the current structure can not preserve the MNT_LOCK... mount flags. Therefore refactor the logic into a form that can be modified to preserve those lock bits.

Add a new filesystem flag FS_USERNS_VISIBLE that requires some mount of the filesystem be fully visible in the current mount namespace, before the filesystem may be mounted.

Move the logic for calling fs_fully_visible from proc and sysfs into fs/namespace.c where it has greater access to mount namespace state.

---
 fs/namespace.c     | 8 +++++++-
 fs/proc/root.c     | 5 +----
 fs/sysfs/mount.c   | 5 +----
 include/linux/fs.h | 2 +-
 4 files changed, 10 insertions(+), 10 deletions(-)
fs/namespace.c +7 -1
index 1b9e11167bae..8e7edaf60fe1 100644
@@ -2332,6 +2332,8 @@ unlock:
 	return err;
 }
 
+static bool fs_fully_visible(struct file_system_type *fs_type);
+
 /*
  * create a new mount for userspace and request it to be added into the
  * namespace's tree
@@ -2363,6 +2365,10 @@ static int do_new_mount(struct path *path, const char *fstype, int flags,
 			flags |= MS_NODEV;
 			mnt_flags |= MNT_NODEV | MNT_LOCK_NODEV;
 		}
+		if (type->fs_flags & FS_USERNS_VISIBLE) {
+			if (!fs_fully_visible(type))
+				return -EPERM;
+		}
 	}
 
 	mnt = vfs_kern_mount(type, flags, name, data);
@@ -3164,7 +3170,7 @@ bool current_chrooted(void)
 	return chrooted;
 }
 
-bool fs_fully_visible(struct file_system_type *type)
+static bool fs_fully_visible(struct file_system_type *type)
 {
 	struct mnt_namespace *ns = current->nsproxy->mnt_ns;
 	struct mount *mnt;
fs/proc/root.c +1 -4
index b7fa4bfe896a..64e1ab64bde6 100644
@@ -112,9 +112,6 @@ static struct dentry *proc_mount(struct file_system_type *fs_type,
 		ns = task_active_pid_ns(current);
 		options = data;
 
-		if (!capable(CAP_SYS_ADMIN) && !fs_fully_visible(fs_type))
-			return ERR_PTR(-EPERM);
-
 		/* Does the mounter have privilege over the pid namespace? */
 		if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN))
 			return ERR_PTR(-EPERM);
@@ -159,7 +156,7 @@ static struct file_system_type proc_fs_type = {
 	.name		= "proc",
 	.mount		= proc_mount,
 	.kill_sb	= proc_kill_sb,
-	.fs_flags	= FS_USERNS_MOUNT,
+	.fs_flags	= FS_USERNS_VISIBLE | FS_USERNS_MOUNT,
 };
 
 void __init proc_root_init(void)
fs/sysfs/mount.c +1 -4
index 8a49486bf30c..1c6ac6fcee9f 100644
@@ -31,9 +31,6 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type,
 	bool new_sb;
 
 	if (!(flags & MS_KERNMOUNT)) {
-		if (!capable(CAP_SYS_ADMIN) && !fs_fully_visible(fs_type))
-			return ERR_PTR(-EPERM);
-
 		if (!kobj_ns_current_may_mount(KOBJ_NS_TYPE_NET))
 			return ERR_PTR(-EPERM);
 	}
@@ -58,7 +55,7 @@ static struct file_system_type sysfs_fs_type = {
 	.name		= "sysfs",
 	.mount		= sysfs_mount,
 	.kill_sb	= sysfs_kill_sb,
-	.fs_flags	= FS_USERNS_MOUNT,
+	.fs_flags	= FS_USERNS_VISIBLE | FS_USERNS_MOUNT,
 };
 
 int __init sysfs_init(void)
include/linux/fs.h +1 -1
index 35ec87e490b1..2d24eeb8e59c 100644
@@ -1897,6 +1897,7 @@ struct file_system_type {
 #define FS_HAS_SUBTYPE		4
 #define FS_USERNS_MOUNT		8	/* Can be mounted by userns root */
 #define FS_USERNS_DEV_MOUNT	16 /* A userns mount does not imply MNT_NODEV */
+#define FS_USERNS_VISIBLE	32	/* FS must already be visible */
 #define FS_RENAME_DOES_D_MOVE	32768	/* FS will handle d_move() during rename() internally. */
 	struct dentry *(*mount) (struct file_system_type *, int,
 		       const char *, void *);
@@ -1984,7 +1985,6 @@ extern int vfs_ustat(dev_t, struct kstatfs *);
 extern int freeze_super(struct super_block *super);
 extern int thaw_super(struct super_block *super);
 extern bool our_mnt(struct vfsmount *mnt);
-extern bool fs_fully_visible(struct file_system_type *);
 
 extern int current_umask(void);
 
Signature · 1 line
2.2.1
#3 lore raw

PATCH 2/10 mnt: Modify fs_fully_visible to deal with mount attributes

In reply to a message not in the archive

Ignore an existing mount if it's locked attributes are less permissive than the new mounts attributes.

On success ensure the new mount locks all of the same attributes as the old mount.

---
 fs/namespace.c | 32 +++++++++++++++++++++++++++++---
 1 file changed, 29 insertions(+), 3 deletions(-)
fs/namespace.c +29 -3
index 8e7edaf60fe1..fccee9924e8c 100644
@@ -2332,7 +2332,7 @@ unlock:
 	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
@@ -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;
 		}
 	}
@@ -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;
 
@@ -3191,6 +3192,25 @@ 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_NOSUID) &&
+		    !(new_flags & MNT_NOSUID))
+			continue;
+		if ((mnt->mnt.mnt_flags & MNT_LOCK_NOEXEC) &&
+		    !(new_flags & MNT_NOEXEC))
+			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.
 		 */
@@ -3201,6 +3221,12 @@ 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_NOSUID   | \
+							MNT_LOCK_NOEXEC   | \
+							MNT_LOCK_ATIME);
 		visible = true;
 		goto found;
 	next:	;
Signature · 1 line
2.2.1
#4 lore raw

PATCH 3/10 vfs: Ignore unlocked mounts in fs_fully_visible

In reply to a message not in the archive

Limit the mounts fs_fully_visible considers to locked mounts. Unlocked can always be unmounted so considering them adds hassle but no security benefit.

---
 fs/namespace.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)
fs/namespace.c +6 -2
index fccee9924e8c..3ede0669b8d2 100644
@@ -3211,11 +3211,15 @@ static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags)
 		    ((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.
+		/* This mount is not fully visible if there are any
+		 * locked child mounts that cover anything except for
+		 * empty directories.
 		 */
 		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))
+				continue;
 			if (!S_ISDIR(inode->i_mode))
 				goto next;
 			if (inode->i_nlink > 2)
Signature · 1 line
2.2.1
#5 lore raw

PATCH 4/10 fs: Add helper functions for permanently empty directories.

In reply to a message not in the archive

To ensure it is safe to mount proc and sysfs I need to check if filesystems that are mounted on top of them are mounted on truly empty directories. Given that some directories can gain entries over time, knowing that a directory is empty right now is insufficient.

Therefore add supporting infrastructure for permantently empty directories that proc and sysfs can use when they create mount points for filesystems and fs_fully_visible can use to test for permanently empty directories to ensure that nothing will be gained by mounting a fresh copy of proc or sysfs.

---
 fs/libfs.c         | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/fs.h |  2 ++
 2 files changed, 98 insertions(+)
fs/libfs.c +96 -0
index cb1fb4b9b637..02813592e121 100644
@@ -1093,3 +1093,99 @@ simple_nosetlease(struct file *filp, long arg, struct file_lock **flp,
 	return -EINVAL;
 }
 EXPORT_SYMBOL(simple_nosetlease);
+
+
+/*
+ * Operations for a permanently empty directory.
+ */
+static struct dentry *empty_dir_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
+{
+	return ERR_PTR(-ENOENT);
+}
+
+static int empty_dir_getattr(struct vfsmount *mnt, struct dentry *dentry,
+				 struct kstat *stat)
+{
+	struct inode *inode = d_inode(dentry);
+	generic_fillattr(inode, stat);
+	return 0;
+}
+
+static int empty_dir_setattr(struct dentry *dentry, struct iattr *attr)
+{
+	return -EPERM;
+}
+
+static int empty_dir_setxattr(struct dentry *dentry, const char *name,
+			      const void *value, size_t size, int flags)
+{
+	return -EOPNOTSUPP;
+}
+
+static ssize_t empty_dir_getxattr(struct dentry *dentry, const char *name,
+				  void *value, size_t size)
+{
+	return -EOPNOTSUPP;
+}
+
+static int empty_dir_removexattr(struct dentry *dentry, const char *name)
+{
+	return -EOPNOTSUPP;
+}
+
+static ssize_t empty_dir_listxattr(struct dentry *dentry, char *list, size_t size)
+{
+	return -EOPNOTSUPP;
+}
+
+static const struct inode_operations empty_dir_inode_operations = {
+	.lookup		= empty_dir_lookup,
+	.permission	= generic_permission,
+	.setattr	= empty_dir_setattr,
+	.getattr	= empty_dir_getattr,
+	.setxattr	= empty_dir_setxattr,
+	.getxattr	= empty_dir_getxattr,
+	.removexattr	= empty_dir_removexattr,
+	.listxattr	= empty_dir_listxattr,
+};
+
+static loff_t empty_dir_llseek(struct file *file, loff_t offset, int whence)
+{
+	/* An empty directory has two entries . and .. at offsets 0 and 1 */
+	return generic_file_llseek_size(file, offset, whence, 2, 2);
+}
+
+static int empty_dir_readdir(struct file *file, struct dir_context *ctx)
+{
+	dir_emit_dots(file, ctx);
+	return 0;
+}
+
+static const struct file_operations empty_dir_operations = {
+	.llseek		= empty_dir_llseek,
+	.read		= generic_read_dir,
+	.iterate	= empty_dir_readdir,
+	.fsync		= noop_fsync,
+};
+
+
+void make_empty_dir_inode(struct inode *inode)
+{
+	set_nlink(inode, 2);
+	inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
+	inode->i_uid = GLOBAL_ROOT_UID;
+	inode->i_gid = GLOBAL_ROOT_GID;
+	inode->i_rdev = 0;
+	inode->i_size = 2;
+	inode->i_blkbits = PAGE_SHIFT;
+	inode->i_blocks = 0;
+
+	inode->i_op = &empty_dir_inode_operations;
+	inode->i_fop = &empty_dir_operations;
+}
+
+bool is_empty_dir_inode(struct inode *inode)
+{
+	return (inode->i_fop == &empty_dir_operations) &&
+		(inode->i_op == &empty_dir_inode_operations);
+}
include/linux/fs.h +2 -0
index 2d24eeb8e59c..571aab91bfc0 100644
@@ -2780,6 +2780,8 @@ extern struct dentry *simple_lookup(struct inode *, struct dentry *, unsigned in
 extern ssize_t generic_read_dir(struct file *, char __user *, size_t, loff_t *);
 extern const struct file_operations simple_dir_operations;
 extern const struct inode_operations simple_dir_inode_operations;
+extern void make_empty_dir_inode(struct inode *inode);
+extern bool is_empty_dir_inode(struct inode *inode);
 struct tree_descr { char *name; const struct file_operations *ops; int mode; };
 struct dentry *d_alloc_name(struct dentry *, const char *);
 extern int simple_fill_super(struct super_block *, unsigned long, struct tree_descr *);
Signature · 1 line
2.2.1
#6 lore raw

PATCH 5/10 sysctl: Allow creating permanently empty directories.

In reply to a message not in the archive

Add a magic sysctl table permanently_empty_table that when used to create a directory forces that directory to be permanently empty.

Update the code to use make_empty_dir_inode when accessing permanently empty directories.

Update the code to not allow adding to permanently empty directories.

Update /proc/sys/fs/binfmt_misc to be a permanently empty directory.

---
 fs/proc/proc_sysctl.c  | 37 +++++++++++++++++++++++++++++++++++++
 include/linux/sysctl.h |  3 +++
 kernel/sysctl.c        |  8 +-------
 3 files changed, 41 insertions(+), 7 deletions(-)
fs/proc/proc_sysctl.c +37 -0
index fea2561d773b..f9ade2caf438 100644
@@ -19,6 +19,28 @@ static const struct inode_operations proc_sys_inode_operations;
 static const struct file_operations proc_sys_dir_file_operations;
 static const struct inode_operations proc_sys_dir_operations;
 
+/* Support for permanently empty directories */
+
+struct ctl_table permanently_empty_table[] = {
+	{ }
+};
+
+static bool is_empty_dir(struct ctl_table_header *head)
+{
+	return head->ctl_table[0].child == permanently_empty_table;
+}
+
+static void set_empty_dir(struct ctl_dir *dir)
+{
+	dir->header.ctl_table[0].child = permanently_empty_table;
+}
+
+static void clear_empty_dir(struct ctl_dir *dir)
+
+{
+	dir->header.ctl_table[0].child = NULL;
+}
+
 void proc_sys_poll_notify(struct ctl_table_poll *poll)
 {
 	if (!poll)
@@ -187,6 +209,17 @@ static int insert_header(struct ctl_dir *dir, struct ctl_table_header *header)
 	struct ctl_table *entry;
 	int err;
 
+	/* Is this a permanently empty directory? */
+	if (is_empty_dir(&dir->header))
+		return -EROFS;
+
+	/* Am I creating a permanently empty directory? */
+	if (header->ctl_table == permanently_empty_table) {
+		if (!RB_EMPTY_ROOT(&dir->root))
+			return -EINVAL;
+		set_empty_dir(dir);
+	}
+
 	dir->header.nreg++;
 	header->parent = dir;
 	err = insert_links(header);
@@ -202,6 +235,8 @@ fail:
 	erase_header(header);
 	put_links(header);
 fail_links:
+	if (header->ctl_table == permanently_empty_table)
+		clear_empty_dir(dir);
 	header->parent = NULL;
 	drop_sysctl_table(&dir->header);
 	return err;
@@ -419,6 +454,8 @@ static struct inode *proc_sys_make_inode(struct super_block *sb,
 		inode->i_mode |= S_IFDIR;
 		inode->i_op = &proc_sys_dir_operations;
 		inode->i_fop = &proc_sys_dir_file_operations;
+		if (is_empty_dir(head))
+			make_empty_dir_inode(inode);
 	}
 out:
 	return inode;
include/linux/sysctl.h +3 -0
index 795d5fea5697..71fd81994a82 100644
@@ -188,6 +188,9 @@ struct ctl_table_header *register_sysctl_paths(const struct ctl_path *path,
 void unregister_sysctl_table(struct ctl_table_header * table);
 
 extern int sysctl_init(void);
+
+extern struct ctl_table permanently_empty_table[];
+
 #else /* CONFIG_SYSCTL */
 static inline struct ctl_table_header *register_sysctl_table(struct ctl_table * table)
 {
kernel/sysctl.c +1 -7
index 2082b1a88fb9..92f41a43875e 100644
@@ -1531,12 +1531,6 @@ static struct ctl_table vm_table[] = {
 	{ }
 };
 
-#if defined(CONFIG_BINFMT_MISC) || defined(CONFIG_BINFMT_MISC_MODULE)
-static struct ctl_table binfmt_misc_table[] = {
-	{ }
-};
-#endif
-
 static struct ctl_table fs_table[] = {
 	{
 		.procname	= "inode-nr",
@@ -1690,7 +1684,7 @@ static struct ctl_table fs_table[] = {
 	{
 		.procname	= "binfmt_misc",
 		.mode		= 0555,
-		.child		= binfmt_misc_table,
+		.child		= permanently_empty_table,
 	},
 #endif
 	{
Signature · 1 line
2.2.1
#7 lore raw

PATCH 6/10 proc: Allow creating permanently empty directories.

In reply to a message not in the archive

Add a new function proc_mk_empty_dir that when used to creates a directory that can not be added to.

Update the code to use make_empty_dir_inode when reporting a permanently empty directory to the vfs.

Update the code to not allow adding to permanently empty directories.

Update /proc/openprom and /proc/fs/nfsd to be permanently empty directories.

---
 fs/proc/generic.c  | 23 +++++++++++++++++++++++
 fs/proc/inode.c    |  3 +++
 fs/proc/internal.h |  1 +
 fs/proc/root.c     |  4 ++--
 4 files changed, 29 insertions(+), 2 deletions(-)
fs/proc/generic.c +23 -0
index df6327a2b865..e235c1544b22 100644
@@ -373,6 +373,10 @@ static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent,
 		WARN(1, "create '/proc/%s' by hand\n", qstr.name);
 		return NULL;
 	}
+	if (S_ISDIR((*parent)->mode) && ((*parent)->proc_fops == NULL)) {
+		WARN(1, "attempt to add to permanently empty directory");
+		return NULL;
+	}
 
 	ent = kzalloc(sizeof(struct proc_dir_entry) + qstr.len + 1, GFP_KERNEL);
 	if (!ent)
@@ -455,6 +459,25 @@ struct proc_dir_entry *proc_mkdir(const char *name,
 }
 EXPORT_SYMBOL(proc_mkdir);
 
+struct proc_dir_entry *proc_mk_empty_dir(const char *name)
+{
+	umode_t mode = S_IFDIR | S_IRUGO | S_IXUGO;
+	struct proc_dir_entry *ent, *parent = NULL;
+
+	ent = __proc_create(&parent, name, mode, 2);
+	if (ent) {
+		ent->data = NULL;
+		ent->proc_fops = NULL;
+		ent->proc_iops = NULL;
+		if (proc_register(parent, ent) < 0) {
+			kfree(ent);
+			parent->nlink--;
+			ent = NULL;
+		}
+	}
+	return ent;
+}
+
 struct proc_dir_entry *proc_create_data(const char *name, umode_t mode,
 					struct proc_dir_entry *parent,
 					const struct file_operations *proc_fops,
fs/proc/inode.c +3 -0
index 8272aaba1bb0..b957ec618bda 100644
@@ -445,6 +445,9 @@ struct inode *proc_get_inode(struct super_block *sb, struct proc_dir_entry *de)
 					inode->i_fop = &proc_reg_file_ops;
 			} else {
 				inode->i_fop = de->proc_fops;
+				if (S_ISDIR(inode->i_mode) &&
+				    (de->proc_fops == NULL))
+					make_empty_dir_inode(inode);
 			}
 		}
 	} else
fs/proc/internal.h +1 -0
index c835b94c0cd3..6bc2e7a12912 100644
@@ -190,6 +190,7 @@ static inline struct proc_dir_entry *pde_get(struct proc_dir_entry *pde)
 	return pde;
 }
 extern void pde_put(struct proc_dir_entry *);
+struct proc_dir_entry *proc_mk_empty_dir(const char *name);
 
 /*
  * inode.c
fs/proc/root.c +2 -2
index 64e1ab64bde6..b031fc3991c3 100644
@@ -179,10 +179,10 @@ void __init proc_root_init(void)
 #endif
 	proc_mkdir("fs", NULL);
 	proc_mkdir("driver", NULL);
-	proc_mkdir("fs/nfsd", NULL); /* somewhere for the nfsd filesystem to be mounted */
+	proc_mk_empty_dir("fs/nfsd"); /* somewhere for the nfsd filesystem to be mounted */
 #if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE)
 	/* just give it a mountpoint */
-	proc_mkdir("openprom", NULL);
+	proc_mk_empty_dir("openprom");
 #endif
 	proc_tty_init();
 	proc_mkdir("bus", NULL);
Signature · 1 line
2.2.1
#8 lore raw

PATCH 7/10 kernfs: Add support for always empty directories.

In reply to a message not in the archive

Add a new function kernfs_create_empty_dir that can be used to create directory that can not be modified.

Update the code to use make_empty_dir_inode when reporting a permanently empty directory to the vfs.

Update the code to not allow adding to permanently empty directories.

---
 fs/kernfs/dir.c        | 38 +++++++++++++++++++++++++++++++++++++-
 fs/kernfs/inode.c      |  2 ++
 include/linux/kernfs.h |  3 +++
 3 files changed, 42 insertions(+), 1 deletion(-)
fs/kernfs/dir.c +37 -1
index f131fc23ffc4..8643e70536f8 100644
@@ -585,6 +585,9 @@ int kernfs_add_one(struct kernfs_node *kn)
 		goto out_unlock;
 
 	ret = -ENOENT;
+	if (parent->flags & KERNFS_EMPTY_DIR)
+		goto out_unlock;
+
 	if ((parent->flags & KERNFS_ACTIVATED) && !kernfs_active(parent))
 		goto out_unlock;
 
@@ -776,6 +779,38 @@ struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent,
 	return ERR_PTR(rc);
 }
 
+/**
+ * kernfs_create_empty_dir - create an always empty directory
+ * @parent: parent in which to create a new directory
+ * @name: name of the new directory
+ *
+ * Returns the created node on success, ERR_PTR() value on failure.
+ */
+struct kernfs_node *kernfs_create_empty_dir(struct kernfs_node *parent,
+					    const char *name, void *priv)
+{
+	struct kernfs_node *kn;
+	int rc;
+
+	/* allocate */
+	kn = kernfs_new_node(parent, name, S_IRUGO|S_IXUGO|S_IFDIR, KERNFS_DIR);
+	if (!kn)
+		return ERR_PTR(-ENOMEM);
+
+	kn->flags |= KERNFS_EMPTY_DIR;
+	kn->dir.root = parent->dir.root;
+	kn->ns = NULL;
+	kn->priv = priv;
+
+	/* link in */
+	rc = kernfs_add_one(kn);
+	if (!rc)
+		return kn;
+
+	kernfs_put(kn);
+	return ERR_PTR(rc);
+}
+
 static struct dentry *kernfs_iop_lookup(struct inode *dir,
 					struct dentry *dentry,
 					unsigned int flags)
@@ -1247,7 +1282,8 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent,
 	mutex_lock(&kernfs_mutex);
 
 	error = -ENOENT;
-	if (!kernfs_active(kn) || !kernfs_active(new_parent))
+	if (!kernfs_active(kn) || !kernfs_active(new_parent) ||
+	    (new_parent->flags & KERNFS_EMPTY_DIR))
 		goto out;
 
 	error = 0;
fs/kernfs/inode.c +2 -0
index 2da8493a380b..756dd56aaf60 100644
@@ -296,6 +296,8 @@ static void kernfs_init_inode(struct kernfs_node *kn, struct inode *inode)
 	case KERNFS_DIR:
 		inode->i_op = &kernfs_dir_iops;
 		inode->i_fop = &kernfs_dir_fops;
+		if (kn->flags & KERNFS_EMPTY_DIR)
+			make_empty_dir_inode(inode);
 		break;
 	case KERNFS_FILE:
 		inode->i_size = kn->attr.size;
include/linux/kernfs.h +3 -0
index 71ecdab1671b..4b479a0b3d61 100644
@@ -45,6 +45,7 @@ enum kernfs_node_flag {
 	KERNFS_LOCKDEP		= 0x0100,
 	KERNFS_SUICIDAL		= 0x0400,
 	KERNFS_SUICIDED		= 0x0800,
+	KERNFS_EMPTY_DIR	= 0x1000,
 };
 
 /* @flags for kernfs_create_root() */
@@ -285,6 +286,8 @@ void kernfs_destroy_root(struct kernfs_root *root);
 struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent,
 					 const char *name, umode_t mode,
 					 void *priv, const void *ns);
+struct kernfs_node *kernfs_create_empty_dir(struct kernfs_node *parent,
+					    const char *name, void *priv);
 struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent,
 					 const char *name,
 					 umode_t mode, loff_t size,
Signature · 1 line
2.2.1
#9 lore raw

PATCH 8/10 sysfs: Add support for permanently empty directories.

In reply to a message not in the archive

Add two functions sysfs_create_empty_dir and sysfs_remove_empty_dir that hang a permanently empty directory off of a kobject or remove a permanently emptpy directory hanging from a kobject. Export these new functions so modular filesystems can use them.

As all permanently empty directories are, are names and used for mouting other filesystems this seems like the right abstraction.

---
 fs/sysfs/dir.c        | 34 ++++++++++++++++++++++++++++++++++
 include/linux/sysfs.h | 16 ++++++++++++++++
 2 files changed, 50 insertions(+)
fs/sysfs/dir.c +34 -0
index 0b45ff42f374..8244741474d7 100644
@@ -121,3 +121,37 @@ int sysfs_move_dir_ns(struct kobject *kobj, struct kobject *new_parent_kobj,
 
 	return kernfs_rename_ns(kn, new_parent, kn->name, new_ns);
 }
+
+/**
+ * sysfs_create_empty_dir - create an always empty directory
+ * @parent_kobj:  kobject that will contain this always empty directory
+ * @name: The name of the always empty directory to add
+ */
+int sysfs_create_empty_dir(struct kobject *parent_kobj, const char *name)
+{
+	struct kernfs_node *kn, *parent = parent_kobj->sd;
+
+	kn = kernfs_create_empty_dir(parent, name, NULL);
+	if (IS_ERR(kn)) {
+		if (PTR_ERR(kn) == -EEXIST)
+			sysfs_warn_dup(parent, name);
+		return PTR_ERR(kn);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(sysfs_create_empty_dir);
+
+/**
+ *	sysfs_remove_empty_dir - remove an always empty directory.
+ *	@parent_kobj: kobject that will contain this always empty directory
+ *	@name: The name of the always empty directory to remove
+ *
+ */
+void sysfs_remove_empty_dir(struct kobject *parent_kobj, const char *name)
+{
+	struct kernfs_node *parent = parent_kobj->sd;
+
+	kernfs_remove_by_name_ns(parent, name, NULL);
+}
+EXPORT_SYMBOL_GPL(sysfs_remove_empty_dir);
include/linux/sysfs.h +16 -0
index 99382c0df17e..e156d419de75 100644
@@ -210,6 +210,10 @@ int __must_check sysfs_rename_dir_ns(struct kobject *kobj, const char *new_name,
 int __must_check sysfs_move_dir_ns(struct kobject *kobj,
 				   struct kobject *new_parent_kobj,
 				   const void *new_ns);
+int __must_check sysfs_create_empty_dir(struct kobject *parent_kobj,
+					const char *name);
+void sysfs_remove_empty_dir(struct kobject *parent_kobj,
+			    const char *name);
 
 int __must_check sysfs_create_file_ns(struct kobject *kobj,
 				      const struct attribute *attr,
@@ -298,6 +302,18 @@ static inline int sysfs_move_dir_ns(struct kobject *kobj,
 	return 0;
 }
 
+static inline int sysfs_create_empty_dir(struct kobject *parent_kobj,
+					 const char *name)
+{
+	return 0;
+}
+
+static inline void sysfs_remove_empty_dir(struct kobject *parent_kobj,
+					  const char *name)
+{
+	return 0;
+}
+
 static inline int sysfs_create_file_ns(struct kobject *kobj,
 				       const struct attribute *attr,
 				       const void *ns)
Signature · 1 line
2.2.1

A message that is not in the archive (sent off-list or not yet received): [email protected]

#11 lore raw

Re: [CFT][PATCH 08/10] sysfs: Add support for permanently empty directories.

Quoted 8 lines · Eric W. Biederman

Add two functions sysfs_create_empty_dir and sysfs_remove_empty_dir that hang a permanently empty directory off of a kobject or remove a permanently emptpy directory hanging from a kobject. Export these new functions so modular filesystems can use them.

As all permanently empty directories are, are names and used for mouting other filesystems this seems like the right abstraction.

That sentence doesn't make much sense, cut and paste?

Quoted 13 lines
---
 fs/sysfs/dir.c        | 34 ++++++++++++++++++++++++++++++++++
 include/linux/sysfs.h | 16 ++++++++++++++++
 2 files changed, 50 insertions(+)
fs/sysfs/dir.c +0 -0
index 0b45ff42f374..8244741474d7 100644

fs/sysfs/dir.c int sysfs_move_dir_ns(struct kobject *kobj, struct kobject *new_parent_kobj, · line 130

Quoted 10 lines
fs/sysfs/dir.c +7 -0
@@ -121,3 +121,37 @@ int sysfs_move_dir_ns(struct kobject *kobj, struct kobject *new_parent_kobj,
 
 	return kernfs_rename_ns(kn, new_parent, kn->name, new_ns);
 }
+
+/**
+ * sysfs_create_empty_dir - create an always empty directory
+ * @parent_kobj:  kobject that will contain this always empty directory
+ * @name: The name of the always empty directory to add
+ */
+int sysfs_create_empty_dir(struct kobject *parent_kobj, const char *name)

As this really is just a mount point, how about we be explicit with this and call the function:
sysfs_create_mount_point() sysfs_remove_mount_point()
That makes more sense in the long run, otherwise if you just want to create an empty directory in sysfs, you can do so without making an "empty" kobject and some people might do that accidentally in the future. This makes it more obvious as to what is going on.

thanks,

greg k-h

A message that is not in the archive (sent off-list or not yet received): [email protected]

#13 lore raw

Re: [CFT][PATCH 08/10] sysfs: Add support for permanently empty directories.

Quoted 11 lines · Greg Kroah-Hartman
Quoted 8 lines · Eric W. Biederman

Add two functions sysfs_create_empty_dir and sysfs_remove_empty_dir that hang a permanently empty directory off of a kobject or remove a permanently emptpy directory hanging from a kobject. Export these new functions so modular filesystems can use them.

As all permanently empty directories are, are names and used for mouting other filesystems this seems like the right abstraction.

That sentence doesn't make much sense, cut and paste?

Probably one edit too many or too few depending on how you look at it.

What I meant is that since the only interesting thing about a permanently empty directory is it's name, treating them like sysfs files rather than normal sysfs directories which require a kobject seems like the right abstraction.

Quoted 23 lines
Quoted 12 lines
---
 fs/sysfs/dir.c        | 34 ++++++++++++++++++++++++++++++++++
 include/linux/sysfs.h | 16 ++++++++++++++++
 2 files changed, 50 insertions(+)
fs/sysfs/dir.c +0 -0
index 0b45ff42f374..8244741474d7 100644

fs/sysfs/dir.c int sysfs_move_dir_ns(struct kobject *kobj, struct kobject *new_parent_kobj, · line 130

Quoted 10 lines
fs/sysfs/dir.c +7 -0
@@ -121,3 +121,37 @@ int sysfs_move_dir_ns(struct kobject *kobj, struct kobject *new_parent_kobj,
 
 	return kernfs_rename_ns(kn, new_parent, kn->name, new_ns);
 }
+
+/**
+ * sysfs_create_empty_dir - create an always empty directory
+ * @parent_kobj:  kobject that will contain this always empty directory
+ * @name: The name of the always empty directory to add
+ */
+int sysfs_create_empty_dir(struct kobject *parent_kobj, const char *name)
Quoted 8 lines

As this really is just a mount point, how about we be explicit with this and call the function:
sysfs_create_mount_point() sysfs_remove_mount_point()
That makes more sense in the long run, otherwise if you just want to create an empty directory in sysfs, you can do so without making an "empty" kobject and some people might do that accidentally in the future. This makes it more obvious as to what is going on.

Yeah. That seems fairly reasonable.

My brain is on the edge between the functional description of creating a permanently empty directory, and the usage based description (creating a directory to mount filesystems on).

But I agree a name that makes it totally obvious we are creating a directory to mount something on is going to be more usable and comprehensible.

My head doesn't like sysfs_create_mount_point() as a mount point can be a file. But I will put it on the back burner and see if I can come up with something better, and if not sysfs_create_mount_point it is.

Brainstorming:

sysfs_create_expected_mount_point()
sysfs_reserve_dir_for_mount()
sysfs_create_dir_mount_point()
sysfs_create_expected_mount_point()

Partly I think I would like to rename the proc, sysctl and infrastructure bit as well (consistency and clarity is good).

Where I get stuck is how do I ask the question:
I see this directory is a mount point, is it a directory whose sole purpose in life is to be a mount point?

In the context of that question I like my naming of empty_dir as it conveys what I am interested in.

But I like the sysfs_create_mount_point for general use. Maybe I won't make my names consistent.

I don't know. I am putting this naming question on the back burner for a bit.

Eric

#14 lore raw

Re: [CFT][PATCH 08/10] sysfs: Add support for permanently empty directories.

In reply to a message not in the archive
Quoted 11 lines · Greg Kroah-Hartman
Quoted 8 lines · Eric W. Biederman

Add two functions sysfs_create_empty_dir and sysfs_remove_empty_dir that hang a permanently empty directory off of a kobject or remove a permanently emptpy directory hanging from a kobject. Export these new functions so modular filesystems can use them.

As all permanently empty directories are, are names and used for mouting other filesystems this seems like the right abstraction.

That sentence doesn't make much sense, cut and paste?

Probably one edit too many or too few depending on how you look at it.

What I meant is that since the only interesting thing about a permanently empty directory is it's name, treating them like sysfs files rather than normal sysfs directories which require a kobject seems like the right abstraction.

Quoted 23 lines
Quoted 12 lines
---
 fs/sysfs/dir.c        | 34 ++++++++++++++++++++++++++++++++++
 include/linux/sysfs.h | 16 ++++++++++++++++
 2 files changed, 50 insertions(+)
fs/sysfs/dir.c +0 -0
index 0b45ff42f374..8244741474d7 100644

fs/sysfs/dir.c int sysfs_move_dir_ns(struct kobject *kobj, struct kobject *new_parent_kobj, · line 130

Quoted 10 lines
fs/sysfs/dir.c +7 -0
@@ -121,3 +121,37 @@ int sysfs_move_dir_ns(struct kobject *kobj, struct kobject *new_parent_kobj,
 
 	return kernfs_rename_ns(kn, new_parent, kn->name, new_ns);
 }
+
+/**
+ * sysfs_create_empty_dir - create an always empty directory
+ * @parent_kobj:  kobject that will contain this always empty directory
+ * @name: The name of the always empty directory to add
+ */
+int sysfs_create_empty_dir(struct kobject *parent_kobj, const char *name)
Quoted 8 lines

As this really is just a mount point, how about we be explicit with this and call the function:
sysfs_create_mount_point() sysfs_remove_mount_point()
That makes more sense in the long run, otherwise if you just want to create an empty directory in sysfs, you can do so without making an "empty" kobject and some people might do that accidentally in the future. This makes it more obvious as to what is going on.

Yeah. That seems fairly reasonable.

My brain is on the edge between the functional description of creating a permanently empty directory, and the usage based description (creating a directory to mount filesystems on).

But I agree a name that makes it totally obvious we are creating a directory to mount something on is going to be more usable and comprehensible.

My head doesn't like sysfs_create_mount_point() as a mount point can be a file. But I will put it on the back burner and see if I can come up with something better, and if not sysfs_create_mount_point it is.

Brainstorming:

sysfs_create_expected_mount_point()
sysfs_reserve_dir_for_mount()
sysfs_create_dir_mount_point()
sysfs_create_expected_mount_point()

Partly I think I would like to rename the proc, sysctl and infrastructure bit as well (consistency and clarity is good).

Where I get stuck is how do I ask the question:
I see this directory is a mount point, is it a directory whose sole purpose in life is to be a mount point?

In the context of that question I like my naming of empty_dir as it conveys what I am interested in.

But I like the sysfs_create_mount_point for general use. Maybe I won't make my names consistent.

I don't know. I am putting this naming question on the back burner for a bit.

Eric

#15 lore raw

Re: [CFT][PATCH 08/10] sysfs: Add support for permanently empty directories.

In reply to a message not in the archive
Quoted 8 lines · Eric W. Biederman

Add two functions sysfs_create_empty_dir and sysfs_remove_empty_dir that hang a permanently empty directory off of a kobject or remove a permanently emptpy directory hanging from a kobject. Export these new functions so modular filesystems can use them.

As all permanently empty directories are, are names and used for mouting other filesystems this seems like the right abstraction.

That sentence doesn't make much sense, cut and paste?

Quoted 13 lines
---
 fs/sysfs/dir.c        | 34 ++++++++++++++++++++++++++++++++++
 include/linux/sysfs.h | 16 ++++++++++++++++
 2 files changed, 50 insertions(+)
fs/sysfs/dir.c +0 -0
index 0b45ff42f374..8244741474d7 100644

fs/sysfs/dir.c int sysfs_move_dir_ns(struct kobject *kobj, struct kobject *new_parent_kobj, · line 130

Quoted 10 lines
fs/sysfs/dir.c +7 -0
@@ -121,3 +121,37 @@ int sysfs_move_dir_ns(struct kobject *kobj, struct kobject *new_parent_kobj,
 
 	return kernfs_rename_ns(kn, new_parent, kn->name, new_ns);
 }
+
+/**
+ * sysfs_create_empty_dir - create an always empty directory
+ * @parent_kobj:  kobject that will contain this always empty directory
+ * @name: The name of the always empty directory to add
+ */
+int sysfs_create_empty_dir(struct kobject *parent_kobj, const char *name)

As this really is just a mount point, how about we be explicit with this and call the function:
sysfs_create_mount_point() sysfs_remove_mount_point()
That makes more sense in the long run, otherwise if you just want to create an empty directory in sysfs, you can do so without making an "empty" kobject and some people might do that accidentally in the future. This makes it more obvious as to what is going on.

thanks,

greg k-h

#16 lore raw

PATCH 9/10 sysfs: Create mountpoints with sysfs_create_empty_dir

In reply to a message not in the archive

This allows for better documentation in the code and it allows for a simpler and fully correct version of fs_fully_visible to be written.

The mount points converted and their filesystems are:

/sys/hypervisor/s390/       s390_hypfs
/sys/kernel/config/         configfs
/sys/kernel/debug/          debugfs
/sys/firmware/efi/efivars/  efivarfs
/sys/fs/fuse/connections/   fusectl
/sys/fs/pstore/             pstore
/sys/kernel/tracing/        tracefs
/sys/fs/cgroup/             cgroup
/sys/kernel/security/       securityfs
/sys/fs/selinux/            selinuxfs
/sys/fs/smackfs/            smackfs
---
 arch/s390/hypfs/inode.c      | 12 ++++--------
 drivers/firmware/efi/efi.c   |  6 ++----
 fs/configfs/mount.c          | 10 ++++------
 fs/debugfs/inode.c           | 11 ++++-------
 fs/fuse/inode.c              |  9 +++------
 fs/pstore/inode.c            | 12 ++++--------
 fs/tracefs/inode.c           |  6 ++----
 kernel/cgroup.c              | 10 ++++------
 security/inode.c             | 10 ++++------
 security/selinux/selinuxfs.c | 11 +++++------
 security/smack/smackfs.c     |  8 ++++----
 11 files changed, 40 insertions(+), 65 deletions(-)
arch/s390/hypfs/inode.c +4 -8
index d3f896a35b98..d943d36076cc 100644
@@ -456,8 +456,6 @@ static const struct super_operations hypfs_s_ops = {
 	.show_options	= hypfs_show_options,
 };
 
-static struct kobject *s390_kobj;
-
 static int __init hypfs_init(void)
 {
 	int rc;
@@ -481,18 +479,16 @@ static int __init hypfs_init(void)
 		rc = -ENODATA;
 		goto fail_hypfs_sprp_exit;
 	}
-	s390_kobj = kobject_create_and_add("s390", hypervisor_kobj);
-	if (!s390_kobj) {
-		rc = -ENOMEM;
+	rc = sysfs_create_empty_dir(hypervisor_kobj, "s390");
+	if (rc)
 		goto fail_hypfs_diag0c_exit;
-	}
 	rc = register_filesystem(&hypfs_type);
 	if (rc)
 		goto fail_filesystem;
 	return 0;
 
 fail_filesystem:
-	kobject_put(s390_kobj);
+	sysfs_remove_empty_dir(hypervisor_kobj, "s390");
 fail_hypfs_diag0c_exit:
 	hypfs_diag0c_exit();
 fail_hypfs_sprp_exit:
@@ -510,7 +506,7 @@ fail_dbfs_exit:
 static void __exit hypfs_exit(void)
 {
 	unregister_filesystem(&hypfs_type);
-	kobject_put(s390_kobj);
+	sysfs_remove_empty_dir(hypervisor_kobj, "s390");
 	hypfs_diag0c_exit();
 	hypfs_sprp_exit();
 	hypfs_vm_exit();
drivers/firmware/efi/efi.c +2 -4
index 3061bb8629dc..98523650efd9 100644
@@ -65,7 +65,6 @@ static int __init parse_efi_cmdline(char *str)
 early_param("efi", parse_efi_cmdline);
 
 static struct kobject *efi_kobj;
-static struct kobject *efivars_kobj;
 
 /*
  * Let's not leave out systab information that snuck into
@@ -212,10 +211,9 @@ static int __init efisubsys_init(void)
 		goto err_remove_group;
 
 	/* and the standard mountpoint for efivarfs */
-	efivars_kobj = kobject_create_and_add("efivars", efi_kobj);
-	if (!efivars_kobj) {
+	error = sysfs_create_empty_dir(efi_kobj, "efivars");
+	if (error) {
 		pr_err("efivars: Subsystem registration failed.\n");
-		error = -ENOMEM;
 		goto err_remove_group;
 	}
 
fs/configfs/mount.c +4 -6
index da94e41bdbf6..b4d1580a6602 100644
@@ -129,8 +129,6 @@ void configfs_release_fs(void)
 }
 
 
-static struct kobject *config_kobj;
-
 static int __init configfs_init(void)
 {
 	int err = -ENOMEM;
@@ -141,8 +139,8 @@ static int __init configfs_init(void)
 	if (!configfs_dir_cachep)
 		goto out;
 
-	config_kobj = kobject_create_and_add("config", kernel_kobj);
-	if (!config_kobj)
+	err = sysfs_create_empty_dir(kernel_kobj, "config");
+	if (err)
 		goto out2;
 
 	err = register_filesystem(&configfs_fs_type);
@@ -152,7 +150,7 @@ static int __init configfs_init(void)
 	return 0;
 out3:
 	pr_err("Unable to register filesystem!\n");
-	kobject_put(config_kobj);
+	sysfs_remove_empty_dir(kernel_kobj, "config");
 out2:
 	kmem_cache_destroy(configfs_dir_cachep);
 	configfs_dir_cachep = NULL;
@@ -163,7 +161,7 @@ out:
 static void __exit configfs_exit(void)
 {
 	unregister_filesystem(&configfs_fs_type);
-	kobject_put(config_kobj);
+	sysfs_remove_empty_dir(kernel_kobj, "config");
 	kmem_cache_destroy(configfs_dir_cachep);
 	configfs_dir_cachep = NULL;
 }
fs/debugfs/inode.c +4 -7
index c1e7ffb0dab6..5bcb499980d0 100644
@@ -716,20 +716,17 @@ bool debugfs_initialized(void)
 }
 EXPORT_SYMBOL_GPL(debugfs_initialized);
 
-
-static struct kobject *debug_kobj;
-
 static int __init debugfs_init(void)
 {
 	int retval;
 
-	debug_kobj = kobject_create_and_add("debug", kernel_kobj);
-	if (!debug_kobj)
-		return -EINVAL;
+	retval = sysfs_create_empty_dir(kernel_kobj, "debug");
+	if (retval)
+		return retval;
 
 	retval = register_filesystem(&debug_fs_type);
 	if (retval)
-		kobject_put(debug_kobj);
+		sysfs_remove_empty_dir(kernel_kobj, "debug");
 	else
 		debugfs_registered = true;
 
fs/fuse/inode.c +3 -6
index 082ac1c97f39..475d9cfa59a9 100644
@@ -1238,7 +1238,6 @@ static void fuse_fs_cleanup(void)
 }
 
 static struct kobject *fuse_kobj;
-static struct kobject *connections_kobj;
 
 static int fuse_sysfs_init(void)
 {
@@ -1250,11 +1249,9 @@ static int fuse_sysfs_init(void)
 		goto out_err;
 	}
 
-	connections_kobj = kobject_create_and_add("connections", fuse_kobj);
-	if (!connections_kobj) {
-		err = -ENOMEM;
+	err = sysfs_create_empty_dir(fuse_kobj, "connections");
+	if (err)
 		goto out_fuse_unregister;
-	}
 
 	return 0;
 
@@ -1266,7 +1263,7 @@ static int fuse_sysfs_init(void)
 
 static void fuse_sysfs_cleanup(void)
 {
-	kobject_put(connections_kobj);
+	sysfs_remove_empty_dir(fuse_kobj, "connections");
 	kobject_put(fuse_kobj);
 }
 
fs/pstore/inode.c +4 -8
index dc43b5f29305..d1caeefd2d1b 100644
@@ -461,22 +461,18 @@ static struct file_system_type pstore_fs_type = {
 	.kill_sb	= pstore_kill_sb,
 };
 
-static struct kobject *pstore_kobj;
-
 static int __init init_pstore_fs(void)
 {
-	int err = 0;
+	int err;
 
 	/* Create a convenient mount point for people to access pstore */
-	pstore_kobj = kobject_create_and_add("pstore", fs_kobj);
-	if (!pstore_kobj) {
-		err = -ENOMEM;
+	err = sysfs_create_empty_dir(fs_kobj, "pstore");
+	if (err)
 		goto out;
-	}
 
 	err = register_filesystem(&pstore_fs_type);
 	if (err < 0)
-		kobject_put(pstore_kobj);
+		sysfs_remove_empty_dir(fs_kobj, "pstore");
 
 out:
 	return err;
fs/tracefs/inode.c +2 -4
index d92bdf3b079a..e887c881a4b3 100644
@@ -631,14 +631,12 @@ bool tracefs_initialized(void)
 	return tracefs_registered;
 }
 
-static struct kobject *trace_kobj;
-
 static int __init tracefs_init(void)
 {
 	int retval;
 
-	trace_kobj = kobject_create_and_add("tracing", kernel_kobj);
-	if (!trace_kobj)
+	retval = sysfs_create_empty_dir(kernel_kobj, "tracing");
+	if (retval)
 		return -EINVAL;
 
 	retval = register_filesystem(&trace_fs_type);
kernel/cgroup.c +4 -6
index 469dd547770c..816657b5ef16 100644
@@ -1924,8 +1924,6 @@ static struct file_system_type cgroup_fs_type = {
 	.kill_sb = cgroup_kill_sb,
 };
 
-static struct kobject *cgroup_kobj;
-
 /**
  * task_cgroup_path - cgroup path of a task in the first cgroup hierarchy
  * @task: target task
@@ -5044,13 +5042,13 @@ int __init cgroup_init(void)
 			ss->bind(init_css_set.subsys[ssid]);
 	}
 
-	cgroup_kobj = kobject_create_and_add("cgroup", fs_kobj);
-	if (!cgroup_kobj)
-		return -ENOMEM;
+	err = sysfs_create_empty_dir(fs_kobj, "cgroup");
+	if (err)
+		return err;
 
 	err = register_filesystem(&cgroup_fs_type);
 	if (err < 0) {
-		kobject_put(cgroup_kobj);
+		sysfs_remove_empty_dir(fs_kobj, "cgroup");
 		return err;
 	}
 
security/inode.c +4 -6
index 91503b79c5f8..d7e5de5ffc59 100644
@@ -215,19 +215,17 @@ void securityfs_remove(struct dentry *dentry)
 }
 EXPORT_SYMBOL_GPL(securityfs_remove);
 
-static struct kobject *security_kobj;
-
 static int __init securityfs_init(void)
 {
 	int retval;
 
-	security_kobj = kobject_create_and_add("security", kernel_kobj);
-	if (!security_kobj)
-		return -EINVAL;
+	retval = sysfs_create_empty_dir(kernel_kobj, "security");
+	if (retval)
+		return retval;
 
 	retval = register_filesystem(&fs_type);
 	if (retval)
-		kobject_put(security_kobj);
+		sysfs_remove_empty_dir(kernel_kobj, "security");
 	return retval;
 }
 
security/selinux/selinuxfs.c +5 -6
index d2787cca1fcb..a3d882729a45 100644
@@ -1853,7 +1853,6 @@ static struct file_system_type sel_fs_type = {
 };
 
 struct vfsmount *selinuxfs_mount;
-static struct kobject *selinuxfs_kobj;
 
 static int __init init_sel_fs(void)
 {
@@ -1862,13 +1861,13 @@ static int __init init_sel_fs(void)
 	if (!selinux_enabled)
 		return 0;
 
-	selinuxfs_kobj = kobject_create_and_add("selinux", fs_kobj);
-	if (!selinuxfs_kobj)
-		return -ENOMEM;
+	err = sysfs_create_empty_dir(fs_kobj, "selinux");
+	if (err)
+		return err;
 
 	err = register_filesystem(&sel_fs_type);
 	if (err) {
-		kobject_put(selinuxfs_kobj);
+		sysfs_remove_empty_dir(fs_kobj, "selinux");
 		return err;
 	}
 
@@ -1887,7 +1886,7 @@ __initcall(init_sel_fs);
 #ifdef CONFIG_SECURITY_SELINUX_DISABLE
 void exit_sel_fs(void)
 {
-	kobject_put(selinuxfs_kobj);
+	sysfs_remove_empty_dir(fs_kobj, "selinux");
 	kern_unmount(selinuxfs_mount);
 	unregister_filesystem(&sel_fs_type);
 }
security/smack/smackfs.c +4 -4
index d9682985349e..35079cc8c765 100644
@@ -2241,16 +2241,16 @@ static const struct file_operations smk_revoke_subj_ops = {
 	.llseek		= generic_file_llseek,
 };
 
-static struct kset *smackfs_kset;
 /**
  * smk_init_sysfs - initialize /sys/fs/smackfs
  *
  */
 static int smk_init_sysfs(void)
 {
-	smackfs_kset = kset_create_and_add("smackfs", NULL, fs_kobj);
-	if (!smackfs_kset)
-		return -ENOMEM;
+	int err;
+	err = sysfs_create_empty_dir(fs_kobj, "smackfs");
+	if (err)
+		return err;
 	return 0;
 }
 
Signature · 1 line
2.2.1

A message that is not in the archive (sent off-list or not yet received): [email protected]

#18 lore raw

Re: [CFT][PATCH 09/10] sysfs: Create mountpoints with sysfs_create_empty_dir

Quoted 18 lines · Eric W. Biederman

This allows for better documentation in the code and it allows for a simpler and fully correct version of fs_fully_visible to be written.

The mount points converted and their filesystems are:

/sys/hypervisor/s390/       s390_hypfs
/sys/kernel/config/         configfs
/sys/kernel/debug/          debugfs
/sys/firmware/efi/efivars/  efivarfs
/sys/fs/fuse/connections/   fusectl
/sys/fs/pstore/             pstore
/sys/kernel/tracing/        tracefs
/sys/fs/cgroup/             cgroup
/sys/kernel/security/       securityfs
/sys/fs/selinux/            selinuxfs
/sys/fs/smackfs/            smackfs
Quoted 2 lines

So, this somehow ends up confusing upstart on centos6 based systems making it fail to mount tmpfs on /sys/fs/cgroup. It also skips sunrpc and other mounts are different too. No idea why at this point. Can we please revert this from -stable until we know what's going on?

Thanks.

Signature · 1 line
tejun
#19 lore raw

Re: [CFT][PATCH 09/10] sysfs: Create mountpoints with sysfs_create_empty_dir

Quoted 19 lines · Tejun Heo
Quoted 18 lines · Eric W. Biederman

This allows for better documentation in the code and it allows for a simpler and fully correct version of fs_fully_visible to be written.

The mount points converted and their filesystems are:

/sys/hypervisor/s390/       s390_hypfs
/sys/kernel/config/         configfs
/sys/kernel/debug/          debugfs
/sys/firmware/efi/efivars/  efivarfs
/sys/fs/fuse/connections/   fusectl
/sys/fs/pstore/             pstore
/sys/kernel/tracing/        tracefs
/sys/fs/cgroup/             cgroup
/sys/kernel/security/       securityfs
/sys/fs/selinux/            selinuxfs
/sys/fs/smackfs/            smackfs
Quoted 7 lines
Quoted 2 lines

So, this somehow ends up confusing upstart on centos6 based systems making it fail to mount tmpfs on /sys/fs/cgroup. It also skips sunrpc and other mounts are different too. No idea why at this point. Can we please revert this from -stable until we know what's going on?

*Boggle*

The only time this should prevent anything is when in a container when you are not global root. And then only mounting sysfs should be affected.

The only difference in executed code really should be setting an extra flag on the kernfs, inode. The kernfs changes will also refuse to add entries to these directories (but these directories are empty).

If this is causing problems I don't have a problem with a revert but reverts take a minute, and this seems to be the first report of this kind. Can we take a minute and attempt to get a coherent explanation.

Quoted 1 line

From what little information you given above it sounds like something

shifted and when you rebuilt the kernel and now a memory stomp is hitting something else. It should be a matter of moments to debug this issue (once a test environment is setup), and see what is wrong and then we can act intelligently. Tracing a single system call is not difficult.

If there really is some weird issue I want to know what it is.

Eric

A message that is not in the archive (sent off-list or not yet received): [email protected]

#21 lore raw

Re: [CFT][PATCH 09/10] sysfs: Create mountpoints with sysfs_create_empty_dir

Quoted 29 lines · Eric W. Biederman
Quoted 19 lines · Tejun Heo
Quoted 18 lines · Eric W. Biederman

This allows for better documentation in the code and it allows for a simpler and fully correct version of fs_fully_visible to be written.

The mount points converted and their filesystems are:

/sys/hypervisor/s390/       s390_hypfs
/sys/kernel/config/         configfs
/sys/kernel/debug/          debugfs
/sys/firmware/efi/efivars/  efivarfs
/sys/fs/fuse/connections/   fusectl
/sys/fs/pstore/             pstore
/sys/kernel/tracing/        tracefs
/sys/fs/cgroup/             cgroup
/sys/kernel/security/       securityfs
/sys/fs/selinux/            selinuxfs
/sys/fs/smackfs/            smackfs
Quoted 7 lines
Quoted 2 lines

So, this somehow ends up confusing upstart on centos6 based systems making it fail to mount tmpfs on /sys/fs/cgroup. It also skips sunrpc and other mounts are different too. No idea why at this point. Can we please revert this from -stable until we know what's going on?

Quoted 5 lines

*Boggle*

The only time this should prevent anything is when in a container when you are not global root. And then only mounting sysfs should be affected.

Before:

open("/sys/kernel/debug/asdf", O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK, 0666) = -1 EACCES (Permission denied)

After:

open("/sys/kernel/debug/asdf", O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK, 0666) = -1 ENOENT (No such file or directory)

Something broke. I don't know whether CentOS cares about that change, but there could be other odd side effects.

--Andy

#22 lore raw

Re: [CFT][PATCH 09/10] sysfs: Create mountpoints with sysfs_create_empty_dir

In reply to a message not in the archive

Hey,

Quoted 10 lines · Eric W. Biederman
Quoted 4 lines

So, this somehow ends up confusing upstart on centos6 based systems making it fail to mount tmpfs on /sys/fs/cgroup. It also skips sunrpc and other mounts are different too. No idea why at this point. Can we please revert this from -stable until we know what's going on?

*Boggle*

The only time this should prevent anything is when in a container when you are not global root. And then only mounting sysfs should be affected.

This is just plain boot. No namespace involved.

Quoted 3 lines

The only difference in executed code really should be setting an extra flag on the kernfs, inode. The kernfs changes will also refuse to add entries to these directories (but these directories are empty).

Why do we have this in -stable then? Is this part of a larger fix?

Quoted 7 lines

If this is causing problems I don't have a problem with a revert but reverts take a minute, and this seems to be the first report of this kind. Can we take a minute and attempt to get a coherent explanation.

From what little information you given above it sounds like something shifted and when you rebuilt the kernel and now a memory stomp is hitting something else. It should be a matter of moments to debug this

I don't think it's a random memory stomping thing. I reverted the commit from two different kernels and the result was always consistent.

Quoted 2 lines

issue (once a test environment is setup), and see what is wrong and then we can act intelligently. Tracing a single system call is not difficult.

I'm already out today so it'll have to wait till tomorrow.

Quoted 1 line

If there really is some weird issue I want to know what it is.

Sure, but you wanna do that in -stable?

Thanks.

Signature · 1 line
tejun

A message that is not in the archive (sent off-list or not yet received): CAOS58YOHU8SFv4UXeBRr4t88UU=DXQCPg2HU_dMBmgM7WBB1zQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org

#24 lore raw

Re: [CFT][PATCH 09/10] sysfs: Create mountpoints with sysfs_create_empty_dir

Quoted 15 lines · Tejun Heo

Hey,

Quoted 10 lines · Eric W. Biederman
Quoted 4 lines

So, this somehow ends up confusing upstart on centos6 based systems making it fail to mount tmpfs on /sys/fs/cgroup. It also skips sunrpc and other mounts are different too. No idea why at this point. Can we please revert this from -stable until we know what's going on?

*Boggle*

The only time this should prevent anything is when in a container when you are not global root. And then only mounting sysfs should be affected.

Quoted 7 lines

This is just plain boot. No namespace involved.

Quoted 3 lines

The only difference in executed code really should be setting an extra flag on the kernfs, inode. The kernfs changes will also refuse to add entries to these directories (but these directories are empty).

Why do we have this in -stable then? Is this part of a larger fix?

It is. This patch is part of the prep work to prevent unprivileged users not mounting sysfs (using user namespace permissions) when they should not be allowed to.

Quoted 8 lines
Quoted 7 lines

If this is causing problems I don't have a problem with a revert but reverts take a minute, and this seems to be the first report of this kind. Can we take a minute and attempt to get a coherent explanation.

It should be a matter of moments to debug this
issue (once a test environment is setup), and see what is wrong and then we can act intelligently. Tracing a single system call is not difficult.

Quoted 5 lines

I'm already out today so it'll have to wait till tomorrow.

Quoted 1 line

If there really is some weird issue I want to know what it is.

Sure, but you wanna do that in -stable?

Before fixing anything I want a bug report that is clear enough to be reproducible.

I just went and attempted to reproduce this, and on RHEL6 workstation (aka my work laptop), using the todays 4.2.0-rc6+ aka edf15b4d4b01b565cb5f4fd2e2d08940b9f92e2f and all of the mounts in /proc/self/mounts are the same between 4.2.0-rc6 and the RHEL6 stock 2.6.32-504.30.3.el6.x86_64, including the cgroups mounted on /cgroup.

Which means that I don't have any reason to believe that normal CentOS 6 is broken.

Which -stable kernel are you having problems with? Perhaps it was a broken backport?

Is it possible this is a local CentOS 6 hack that is breaking? Perhaps a patch you apply on top of your -stable kernel?

Certainly with cgroups expected to be mounted at /sys/fs/cgroup there has clearly been at least one change from the stock configuration.

I think it is a little less serious if stock CentOS 6 doesn't have problems. Unless it is a conflict of kernel patches I definitely think whatever it is needs to be fixed.

Eric

A message that is not in the archive (sent off-list or not yet received): [email protected]

#26 lore raw

Re: [CFT][PATCH 09/10] sysfs: Create mountpoints with sysfs_create_empty_dir

Quoted 5 lines · ebiederm-aS9lmoZGLiVWk0Htik3J/[email protected] (Eric W. Biederman) writes:

I just went and attempted to reproduce this, and on RHEL6 workstation (aka my work laptop), using the todays 4.2.0-rc6+ aka edf15b4d4b01b565cb5f4fd2e2d08940b9f92e2f and all of the mounts in /proc/self/mounts are the same between 4.2.0-rc6 and the RHEL6 stock 2.6.32-504.30.3.el6.x86_64, including the cgroups mounted on /cgroup.

I built a few more kernels just to see if this was some weird backport thing. The kernels 3.10.86, 3.14.58, 3.18.20, and 4.1.5 all boot and mount their cgroup filesystems just fine. Granted I kept having to smack the memory cgroup into being compiled in as the config options kept changing but otherwise I have not seen any problems.

So I am very surprised you are having problems.

Eric

A message that is not in the archive (sent off-list or not yet received): [email protected]

#28 lore raw

Re: [CFT][PATCH 09/10] sysfs: Create mountpoints with sysfs_create_empty_dir

Quoted 8 lines · ebiederm-aS9lmoZGLiVWk0Htik3J/[email protected] (Eric W. Biederman) writes:
Quoted 5 lines · ebiederm-aS9lmoZGLiVWk0Htik3J/[email protected] (Eric W. Biederman) writes:

I just went and attempted to reproduce this, and on RHEL6 workstation (aka my work laptop), using the todays 4.2.0-rc6+ aka edf15b4d4b01b565cb5f4fd2e2d08940b9f92e2f and all of the mounts in /proc/self/mounts are the same between 4.2.0-rc6 and the RHEL6 stock 2.6.32-504.30.3.el6.x86_64, including the cgroups mounted on /cgroup.

Quoted 7 lines

I built a few more kernels just to see if this was some weird backport thing. The kernels 3.10.86, 3.14.58, 3.18.20, and 4.1.5 all boot and mount their cgroup filesystems just fine. Granted I kept having to smack the memory cgroup into being compiled in as the config options kept changing but otherwise I have not seen any problems.

So I am very surprised you are having problems.

Although I guess I could have saved myself some time by noticing that 4.1.5 was the only one of the kernels with the change backported into it. *Shrug*

I don't see the problem and I don't know where to look to see why you are having problems.

Eric

A message that is not in the archive (sent off-list or not yet received): [email protected]

#30 lore raw

Re: [CFT][PATCH 09/10] sysfs: Create mountpoints with sysfs_create_empty_dir

Hello, Eric.

Quoted 16 lines · Eric W. Biederman
Quoted 14 lines · ebiederm-aS9lmoZGLiVWk0Htik3J/[email protected] (Eric W. Biederman) writes:
Quoted 5 lines · ebiederm-aS9lmoZGLiVWk0Htik3J/[email protected] (Eric W. Biederman) writes:

I just went and attempted to reproduce this, and on RHEL6 workstation (aka my work laptop), using the todays 4.2.0-rc6+ aka edf15b4d4b01b565cb5f4fd2e2d08940b9f92e2f and all of the mounts in /proc/self/mounts are the same between 4.2.0-rc6 and the RHEL6 stock 2.6.32-504.30.3.el6.x86_64, including the cgroups mounted on /cgroup.

I built a few more kernels just to see if this was some weird backport thing. The kernels 3.10.86, 3.14.58, 3.18.20, and 4.1.5 all boot and mount their cgroup filesystems just fine. Granted I kept having to smack the memory cgroup into being compiled in as the config options kept changing but otherwise I have not seen any problems.

Quoted 8 lines
Quoted 1 line

So I am very surprised you are having problems.

Although I guess I could have saved myself some time by noticing that 4.1.5 was the only one of the kernels with the change backported into it. *Shrug*

I don't see the problem and I don't know where to look to see why you are having problems.

lol, this wasn't upstart but an internal tool which sets up a custom cgroup hierarchy and the problem was the size of the directory inode reported by stat(2). It's kinda hilarious but that's what the tool was depending on to tell whether tmpfs is mounted on /sys/fs/cgroup or not. A kernfs directory reports zero as its inode size while tmpfs reports some non-zero number, so the tool did stat(2) on /sys/fs/cgroup and mounted tmpfs iff size is zero to avoid mounting tmpfs multiple times. Now, make_empty_dir_inode() sets i_size to 2 and the tool thinks that tmpfs is already mounted there.

It's an icky behavior but it'd be better to maintain the original behavior. We should be able to set size to zero for empty dirs, right?

Thanks.

Signature · 1 line
tejun

A message that is not in the archive (sent off-list or not yet received): [email protected]

#32 lore raw

PATCH 1/1 fs: Set the size of empty dirs to 0.

Before the make_empty_dir_inode calls were introduce into proc, sysfs, and sysctl those directories when stated reported an i_size of 0. make_empty_dir_inode started reporting an i_size of 2. At least one userspace application depended on stat returning i_size of 0. So modify make_empty_dir_inode to cause an i_size of 0 to be reported for these directories.

---

I have tested this and will queue this up shortly.

 fs/libfs.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
fs/libfs.c +1 -1
index 102edfd39000..c7cbfb092e94 100644
@@ -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;
 
Signature · 1 line
2.2.1

A message that is not in the archive (sent off-list or not yet received): 87mvxw46fc.fsf_-_-JOvCrm2gF+uungPnsOpG7nhyD016LWXt@public.gmane.org

Acked-by
#34 lore raw

Re: [PATCH] fs: Set the size of empty dirs to 0.

Quoted 10 lines · Eric W. Biederman

Before the make_empty_dir_inode calls were introduce into proc, sysfs, and sysctl those directories when stated reported an i_size of 0. make_empty_dir_inode started reporting an i_size of 2. At least one userspace application depended on stat returning i_size of 0. So modify make_empty_dir_inode to cause an i_size of 0 to be reported for these directories.

    ^^^
Quoted 1 line

Thanks.

Signature · 1 line
tejun
#35 lore raw

Re: [CFT][PATCH 09/10] sysfs: Create mountpoints with sysfs_create_empty_dir

In reply to a message not in the archive

Hello, Eric.

Quoted 16 lines · Eric W. Biederman
Quoted 14 lines · ebiederm-aS9lmoZGLiVWk0Htik3J/[email protected] (Eric W. Biederman) writes:
Quoted 5 lines · ebiederm-aS9lmoZGLiVWk0Htik3J/[email protected] (Eric W. Biederman) writes:

I just went and attempted to reproduce this, and on RHEL6 workstation (aka my work laptop), using the todays 4.2.0-rc6+ aka edf15b4d4b01b565cb5f4fd2e2d08940b9f92e2f and all of the mounts in /proc/self/mounts are the same between 4.2.0-rc6 and the RHEL6 stock 2.6.32-504.30.3.el6.x86_64, including the cgroups mounted on /cgroup.

I built a few more kernels just to see if this was some weird backport thing. The kernels 3.10.86, 3.14.58, 3.18.20, and 4.1.5 all boot and mount their cgroup filesystems just fine. Granted I kept having to smack the memory cgroup into being compiled in as the config options kept changing but otherwise I have not seen any problems.

Quoted 8 lines
Quoted 1 line

So I am very surprised you are having problems.

Although I guess I could have saved myself some time by noticing that 4.1.5 was the only one of the kernels with the change backported into it. *Shrug*

I don't see the problem and I don't know where to look to see why you are having problems.

lol, this wasn't upstart but an internal tool which sets up a custom cgroup hierarchy and the problem was the size of the directory inode reported by stat(2). It's kinda hilarious but that's what the tool was depending on to tell whether tmpfs is mounted on /sys/fs/cgroup or not. A kernfs directory reports zero as its inode size while tmpfs reports some non-zero number, so the tool did stat(2) on /sys/fs/cgroup and mounted tmpfs iff size is zero to avoid mounting tmpfs multiple times. Now, make_empty_dir_inode() sets i_size to 2 and the tool thinks that tmpfs is already mounted there.

It's an icky behavior but it'd be better to maintain the original behavior. We should be able to set size to zero for empty dirs, right?

Thanks.

Signature · 1 line
tejun
#36 lore raw

Re: [CFT][PATCH 09/10] sysfs: Create mountpoints with sysfs_create_empty_dir

In reply to a message not in the archive
Quoted 15 lines · Tejun Heo

Hey,

Quoted 10 lines · Eric W. Biederman
Quoted 4 lines

So, this somehow ends up confusing upstart on centos6 based systems making it fail to mount tmpfs on /sys/fs/cgroup. It also skips sunrpc and other mounts are different too. No idea why at this point. Can we please revert this from -stable until we know what's going on?

*Boggle*

The only time this should prevent anything is when in a container when you are not global root. And then only mounting sysfs should be affected.

Quoted 7 lines

This is just plain boot. No namespace involved.

Quoted 3 lines

The only difference in executed code really should be setting an extra flag on the kernfs, inode. The kernfs changes will also refuse to add entries to these directories (but these directories are empty).

Why do we have this in -stable then? Is this part of a larger fix?

It is. This patch is part of the prep work to prevent unprivileged users not mounting sysfs (using user namespace permissions) when they should not be allowed to.

Quoted 8 lines
Quoted 7 lines

If this is causing problems I don't have a problem with a revert but reverts take a minute, and this seems to be the first report of this kind. Can we take a minute and attempt to get a coherent explanation.

It should be a matter of moments to debug this
issue (once a test environment is setup), and see what is wrong and then we can act intelligently. Tracing a single system call is not difficult.

Quoted 5 lines

I'm already out today so it'll have to wait till tomorrow.

Quoted 1 line

If there really is some weird issue I want to know what it is.

Sure, but you wanna do that in -stable?

Before fixing anything I want a bug report that is clear enough to be reproducible.

I just went and attempted to reproduce this, and on RHEL6 workstation (aka my work laptop), using the todays 4.2.0-rc6+ aka edf15b4d4b01b565cb5f4fd2e2d08940b9f92e2f and all of the mounts in /proc/self/mounts are the same between 4.2.0-rc6 and the RHEL6 stock 2.6.32-504.30.3.el6.x86_64, including the cgroups mounted on /cgroup.

Which means that I don't have any reason to believe that normal CentOS 6 is broken.

Which -stable kernel are you having problems with? Perhaps it was a broken backport?

Is it possible this is a local CentOS 6 hack that is breaking? Perhaps a patch you apply on top of your -stable kernel?

Certainly with cgroups expected to be mounted at /sys/fs/cgroup there has clearly been at least one change from the stock configuration.

I think it is a little less serious if stock CentOS 6 doesn't have problems. Unless it is a conflict of kernel patches I definitely think whatever it is needs to be fixed.

Eric

#37 lore raw

Re: [CFT][PATCH 09/10] sysfs: Create mountpoints with sysfs_create_empty_dir

In reply to Eric W. Biederman
Quoted 29 lines · Eric W. Biederman
Quoted 19 lines · Tejun Heo
Quoted 18 lines · Eric W. Biederman

This allows for better documentation in the code and it allows for a simpler and fully correct version of fs_fully_visible to be written.

The mount points converted and their filesystems are:

/sys/hypervisor/s390/       s390_hypfs
/sys/kernel/config/         configfs
/sys/kernel/debug/          debugfs
/sys/firmware/efi/efivars/  efivarfs
/sys/fs/fuse/connections/   fusectl
/sys/fs/pstore/             pstore
/sys/kernel/tracing/        tracefs
/sys/fs/cgroup/             cgroup
/sys/kernel/security/       securityfs
/sys/fs/selinux/            selinuxfs
/sys/fs/smackfs/            smackfs
Quoted 7 lines
Quoted 2 lines

So, this somehow ends up confusing upstart on centos6 based systems making it fail to mount tmpfs on /sys/fs/cgroup. It also skips sunrpc and other mounts are different too. No idea why at this point. Can we please revert this from -stable until we know what's going on?

Quoted 5 lines

*Boggle*

The only time this should prevent anything is when in a container when you are not global root. And then only mounting sysfs should be affected.

Before:

open("/sys/kernel/debug/asdf", O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK, 0666) = -1 EACCES (Permission denied)

After:

open("/sys/kernel/debug/asdf", O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK, 0666) = -1 ENOENT (No such file or directory)

Something broke. I don't know whether CentOS cares about that change, but there could be other odd side effects.

--Andy

A message that is not in the archive (sent off-list or not yet received): CALCETrXE=fKa3XkEEo6y2=ZNtsuBfX=kaoyDwiP0C2BwqKJWjw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org

#39 lore raw

Re: [CFT][PATCH 09/10] sysfs: Create mountpoints with sysfs_create_empty_dir

Quoted 15 lines · Andy Lutomirski
Quoted 6 lines · Eric W. Biederman

*Boggle*

The only time this should prevent anything is when in a container when you are not global root. And then only mounting sysfs should be affected.

Before:

open("/sys/kernel/debug/asdf", O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK, 0666) = -1 EACCES (Permission denied)

Quoted 7 lines

After:

open("/sys/kernel/debug/asdf", O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK, 0666) = -1 ENOENT (No such file or directory)

Something broke. I don't know whether CentOS cares about that change, but there could be other odd side effects.

Thanks for pointing this out. I don't know if broke is quite the right word for a change in error codes on lookup failure, but I agree it is a difference that could have affected something.

The behavior of empty proc dirs actually return -ENOENT in this situation and so it is a little fuzzy about which is the best behavior to use.

Creativing a negative dentry and and then letting vfs_create fail may be the better way to go.

Negative dentries are weird enough that I would prefer not to have code that creates negative dentries. They could easily be a lurking trap for some filesystems dentry operations.

The patch below is enough to change the error code if someone who can reproduce this wants to try this.

Eric

diff --gdiff --git a/fs/libfs.c b/fs/libfs.c
index 102edfd39000..3a452a485cbf 100644

fs/libfs.c +1 -1
@@ -1109,7 +1109,7 @@ EXPORT_SYMBOL(simple_symlink_inode_operations);
  */
 static struct dentry *empty_dir_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
 {
-       return ERR_PTR(-ENOENT);
+       return NULL;
 }
 
 static int empty_dir_getattr(struct vfsmount *mnt, struct dentry *dentry,

A message that is not in the archive (sent off-list or not yet received): [email protected]

#41 lore raw

Re: [CFT][PATCH 09/10] sysfs: Create mountpoints with sysfs_create_empty_dir

Quoted 50 lines · Eric W. Biederman
Quoted 15 lines · Andy Lutomirski
Quoted 6 lines · Eric W. Biederman

*Boggle*

The only time this should prevent anything is when in a container when you are not global root. And then only mounting sysfs should be affected.

Before:

open("/sys/kernel/debug/asdf", O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK, 0666) = -1 EACCES (Permission denied)

Quoted 7 lines

After:

open("/sys/kernel/debug/asdf", O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK, 0666) = -1 ENOENT (No such file or directory)

Something broke. I don't know whether CentOS cares about that change, but there could be other odd side effects.

Thanks for pointing this out. I don't know if broke is quite the right word for a change in error codes on lookup failure, but I agree it is a difference that could have affected something.

The behavior of empty proc dirs actually return -ENOENT in this situation and so it is a little fuzzy about which is the best behavior to use.

Creativing a negative dentry and and then letting vfs_create fail may be the better way to go.

Negative dentries are weird enough that I would prefer not to have code that creates negative dentries. They could easily be a lurking trap for some filesystems dentry operations.

The patch below is enough to change the error code if someone who can reproduce this wants to try this.

Eric

diff --gdiff --git a/fs/libfs.c b/fs/libfs.c
index 102edfd39000..3a452a485cbf 100644

fs/libfs.c EXPORT_SYMBOL(simple_symlink_inode_operations); · line 1112

Quoted 5 lines
fs/libfs.c +1 -1
@@ -1109,7 +1109,7 @@ EXPORT_SYMBOL(simple_symlink_inode_operations);
  */
 static struct dentry *empty_dir_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
 {
-       return ERR_PTR(-ENOENT);
+       return NULL;

And let's please restore this too. Sentiments about negative dentries aside, It's outright wrong to report -ENOENT on creat.

Thanks.

Signature · 1 line
tejun
#42 lore raw

Re: [CFT][PATCH 09/10] sysfs: Create mountpoints with sysfs_create_empty_dir

Quoted 46 lines · Tejun Heo
Quoted 45 lines · Eric W. Biederman
Quoted 15 lines · Andy Lutomirski
Quoted 6 lines · Eric W. Biederman

*Boggle*

The only time this should prevent anything is when in a container when you are not global root. And then only mounting sysfs should be affected.

Before:

open("/sys/kernel/debug/asdf", O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK, 0666) = -1 EACCES (Permission denied)

Quoted 7 lines

After:

open("/sys/kernel/debug/asdf", O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK, 0666) = -1 ENOENT (No such file or directory)

Something broke. I don't know whether CentOS cares about that change, but there could be other odd side effects.

Thanks for pointing this out. I don't know if broke is quite the right word for a change in error codes on lookup failure, but I agree it is a difference that could have affected something.

The behavior of empty proc dirs actually return -ENOENT in this situation and so it is a little fuzzy about which is the best behavior to use.

Creativing a negative dentry and and then letting vfs_create fail may be the better way to go.

Negative dentries are weird enough that I would prefer not to have code that creates negative dentries. They could easily be a lurking trap for some filesystems dentry operations.

The patch below is enough to change the error code if someone who can reproduce this wants to try this.

Eric

Quoted 13 lines

fs/libfs.c EXPORT_SYMBOL(simple_symlink_inode_operations); · line 1112

Quoted 10 lines

diff --gdiff --git a/fs/libfs.c b/fs/libfs.c
index 102edfd39000..3a452a485cbf 100644

fs/libfs.c +1 -1
@@ -1109,7 +1109,7 @@ EXPORT_SYMBOL(simple_symlink_inode_operations);
  */
 static struct dentry *empty_dir_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
 {
-       return ERR_PTR(-ENOENT);
+       return NULL;

And let's please restore this too. Sentiments about negative dentries aside, It's outright wrong to report -ENOENT on creat.

proc has always reported -ENOENT. sysfs is the odd one out.

I am not completely certain that trivial patch above, does not introduce a leak, a NULL pointer dereference or something else nasty when the code is hit.

So far it seems that no one cares. And since the change is brittle I am not inclined to mess with it this week, as I have other demands on my limited review bandwidth right now.

Eric

A message that is not in the archive (sent off-list or not yet received): [email protected]

#44 lore raw

Re: [CFT][PATCH 09/10] sysfs: Create mountpoints with sysfs_create_empty_dir

Hello,

Quoted 1 line · Eric W. Biederman

proc has always reported -ENOENT. sysfs is the odd one out.

Hmm... open(2) is clear about failure modes and ENOENT doesn't fit the bill here. Maintaining the behavior for proc for backward compatibility is fine but I don't think it's appropriate to change behaviors on other filesystems which were behaving correctly especially through changes which got routed through -stable.

ENOENT O_CREAT is not set and the named file does not exist. Or, a directory component in pathname does not exist or is a dangling symbolic link.

ENOENT pathname refers to a nonexistent directory, O_TMPFILE and one of O_WRONLY or O_RDWR were specified in flags, but this kernel version does not provide the O_TMPFILE
functionality.

Quoted 7 lines

I am not completely certain that trivial patch above, does not introduce a leak, a NULL pointer dereference or something else nasty when the code is hit.

So far it seems that no one cares. And since the change is brittle I am not inclined to mess with it this week, as I have other demands on my limited review bandwidth right now.

Sure, it isn't "today" urgent but let's please restore the original behavior before the new behavior gets too widespread.

Thanks.

Signature · 1 line
tejun

A message that is not in the archive (sent off-list or not yet received): [email protected]

#46 lore raw

Re: [CFT][PATCH 09/10] sysfs: Create mountpoints with sysfs_create_empty_dir

Quoted 46 lines · Tejun Heo
Quoted 45 lines · Eric W. Biederman
Quoted 15 lines · Andy Lutomirski
Quoted 6 lines · Eric W. Biederman

*Boggle*

The only time this should prevent anything is when in a container when you are not global root. And then only mounting sysfs should be affected.

Before:

open("/sys/kernel/debug/asdf", O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK, 0666) = -1 EACCES (Permission denied)

Quoted 7 lines

After:

open("/sys/kernel/debug/asdf", O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK, 0666) = -1 ENOENT (No such file or directory)

Something broke. I don't know whether CentOS cares about that change, but there could be other odd side effects.

Thanks for pointing this out. I don't know if broke is quite the right word for a change in error codes on lookup failure, but I agree it is a difference that could have affected something.

The behavior of empty proc dirs actually return -ENOENT in this situation and so it is a little fuzzy about which is the best behavior to use.

Creativing a negative dentry and and then letting vfs_create fail may be the better way to go.

Negative dentries are weird enough that I would prefer not to have code that creates negative dentries. They could easily be a lurking trap for some filesystems dentry operations.

The patch below is enough to change the error code if someone who can reproduce this wants to try this.

Eric

Quoted 13 lines

fs/libfs.c EXPORT_SYMBOL(simple_symlink_inode_operations); · line 1112

Quoted 10 lines

diff --gdiff --git a/fs/libfs.c b/fs/libfs.c
index 102edfd39000..3a452a485cbf 100644

fs/libfs.c +1 -1
@@ -1109,7 +1109,7 @@ EXPORT_SYMBOL(simple_symlink_inode_operations);
  */
 static struct dentry *empty_dir_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
 {
-       return ERR_PTR(-ENOENT);
+       return NULL;

And let's please restore this too. Sentiments about negative dentries aside, It's outright wrong to report -ENOENT on creat.

proc has always reported -ENOENT. sysfs is the odd one out.

I am not completely certain that trivial patch above, does not introduce a leak, a NULL pointer dereference or something else nasty when the code is hit.

So far it seems that no one cares. And since the change is brittle I am not inclined to mess with it this week, as I have other demands on my limited review bandwidth right now.

Eric

#47 lore raw

Re: [CFT][PATCH 09/10] sysfs: Create mountpoints with sysfs_create_empty_dir

In reply to a message not in the archive
Quoted 50 lines · Eric W. Biederman
Quoted 15 lines · Andy Lutomirski
Quoted 6 lines · Eric W. Biederman

*Boggle*

The only time this should prevent anything is when in a container when you are not global root. And then only mounting sysfs should be affected.

Before:

open("/sys/kernel/debug/asdf", O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK, 0666) = -1 EACCES (Permission denied)

Quoted 7 lines

After:

open("/sys/kernel/debug/asdf", O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK, 0666) = -1 ENOENT (No such file or directory)

Something broke. I don't know whether CentOS cares about that change, but there could be other odd side effects.

Thanks for pointing this out. I don't know if broke is quite the right word for a change in error codes on lookup failure, but I agree it is a difference that could have affected something.

The behavior of empty proc dirs actually return -ENOENT in this situation and so it is a little fuzzy about which is the best behavior to use.

Creativing a negative dentry and and then letting vfs_create fail may be the better way to go.

Negative dentries are weird enough that I would prefer not to have code that creates negative dentries. They could easily be a lurking trap for some filesystems dentry operations.

The patch below is enough to change the error code if someone who can reproduce this wants to try this.

Eric

diff --gdiff --git a/fs/libfs.c b/fs/libfs.c
index 102edfd39000..3a452a485cbf 100644

fs/libfs.c EXPORT_SYMBOL(simple_symlink_inode_operations); · line 1112

Quoted 5 lines
fs/libfs.c +1 -1
@@ -1109,7 +1109,7 @@ EXPORT_SYMBOL(simple_symlink_inode_operations);
  */
 static struct dentry *empty_dir_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
 {
-       return ERR_PTR(-ENOENT);
+       return NULL;

And let's please restore this too. Sentiments about negative dentries aside, It's outright wrong to report -ENOENT on creat.

Thanks.

Signature · 1 line
tejun
#48 lore raw

Re: [CFT][PATCH 09/10] sysfs: Create mountpoints with sysfs_create_empty_dir

In reply to a message not in the archive
Quoted 15 lines · Andy Lutomirski
Quoted 6 lines · Eric W. Biederman

*Boggle*

The only time this should prevent anything is when in a container when you are not global root. And then only mounting sysfs should be affected.

Before:

open("/sys/kernel/debug/asdf", O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK, 0666) = -1 EACCES (Permission denied)

Quoted 7 lines

After:

open("/sys/kernel/debug/asdf", O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK, 0666) = -1 ENOENT (No such file or directory)

Something broke. I don't know whether CentOS cares about that change, but there could be other odd side effects.

Thanks for pointing this out. I don't know if broke is quite the right word for a change in error codes on lookup failure, but I agree it is a difference that could have affected something.

The behavior of empty proc dirs actually return -ENOENT in this situation and so it is a little fuzzy about which is the best behavior to use.

Creativing a negative dentry and and then letting vfs_create fail may be the better way to go.

Negative dentries are weird enough that I would prefer not to have code that creates negative dentries. They could easily be a lurking trap for some filesystems dentry operations.

The patch below is enough to change the error code if someone who can reproduce this wants to try this.

Eric

diff --gdiff --git a/fs/libfs.c b/fs/libfs.c
index 102edfd39000..3a452a485cbf 100644

fs/libfs.c +1 -1
@@ -1109,7 +1109,7 @@ EXPORT_SYMBOL(simple_symlink_inode_operations);
  */
 static struct dentry *empty_dir_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
 {
-       return ERR_PTR(-ENOENT);
+       return NULL;
 }
 
 static int empty_dir_getattr(struct vfsmount *mnt, struct dentry *dentry,

A message that is not in the archive (sent off-list or not yet received): [email protected]

#50 lore raw

Re: [CFT][PATCH 09/10] sysfs: Create mountpoints with sysfs_create_empty_dir

Quoted 19 lines · Tejun Heo
Quoted 18 lines · Eric W. Biederman

This allows for better documentation in the code and it allows for a simpler and fully correct version of fs_fully_visible to be written.

The mount points converted and their filesystems are:

/sys/hypervisor/s390/       s390_hypfs
/sys/kernel/config/         configfs
/sys/kernel/debug/          debugfs
/sys/firmware/efi/efivars/  efivarfs
/sys/fs/fuse/connections/   fusectl
/sys/fs/pstore/             pstore
/sys/kernel/tracing/        tracefs
/sys/fs/cgroup/             cgroup
/sys/kernel/security/       securityfs
/sys/fs/selinux/            selinuxfs
/sys/fs/smackfs/            smackfs
Quoted 7 lines
Quoted 2 lines

So, this somehow ends up confusing upstart on centos6 based systems making it fail to mount tmpfs on /sys/fs/cgroup. It also skips sunrpc and other mounts are different too. No idea why at this point. Can we please revert this from -stable until we know what's going on?

*Boggle*

The only time this should prevent anything is when in a container when you are not global root. And then only mounting sysfs should be affected.

The only difference in executed code really should be setting an extra flag on the kernfs, inode. The kernfs changes will also refuse to add entries to these directories (but these directories are empty).

If this is causing problems I don't have a problem with a revert but reverts take a minute, and this seems to be the first report of this kind. Can we take a minute and attempt to get a coherent explanation.

From what little information you given above it sounds like something shifted and when you rebuilt the kernel and now a memory stomp is hitting something else. It should be a matter of moments to debug this issue (once a test environment is setup), and see what is wrong and then we can act intelligently. Tracing a single system call is not difficult.

If there really is some weird issue I want to know what it is.

Eric

#51 lore raw

Re: [CFT][PATCH 09/10] sysfs: Create mountpoints with sysfs_create_empty_dir

In reply to a message not in the archive
Quoted 18 lines · Eric W. Biederman

This allows for better documentation in the code and it allows for a simpler and fully correct version of fs_fully_visible to be written.

The mount points converted and their filesystems are:

/sys/hypervisor/s390/       s390_hypfs
/sys/kernel/config/         configfs
/sys/kernel/debug/          debugfs
/sys/firmware/efi/efivars/  efivarfs
/sys/fs/fuse/connections/   fusectl
/sys/fs/pstore/             pstore
/sys/kernel/tracing/        tracefs
/sys/fs/cgroup/             cgroup
/sys/kernel/security/       securityfs
/sys/fs/selinux/            selinuxfs
/sys/fs/smackfs/            smackfs
Quoted 2 lines

So, this somehow ends up confusing upstart on centos6 based systems making it fail to mount tmpfs on /sys/fs/cgroup. It also skips sunrpc and other mounts are different too. No idea why at this point. Can we please revert this from -stable until we know what's going on?

Thanks.

Signature · 1 line
tejun
#52 lore raw

PATCH 10/10 mnt: Update fs_fully_visible to test for permanently empty directories

In reply to a message not in the archive

fs_fully_visible attempts to make fresh mounts of proc and sysfs give the mounter no more access to proc and sysfs than if they could have by creating a bind mount. One aspect of proc and sysfs that makes this particularly tricky is that there are other filesystems that typically mount on top of proc and sysfs. As those filesystems are mounted on empty directories in practice it is safe to ignore them. However testing to ensure filesystems are mounted on empty directories has not been something the in kernel data structures have supported so the current test for an empty directory which checks to see if nlink <= 2 is a bit lacking.

proc and sysfs have recently been modified to use the new empty_dir infrastructure to create all of their dedicated mount points. Instead of testing for S_ISDIR(inode->i_mode) && i_nlink <= 2 to see if a directory is empty, test for is_empty_dir_inode(inode). That small change guaranteess mounts found on proc and sysfs really are safe to ignore, because the directories are not only empty but nothing can ever be added to them. This guarantees there is nothing to worry about when mounting proc and sysfs.

---
 fs/namespace.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)
fs/namespace.c +2 -3
index 3ede0669b8d2..eccd925c6e82 100644
@@ -3220,9 +3220,8 @@ static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags)
 			/* Only worry about locked mounts */
 			if (!(mnt->mnt.mnt_flags & MNT_LOCKED))
 				continue;
-			if (!S_ISDIR(inode->i_mode))
-				goto next;
-			if (inode->i_nlink > 2)
+			/* Is the directory permanetly empty? */
+			if (!is_empty_dir_inode(inode))
 				goto next;
 		}
 		/* Preserve the locked attributes */
Signature · 1 line
2.2.1
#53 lore raw

PATCH 10/10 mnt: Update fs_fully_visible to test for permanently empty directories

In reply to a message not in the archive

fs_fully_visible attempts to make fresh mounts of proc and sysfs give the mounter no more access to proc and sysfs than if they could have by creating a bind mount. One aspect of proc and sysfs that makes this particularly tricky is that there are other filesystems that typically mount on top of proc and sysfs. As those filesystems are mounted on empty directories in practice it is safe to ignore them. However testing to ensure filesystems are mounted on empty directories has not been something the in kernel data structures have supported so the current test for an empty directory which checks to see if nlink <= 2 is a bit lacking.

proc and sysfs have recently been modified to use the new empty_dir infrastructure to create all of their dedicated mount points. Instead of testing for S_ISDIR(inode->i_mode) && i_nlink <= 2 to see if a directory is empty, test for is_empty_dir_inode(inode). That small change guaranteess mounts found on proc and sysfs really are safe to ignore, because the directories are not only empty but nothing can ever be added to them. This guarantees there is nothing to worry about when mounting proc and sysfs.

---
 fs/namespace.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)
fs/namespace.c +2 -3
index 3ede0669b8d2..eccd925c6e82 100644
@@ -3220,9 +3220,8 @@ static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags)
 			/* Only worry about locked mounts */
 			if (!(mnt->mnt.mnt_flags & MNT_LOCKED))
 				continue;
-			if (!S_ISDIR(inode->i_mode))
-				goto next;
-			if (inode->i_nlink > 2)
+			/* Is the directory permanetly empty? */
+			if (!is_empty_dir_inode(inode))
 				goto next;
 		}
 		/* Preserve the locked attributes */
Signature · 1 line
2.2.1
#54 lore raw
In reply to a message not in the archive
Quoted 25 lines · Eric W. Biederman

The code is currently available at:

git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace.git for-testing

HEAD: a524faf520600968e58bbc732063fccf2fdf9199 mnt: Update fs_fully_visible to test for permanently empty directories

The problem: Mounting a new instance of proc of sysfs can allow things that a bind mount of those filesystems would not.

That is the cases I am dealing with are:
unshare --user --net --mount ; mount -t sysfs ... unshare --user --pid --mount ; mount -t proc ...

The big change is that this set of changes enforces the preservation of locked mount flags, from the existing mount to the current mount. Which means that if proc was mounted read-only the current current will allow a new instance of proc to be mounted read-write, and this set of changes enforces that proc remain read-only.

The other gotcha is that the current code does not properly detect empty directories so to prevent things slipping through the cracks this set of changes annotates all mount points where nothing will be revealed if the filesystem mounted on top is removed.

Quoted 6 lines

Enforcing the administrators policy can actually matter in the real world as has been shown by the recent docker issue.

With this patchset I have two concerns:
- The enforcement of mount flag preservation on proc and sysfs may break things. (I am especially worried about the implicit adding of nodev).

What do you mean by this? What got added?

Quoted 7 lines

- I missed a filesystem mountpoint on proc or sysfs which would make a fresh copy unmountable for no good reason.

I don't want to break userspace if I can help it, and the code has been this way for a while so I figure there is time to find any pitfalls and address them before this code gets merged.

Quoted 8 lines

So if this works for you please give me your Tested-By

The well known mountpoints for pseudo filesystems that I could find are:

/dev/ffs*/                 functionfs
/dev/gadget/               gadgetfs
/dev/mqueue                mqueue
/dev/oprofile/             oprofilefs
/dev/pts/                  devpts

/dev/shm gets a tmpfs, right? Or do those not matter here?

Quoted 10 lines
/dlm/                      ocfs2_dlmfs
/ipath/                    ipathfs
/proc/fs/nfsd/             nfsd
/proc/openprom/            openpromfs
/proc/sys/fs/binfmt_misc/  binfmt_misc
/spu/                      spufs

/sys/firmware/efi/efivars/ efivarfs
/sys/fs/cgroup/ cgroup
/sys/fs/fuse/connections/ fusectl

I thought fuse mounted a few more things in here, but I don't know for sure.

Quoted 8 lines
/sys/fs/pstore/            pstore
/sys/fs/selinux/           selinuxfs
/sys/fs/smackfs/           smackfs
/sys/hypervisor/s390/      s390_hypfs
/sys/kernel/config/        configfs
/sys/kernel/debug/         debugfs
/sys/kernel/security/      securityfs
/sys/kernel/tracing/       tracefs

I think these are all correct for sysfs, I have a minor comment on the sysfs patch I'll make in it.

thanks,

greg k-h

#55 lore raw

cover Making new mounts of proc and sysfs as safe as bind mounts (take 2)

In reply to a message not in the archive

The code is currently available at:

git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace.git for-testing

HEAD: 513d98ba1adfa9e3178b6fc3b2fa57a622283d32 mnt: Update fs_fully_visible to test for permanently empty directories

The problem: Mounting a new instance of proc of sysfs can allow things that a bind mount of those filesystems would not.

That is the cases I am dealing with are:
unshare --user --net --mount ; mount -t sysfs ... unshare --user --pid --mount ; mount -t proc ...

This set of changes enforces the preservation of locked mount flags, from the existing mount to the current mount. Which means that if proc was mounted read-only the current current will allow a new instance of proc to be mounted read-write, and this set of changes enforces that proc remain read-only.

This set of changes also updates sysctl, proc and sysfs to explicitly create the directories they expect to be mount points as mount points. Making the code a little clearly and making it so when fs_fully_visible disregards something mounted on a proc or sysfs it is guaranteed to be safe, unlike the current code which can occassionally let things fall through the cracks.

These changes to enforce the administrators policy can actually matter in the real world as has been shown by the recent docker issue.

With this patchset I have two concerns:
- The enforcement of not being able to mount proc or sysfs with fewer mount flags than the existing mount may break something.

- That there is a filesystem that that common mounts on proc or sysfs and I missed annotating it's mount point. That would make mounting a freshy copy of proc or sysfs impossible.

I don't want to break userspace if I can help it, and the code has been this way for a while so I figure there is time to find any pitfalls and address them before this code gets merged. Folks rom lxc, sandstorm, libvirt-lxc (anyone who uses user namespaces in the least) a confirmation that I have not broken your existing code would be appreciated.

If this works for you please give me your Tested-By

Since the first version I have renamed the directory creation calls to have sysfs_create_mount_point and proc_create_mount_point (as suggested by Greg KH so that it is very clear what the code that creates those mount points is doing. I have also fixed a stupid bug that slipped into the proc code when I refactored it. I have also gone through and rested everything so hopefully nothing has slipped past me.

The well known mountpoints for pseudo filesystems that I could find are:

/dev/ffs*/                 functionfs
/dev/gadget/               gadgetfs
/dev/mqueue                mqueue
/dev/oprofile/             oprofilefs
/dev/pts/                  devpts
/dev/shm/                  tmpfs
/dlm/                      ocfs2_dlmfs
/ipath/                    ipathfs
/proc/fs/nfsd/             nfsd
/proc/openprom/            openpromfs
/proc/sys/fs/binfmt_misc/  binfmt_misc
/spu/                      spufs
/sys/firmware/efi/efivars/ efivarfs
/sys/fs/cgroup/            cgroup
/sys/fs/fuse/connections/  fusectl
/sys/fs/pstore/            pstore
/sys/fs/selinux/           selinuxfs
/sys/fs/smackfs/           smackfs
/sys/hypervisor/s390/      s390_hypfs
/sys/kernel/config/        configfs
/sys/kernel/debug/         debugfs
/sys/kernel/security/      securityfs
/sys/kernel/tracing/       tracefs
/var/lib/ibmasm/           ibmasmfs
/var/lib/nfs/rpc_pipefs/   rpc_pipefs

Eric W. Biederman (10):
mnt: Refactor the logic for mounting sysfs and proc in a user namespace
mnt: Modify fs_fully_visible to deal with mount attributes
vfs: Ignore unlocked mounts in fs_fully_visible
fs: Add helper functions for permanently empty directories.
sysctl: Allow creating permanently empty directories that serve as mountpoints.
proc: Allow creating permanently empty directories that serve as mount points
kernfs: Add support for always empty directories.
sysfs: Add support for permanently empty directories to serve as mount points.
sysfs: Create mountpoints with sysfs_create_mount_point
mnt: Update fs_fully_visible to test for permanently empty directories

 arch/s390/hypfs/inode.c      | 12 ++----
 drivers/firmware/efi/efi.c   |  6 +--
 fs/configfs/mount.c          | 10 ++---
 fs/debugfs/inode.c           | 11 ++---
 fs/fuse/inode.c              |  9 ++---
 fs/kernfs/dir.c              | 38 +++++++++++++++++-
 fs/kernfs/inode.c            |  2 +
 fs/libfs.c                   | 96 ++++++++++++++++++++++++++++++++++++++++++++
 fs/namespace.c               | 47 +++++++++++++++++++---
 fs/proc/generic.c            | 23 +++++++++++
 fs/proc/inode.c              |  4 ++
 fs/proc/internal.h           |  6 +++
 fs/proc/proc_sysctl.c        | 37 +++++++++++++++++
 fs/proc/root.c               |  9 ++---
 fs/pstore/inode.c            | 12 ++----
 fs/sysfs/dir.c               | 34 ++++++++++++++++
 fs/sysfs/mount.c             |  5 +--
 fs/tracefs/inode.c           |  6 +--
 include/linux/fs.h           |  4 +-
 include/linux/kernfs.h       |  3 ++
 include/linux/sysctl.h       |  3 ++
 include/linux/sysfs.h        | 16 ++++++++
 kernel/cgroup.c              | 10 ++---
 kernel/sysctl.c              |  8 +---
 security/inode.c             | 10 ++---
 security/selinux/selinuxfs.c | 11 +++--
 security/smack/smackfs.c     |  8 ++--
 27 files changed, 350 insertions(+), 90 deletions(-)

Eric

#56 lore raw

PATCH 4/10 fs: Add helper functions for permanently empty directories.

In reply to Eric W. Biederman

To ensure it is safe to mount proc and sysfs I need to check if filesystems that are mounted on top of them are mounted on truly empty directories. Given that some directories can gain entries over time, knowing that a directory is empty right now is insufficient.

Therefore add supporting infrastructure for permantently empty directories that proc and sysfs can use when they create mount points for filesystems and fs_fully_visible can use to test for permanently empty directories to ensure that nothing will be gained by mounting a fresh copy of proc or sysfs.

---
 fs/libfs.c         | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/fs.h |  2 ++
 2 files changed, 98 insertions(+)
fs/libfs.c +96 -0
index cb1fb4b9b637..02813592e121 100644
@@ -1093,3 +1093,99 @@ simple_nosetlease(struct file *filp, long arg, struct file_lock **flp,
 	return -EINVAL;
 }
 EXPORT_SYMBOL(simple_nosetlease);
+
+
+/*
+ * Operations for a permanently empty directory.
+ */
+static struct dentry *empty_dir_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
+{
+	return ERR_PTR(-ENOENT);
+}
+
+static int empty_dir_getattr(struct vfsmount *mnt, struct dentry *dentry,
+				 struct kstat *stat)
+{
+	struct inode *inode = d_inode(dentry);
+	generic_fillattr(inode, stat);
+	return 0;
+}
+
+static int empty_dir_setattr(struct dentry *dentry, struct iattr *attr)
+{
+	return -EPERM;
+}
+
+static int empty_dir_setxattr(struct dentry *dentry, const char *name,
+			      const void *value, size_t size, int flags)
+{
+	return -EOPNOTSUPP;
+}
+
+static ssize_t empty_dir_getxattr(struct dentry *dentry, const char *name,
+				  void *value, size_t size)
+{
+	return -EOPNOTSUPP;
+}
+
+static int empty_dir_removexattr(struct dentry *dentry, const char *name)
+{
+	return -EOPNOTSUPP;
+}
+
+static ssize_t empty_dir_listxattr(struct dentry *dentry, char *list, size_t size)
+{
+	return -EOPNOTSUPP;
+}
+
+static const struct inode_operations empty_dir_inode_operations = {
+	.lookup		= empty_dir_lookup,
+	.permission	= generic_permission,
+	.setattr	= empty_dir_setattr,
+	.getattr	= empty_dir_getattr,
+	.setxattr	= empty_dir_setxattr,
+	.getxattr	= empty_dir_getxattr,
+	.removexattr	= empty_dir_removexattr,
+	.listxattr	= empty_dir_listxattr,
+};
+
+static loff_t empty_dir_llseek(struct file *file, loff_t offset, int whence)
+{
+	/* An empty directory has two entries . and .. at offsets 0 and 1 */
+	return generic_file_llseek_size(file, offset, whence, 2, 2);
+}
+
+static int empty_dir_readdir(struct file *file, struct dir_context *ctx)
+{
+	dir_emit_dots(file, ctx);
+	return 0;
+}
+
+static const struct file_operations empty_dir_operations = {
+	.llseek		= empty_dir_llseek,
+	.read		= generic_read_dir,
+	.iterate	= empty_dir_readdir,
+	.fsync		= noop_fsync,
+};
+
+
+void make_empty_dir_inode(struct inode *inode)
+{
+	set_nlink(inode, 2);
+	inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
+	inode->i_uid = GLOBAL_ROOT_UID;
+	inode->i_gid = GLOBAL_ROOT_GID;
+	inode->i_rdev = 0;
+	inode->i_size = 2;
+	inode->i_blkbits = PAGE_SHIFT;
+	inode->i_blocks = 0;
+
+	inode->i_op = &empty_dir_inode_operations;
+	inode->i_fop = &empty_dir_operations;
+}
+
+bool is_empty_dir_inode(struct inode *inode)
+{
+	return (inode->i_fop == &empty_dir_operations) &&
+		(inode->i_op == &empty_dir_inode_operations);
+}
include/linux/fs.h +2 -0
index 2d24eeb8e59c..571aab91bfc0 100644
@@ -2780,6 +2780,8 @@ extern struct dentry *simple_lookup(struct inode *, struct dentry *, unsigned in
 extern ssize_t generic_read_dir(struct file *, char __user *, size_t, loff_t *);
 extern const struct file_operations simple_dir_operations;
 extern const struct inode_operations simple_dir_inode_operations;
+extern void make_empty_dir_inode(struct inode *inode);
+extern bool is_empty_dir_inode(struct inode *inode);
 struct tree_descr { char *name; const struct file_operations *ops; int mode; };
 struct dentry *d_alloc_name(struct dentry *, const char *);
 extern int simple_fill_super(struct super_block *, unsigned long, struct tree_descr *);
Signature · 1 line
2.2.1
#57 lore raw

PATCH 5/10 sysctl: Allow creating permanently empty directories.

In reply to Eric W. Biederman

Add a magic sysctl table permanently_empty_table that when used to create a directory forces that directory to be permanently empty.

Update the code to use make_empty_dir_inode when accessing permanently empty directories.

Update the code to not allow adding to permanently empty directories.

Update /proc/sys/fs/binfmt_misc to be a permanently empty directory.

---
 fs/proc/proc_sysctl.c  | 37 +++++++++++++++++++++++++++++++++++++
 include/linux/sysctl.h |  3 +++
 kernel/sysctl.c        |  8 +-------
 3 files changed, 41 insertions(+), 7 deletions(-)
fs/proc/proc_sysctl.c +37 -0
index fea2561d773b..f9ade2caf438 100644
@@ -19,6 +19,28 @@ static const struct inode_operations proc_sys_inode_operations;
 static const struct file_operations proc_sys_dir_file_operations;
 static const struct inode_operations proc_sys_dir_operations;
 
+/* Support for permanently empty directories */
+
+struct ctl_table permanently_empty_table[] = {
+	{ }
+};
+
+static bool is_empty_dir(struct ctl_table_header *head)
+{
+	return head->ctl_table[0].child == permanently_empty_table;
+}
+
+static void set_empty_dir(struct ctl_dir *dir)
+{
+	dir->header.ctl_table[0].child = permanently_empty_table;
+}
+
+static void clear_empty_dir(struct ctl_dir *dir)
+
+{
+	dir->header.ctl_table[0].child = NULL;
+}
+
 void proc_sys_poll_notify(struct ctl_table_poll *poll)
 {
 	if (!poll)
@@ -187,6 +209,17 @@ static int insert_header(struct ctl_dir *dir, struct ctl_table_header *header)
 	struct ctl_table *entry;
 	int err;
 
+	/* Is this a permanently empty directory? */
+	if (is_empty_dir(&dir->header))
+		return -EROFS;
+
+	/* Am I creating a permanently empty directory? */
+	if (header->ctl_table == permanently_empty_table) {
+		if (!RB_EMPTY_ROOT(&dir->root))
+			return -EINVAL;
+		set_empty_dir(dir);
+	}
+
 	dir->header.nreg++;
 	header->parent = dir;
 	err = insert_links(header);
@@ -202,6 +235,8 @@ fail:
 	erase_header(header);
 	put_links(header);
 fail_links:
+	if (header->ctl_table == permanently_empty_table)
+		clear_empty_dir(dir);
 	header->parent = NULL;
 	drop_sysctl_table(&dir->header);
 	return err;
@@ -419,6 +454,8 @@ static struct inode *proc_sys_make_inode(struct super_block *sb,
 		inode->i_mode |= S_IFDIR;
 		inode->i_op = &proc_sys_dir_operations;
 		inode->i_fop = &proc_sys_dir_file_operations;
+		if (is_empty_dir(head))
+			make_empty_dir_inode(inode);
 	}
 out:
 	return inode;
include/linux/sysctl.h +3 -0
index 795d5fea5697..71fd81994a82 100644
@@ -188,6 +188,9 @@ struct ctl_table_header *register_sysctl_paths(const struct ctl_path *path,
 void unregister_sysctl_table(struct ctl_table_header * table);
 
 extern int sysctl_init(void);
+
+extern struct ctl_table permanently_empty_table[];
+
 #else /* CONFIG_SYSCTL */
 static inline struct ctl_table_header *register_sysctl_table(struct ctl_table * table)
 {
kernel/sysctl.c +1 -7
index 2082b1a88fb9..92f41a43875e 100644
@@ -1531,12 +1531,6 @@ static struct ctl_table vm_table[] = {
 	{ }
 };
 
-#if defined(CONFIG_BINFMT_MISC) || defined(CONFIG_BINFMT_MISC_MODULE)
-static struct ctl_table binfmt_misc_table[] = {
-	{ }
-};
-#endif
-
 static struct ctl_table fs_table[] = {
 	{
 		.procname	= "inode-nr",
@@ -1690,7 +1684,7 @@ static struct ctl_table fs_table[] = {
 	{
 		.procname	= "binfmt_misc",
 		.mode		= 0555,
-		.child		= binfmt_misc_table,
+		.child		= permanently_empty_table,
 	},
 #endif
 	{
Signature · 1 line
2.2.1
#58 lore raw
In reply to Eric W. Biederman
Quoted 25 lines · Eric W. Biederman

The code is currently available at:

git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace.git for-testing

HEAD: a524faf520600968e58bbc732063fccf2fdf9199 mnt: Update fs_fully_visible to test for permanently empty directories

The problem: Mounting a new instance of proc of sysfs can allow things that a bind mount of those filesystems would not.

That is the cases I am dealing with are:
unshare --user --net --mount ; mount -t sysfs ... unshare --user --pid --mount ; mount -t proc ...

The big change is that this set of changes enforces the preservation of locked mount flags, from the existing mount to the current mount. Which means that if proc was mounted read-only the current current will allow a new instance of proc to be mounted read-write, and this set of changes enforces that proc remain read-only.

The other gotcha is that the current code does not properly detect empty directories so to prevent things slipping through the cracks this set of changes annotates all mount points where nothing will be revealed if the filesystem mounted on top is removed.

Quoted 6 lines

Enforcing the administrators policy can actually matter in the real world as has been shown by the recent docker issue.

With this patchset I have two concerns:
- The enforcement of mount flag preservation on proc and sysfs may break things. (I am especially worried about the implicit adding of nodev).

What do you mean by this? What got added?

Quoted 7 lines

- I missed a filesystem mountpoint on proc or sysfs which would make a fresh copy unmountable for no good reason.

I don't want to break userspace if I can help it, and the code has been this way for a while so I figure there is time to find any pitfalls and address them before this code gets merged.

Quoted 8 lines

So if this works for you please give me your Tested-By

The well known mountpoints for pseudo filesystems that I could find are:

/dev/ffs*/                 functionfs
/dev/gadget/               gadgetfs
/dev/mqueue                mqueue
/dev/oprofile/             oprofilefs
/dev/pts/                  devpts

/dev/shm gets a tmpfs, right? Or do those not matter here?

Quoted 10 lines
/dlm/                      ocfs2_dlmfs
/ipath/                    ipathfs
/proc/fs/nfsd/             nfsd
/proc/openprom/            openpromfs
/proc/sys/fs/binfmt_misc/  binfmt_misc
/spu/                      spufs

/sys/firmware/efi/efivars/ efivarfs
/sys/fs/cgroup/ cgroup
/sys/fs/fuse/connections/ fusectl

I thought fuse mounted a few more things in here, but I don't know for sure.

Quoted 8 lines
/sys/fs/pstore/            pstore
/sys/fs/selinux/           selinuxfs
/sys/fs/smackfs/           smackfs
/sys/hypervisor/s390/      s390_hypfs
/sys/kernel/config/        configfs
/sys/kernel/debug/         debugfs
/sys/kernel/security/      securityfs
/sys/kernel/tracing/       tracefs

I think these are all correct for sysfs, I have a minor comment on the sysfs patch I'll make in it.

thanks,

greg k-h

#59 lore raw
Quoted 26 lines · Greg Kroah-Hartman
Quoted 25 lines · Eric W. Biederman

The code is currently available at:

git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace.git for-testing

HEAD: a524faf520600968e58bbc732063fccf2fdf9199 mnt: Update fs_fully_visible to test for permanently empty directories

The problem: Mounting a new instance of proc of sysfs can allow things that a bind mount of those filesystems would not.

That is the cases I am dealing with are:
unshare --user --net --mount ; mount -t sysfs ... unshare --user --pid --mount ; mount -t proc ...

The big change is that this set of changes enforces the preservation of locked mount flags, from the existing mount to the current mount. Which means that if proc was mounted read-only the current current will allow a new instance of proc to be mounted read-write, and this set of changes enforces that proc remain read-only.

The other gotcha is that the current code does not properly detect empty directories so to prevent things slipping through the cracks this set of changes annotates all mount points where nothing will be revealed if the filesystem mounted on top is removed.

Quoted 8 lines
Quoted 6 lines

Enforcing the administrators policy can actually matter in the real world as has been shown by the recent docker issue.

With this patchset I have two concerns:
- The enforcement of mount flag preservation on proc and sysfs may break things. (I am especially worried about the implicit adding of nodev).

What do you mean by this? What got added?

In a user namespace mounting a filesystem implicitly adds nodev.

When I started enforcing not clearing bits that root had set on a filesystem in mount -o remount the implicit nodev wound up being an issue that broke userspace for no good reason. The fix was to implicitly add nodev in remount as well.

Taking a second look at this nodev is implicitly added before the fs_fully_visible check so even for applications that are know how the original proc was mounted (and don't see an implicit nodev) and that don't add nodev (because they ''know'' the mount flags) this change should not be a problem. Hooray! One less scary thing.

Quoted 9 lines
Quoted 9 lines

- I missed a filesystem mountpoint on proc or sysfs which would make a fresh copy unmountable for no good reason.

I don't want to break userspace if I can help it, and the code has been this way for a while so I figure there is time to find any pitfalls and address them before this code gets merged.

So if this works for you please give me your Tested-By

Quoted 8 lines
Quoted 6 lines

The well known mountpoints for pseudo filesystems that I could find are:

/dev/ffs*/                 functionfs
/dev/gadget/               gadgetfs
/dev/mqueue                mqueue
/dev/oprofile/             oprofilefs
/dev/pts/                  devpts

/dev/shm gets a tmpfs, right? Or do those not matter here?

It does, but it doesn't matter in this context. I was looking for
things that mounted themselves on proc or sysfs and I catalogued the rest just to know they were not mounted there.

Quoted 7 lines
Quoted 6 lines
/dlm/                      ocfs2_dlmfs
/ipath/                    ipathfs
/proc/fs/nfsd/             nfsd
/proc/openprom/            openpromfs
/proc/sys/fs/binfmt_misc/  binfmt_misc
/spu/                      spufs
Quoted 6 lines
Quoted 3 lines

/sys/firmware/efi/efivars/ efivarfs
/sys/fs/cgroup/ cgroup
/sys/fs/fuse/connections/ fusectl

I thought fuse mounted a few more things in here, but I don't know for sure.

There are definitely some fuse attributes under /sys/fs/fuse/ but I don't see anything else in the code that could be creating a mount point.

Quoted 11 lines
Quoted 8 lines
/sys/fs/pstore/            pstore
/sys/fs/selinux/           selinuxfs
/sys/fs/smackfs/           smackfs
/sys/hypervisor/s390/      s390_hypfs
/sys/kernel/config/        configfs
/sys/kernel/debug/         debugfs
/sys/kernel/security/      securityfs
/sys/kernel/tracing/       tracefs

I think these are all correct for sysfs, I have a minor comment on the sysfs patch I'll make in it.

Good to hear and I will answer there as well.

Eric

A message that is not in the archive (sent off-list or not yet received): [email protected]

#61 lore raw
Quoted 44 lines · Eric W. Biederman
Quoted 26 lines · Greg Kroah-Hartman
Quoted 25 lines · Eric W. Biederman

The code is currently available at:

git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace.git for-testing

HEAD: a524faf520600968e58bbc732063fccf2fdf9199 mnt: Update fs_fully_visible to test for permanently empty directories

The problem: Mounting a new instance of proc of sysfs can allow things that a bind mount of those filesystems would not.

That is the cases I am dealing with are:
unshare --user --net --mount ; mount -t sysfs ... unshare --user --pid --mount ; mount -t proc ...

The big change is that this set of changes enforces the preservation of locked mount flags, from the existing mount to the current mount. Which means that if proc was mounted read-only the current current will allow a new instance of proc to be mounted read-write, and this set of changes enforces that proc remain read-only.

The other gotcha is that the current code does not properly detect empty directories so to prevent things slipping through the cracks this set of changes annotates all mount points where nothing will be revealed if the filesystem mounted on top is removed.

Quoted 8 lines
Quoted 6 lines

Enforcing the administrators policy can actually matter in the real world as has been shown by the recent docker issue.

With this patchset I have two concerns:
- The enforcement of mount flag preservation on proc and sysfs may break things. (I am especially worried about the implicit adding of nodev).

What do you mean by this? What got added?

In a user namespace mounting a filesystem implicitly adds nodev.

When I started enforcing not clearing bits that root had set on a filesystem in mount -o remount the implicit nodev wound up being an issue that broke userspace for no good reason. The fix was to implicitly add nodev in remount as well.

Quoted 5 lines

Taking a second look at this nodev is implicitly added before the fs_fully_visible check so even for applications that are know how the original proc was mounted (and don't see an implicit nodev) and that don't add nodev (because they ''know'' the mount flags) this change should not be a problem. Hooray! One less scary thing.

Can we please just get rid of this implicit nodev thing once and for all? If it breaks some really weird /proc use case, then I think the right fix is to stop enforcing the nodev lock for the proc fully visible check. After all, /proc doesn't contain useful device nodes anyway.

Other than that, the code here looks okay to me on brief inspection.

--Andy

A message that is not in the archive (sent off-list or not yet received): CALCETrU1yxcDfv4YV3wVpWMAdiOOsSUFOPUpFAN-mVA4M-OxdQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org

#63 lore raw
Quoted 4 lines · Andy Lutomirski

Can we please just get rid of this implicit nodev thing once and for all? If it breaks some really weird /proc use case, then I think the right fix is to stop enforcing the nodev lock for the proc fully visible check. After all, /proc doesn't contain useful device nodes anyway.

On second look I don't think that will actually cause issues in this case.

I actually have a fix for the implicit nodev weirdness in my development qeueue but it requires figuring out how to add s_user_ns to superblocks. My last round of testing told me I was doing that wrong.

But if the implicit nodev is actually a problem I will definitely delay this until I have that change ready to go as well.

Quoted 1 line

Other than that, the code here looks okay to me on brief inspection.

At a practical level I am concerned that enforcing things like noexec and nosuid from the original normal global proc might cause problems for things like sandstorm, lxc, and possibly libvirt-lxc. So I would really appreciate if people associated with those projects could test this and tell me if I break things.

Other than my stupid refactor in my code for /proc/fs/nfsd that causes the kernel to oops :( Doh!

Eric

#64 lore raw
In reply to a message not in the archive
Quoted 4 lines · Andy Lutomirski

Can we please just get rid of this implicit nodev thing once and for all? If it breaks some really weird /proc use case, then I think the right fix is to stop enforcing the nodev lock for the proc fully visible check. After all, /proc doesn't contain useful device nodes anyway.

On second look I don't think that will actually cause issues in this case.

I actually have a fix for the implicit nodev weirdness in my development qeueue but it requires figuring out how to add s_user_ns to superblocks. My last round of testing told me I was doing that wrong.

But if the implicit nodev is actually a problem I will definitely delay this until I have that change ready to go as well.

Quoted 1 line

Other than that, the code here looks okay to me on brief inspection.

At a practical level I am concerned that enforcing things like noexec and nosuid from the original normal global proc might cause problems for things like sandstorm, lxc, and possibly libvirt-lxc. So I would really appreciate if people associated with those projects could test this and tell me if I break things.

Other than my stupid refactor in my code for /proc/fs/nfsd that causes the kernel to oops :( Doh!

Eric

#65 lore raw
In reply to a message not in the archive
Quoted 44 lines · Eric W. Biederman
Quoted 26 lines · Greg Kroah-Hartman
Quoted 25 lines · Eric W. Biederman

The code is currently available at:

git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace.git for-testing

HEAD: a524faf520600968e58bbc732063fccf2fdf9199 mnt: Update fs_fully_visible to test for permanently empty directories

The problem: Mounting a new instance of proc of sysfs can allow things that a bind mount of those filesystems would not.

That is the cases I am dealing with are:
unshare --user --net --mount ; mount -t sysfs ... unshare --user --pid --mount ; mount -t proc ...

The big change is that this set of changes enforces the preservation of locked mount flags, from the existing mount to the current mount. Which means that if proc was mounted read-only the current current will allow a new instance of proc to be mounted read-write, and this set of changes enforces that proc remain read-only.

The other gotcha is that the current code does not properly detect empty directories so to prevent things slipping through the cracks this set of changes annotates all mount points where nothing will be revealed if the filesystem mounted on top is removed.

Quoted 8 lines
Quoted 6 lines

Enforcing the administrators policy can actually matter in the real world as has been shown by the recent docker issue.

With this patchset I have two concerns:
- The enforcement of mount flag preservation on proc and sysfs may break things. (I am especially worried about the implicit adding of nodev).

What do you mean by this? What got added?

In a user namespace mounting a filesystem implicitly adds nodev.

When I started enforcing not clearing bits that root had set on a filesystem in mount -o remount the implicit nodev wound up being an issue that broke userspace for no good reason. The fix was to implicitly add nodev in remount as well.

Quoted 5 lines

Taking a second look at this nodev is implicitly added before the fs_fully_visible check so even for applications that are know how the original proc was mounted (and don't see an implicit nodev) and that don't add nodev (because they ''know'' the mount flags) this change should not be a problem. Hooray! One less scary thing.

Can we please just get rid of this implicit nodev thing once and for all? If it breaks some really weird /proc use case, then I think the right fix is to stop enforcing the nodev lock for the proc fully visible check. After all, /proc doesn't contain useful device nodes anyway.

Other than that, the code here looks okay to me on brief inspection.

--Andy

A message that is not in the archive (sent off-list or not yet received): [email protected]

#67 lore raw
Quoted 26 lines · Greg Kroah-Hartman
Quoted 25 lines · Eric W. Biederman

The code is currently available at:

git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace.git for-testing

HEAD: a524faf520600968e58bbc732063fccf2fdf9199 mnt: Update fs_fully_visible to test for permanently empty directories

The problem: Mounting a new instance of proc of sysfs can allow things that a bind mount of those filesystems would not.

That is the cases I am dealing with are:
unshare --user --net --mount ; mount -t sysfs ... unshare --user --pid --mount ; mount -t proc ...

The big change is that this set of changes enforces the preservation of locked mount flags, from the existing mount to the current mount. Which means that if proc was mounted read-only the current current will allow a new instance of proc to be mounted read-write, and this set of changes enforces that proc remain read-only.

The other gotcha is that the current code does not properly detect empty directories so to prevent things slipping through the cracks this set of changes annotates all mount points where nothing will be revealed if the filesystem mounted on top is removed.

Quoted 8 lines
Quoted 6 lines

Enforcing the administrators policy can actually matter in the real world as has been shown by the recent docker issue.

With this patchset I have two concerns:
- The enforcement of mount flag preservation on proc and sysfs may break things. (I am especially worried about the implicit adding of nodev).

What do you mean by this? What got added?

In a user namespace mounting a filesystem implicitly adds nodev.

When I started enforcing not clearing bits that root had set on a filesystem in mount -o remount the implicit nodev wound up being an issue that broke userspace for no good reason. The fix was to implicitly add nodev in remount as well.

Taking a second look at this nodev is implicitly added before the fs_fully_visible check so even for applications that are know how the original proc was mounted (and don't see an implicit nodev) and that don't add nodev (because they ''know'' the mount flags) this change should not be a problem. Hooray! One less scary thing.

Quoted 9 lines
Quoted 9 lines

- I missed a filesystem mountpoint on proc or sysfs which would make a fresh copy unmountable for no good reason.

I don't want to break userspace if I can help it, and the code has been this way for a while so I figure there is time to find any pitfalls and address them before this code gets merged.

So if this works for you please give me your Tested-By

Quoted 8 lines
Quoted 6 lines

The well known mountpoints for pseudo filesystems that I could find are:

/dev/ffs*/                 functionfs
/dev/gadget/               gadgetfs
/dev/mqueue                mqueue
/dev/oprofile/             oprofilefs
/dev/pts/                  devpts

/dev/shm gets a tmpfs, right? Or do those not matter here?

It does, but it doesn't matter in this context. I was looking for
things that mounted themselves on proc or sysfs and I catalogued the rest just to know they were not mounted there.

Quoted 7 lines
Quoted 6 lines
/dlm/                      ocfs2_dlmfs
/ipath/                    ipathfs
/proc/fs/nfsd/             nfsd
/proc/openprom/            openpromfs
/proc/sys/fs/binfmt_misc/  binfmt_misc
/spu/                      spufs
Quoted 6 lines
Quoted 3 lines

/sys/firmware/efi/efivars/ efivarfs
/sys/fs/cgroup/ cgroup
/sys/fs/fuse/connections/ fusectl

I thought fuse mounted a few more things in here, but I don't know for sure.

There are definitely some fuse attributes under /sys/fs/fuse/ but I don't see anything else in the code that could be creating a mount point.

Quoted 11 lines
Quoted 8 lines
/sys/fs/pstore/            pstore
/sys/fs/selinux/           selinuxfs
/sys/fs/smackfs/           smackfs
/sys/hypervisor/s390/      s390_hypfs
/sys/kernel/config/        configfs
/sys/kernel/debug/         debugfs
/sys/kernel/security/      securityfs
/sys/kernel/tracing/       tracefs

I think these are all correct for sysfs, I have a minor comment on the sysfs patch I'll make in it.

Good to hear and I will answer there as well.

Eric

#68 lore raw

cover Making new mounts of proc and sysfs as safe as bind mounts (take 2)

In reply to Eric W. Biederman

The code is currently available at:

git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace.git for-testing

HEAD: 513d98ba1adfa9e3178b6fc3b2fa57a622283d32 mnt: Update fs_fully_visible to test for permanently empty directories

The problem: Mounting a new instance of proc of sysfs can allow things that a bind mount of those filesystems would not.

That is the cases I am dealing with are:
unshare --user --net --mount ; mount -t sysfs ... unshare --user --pid --mount ; mount -t proc ...

This set of changes enforces the preservation of locked mount flags, from the existing mount to the current mount. Which means that if proc was mounted read-only the current current will allow a new instance of proc to be mounted read-write, and this set of changes enforces that proc remain read-only.

This set of changes also updates sysctl, proc and sysfs to explicitly create the directories they expect to be mount points as mount points. Making the code a little clearly and making it so when fs_fully_visible disregards something mounted on a proc or sysfs it is guaranteed to be safe, unlike the current code which can occassionally let things fall through the cracks.

These changes to enforce the administrators policy can actually matter in the real world as has been shown by the recent docker issue.

With this patchset I have two concerns:
- The enforcement of not being able to mount proc or sysfs with fewer mount flags than the existing mount may break something.

- That there is a filesystem that that common mounts on proc or sysfs and I missed annotating it's mount point. That would make mounting a freshy copy of proc or sysfs impossible.

I don't want to break userspace if I can help it, and the code has been this way for a while so I figure there is time to find any pitfalls and address them before this code gets merged. Folks rom lxc, sandstorm, libvirt-lxc (anyone who uses user namespaces in the least) a confirmation that I have not broken your existing code would be appreciated.

If this works for you please give me your Tested-By

Since the first version I have renamed the directory creation calls to have sysfs_create_mount_point and proc_create_mount_point (as suggested by Greg KH so that it is very clear what the code that creates those mount points is doing. I have also fixed a stupid bug that slipped into the proc code when I refactored it. I have also gone through and rested everything so hopefully nothing has slipped past me.

The well known mountpoints for pseudo filesystems that I could find are:

/dev/ffs*/                 functionfs
/dev/gadget/               gadgetfs
/dev/mqueue                mqueue
/dev/oprofile/             oprofilefs
/dev/pts/                  devpts
/dev/shm/                  tmpfs
/dlm/                      ocfs2_dlmfs
/ipath/                    ipathfs
/proc/fs/nfsd/             nfsd
/proc/openprom/            openpromfs
/proc/sys/fs/binfmt_misc/  binfmt_misc
/spu/                      spufs
/sys/firmware/efi/efivars/ efivarfs
/sys/fs/cgroup/            cgroup
/sys/fs/fuse/connections/  fusectl
/sys/fs/pstore/            pstore
/sys/fs/selinux/           selinuxfs
/sys/fs/smackfs/           smackfs
/sys/hypervisor/s390/      s390_hypfs
/sys/kernel/config/        configfs
/sys/kernel/debug/         debugfs
/sys/kernel/security/      securityfs
/sys/kernel/tracing/       tracefs
/var/lib/ibmasm/           ibmasmfs
/var/lib/nfs/rpc_pipefs/   rpc_pipefs

Eric W. Biederman (10):
mnt: Refactor the logic for mounting sysfs and proc in a user namespace
mnt: Modify fs_fully_visible to deal with mount attributes
vfs: Ignore unlocked mounts in fs_fully_visible
fs: Add helper functions for permanently empty directories.
sysctl: Allow creating permanently empty directories that serve as mountpoints.
proc: Allow creating permanently empty directories that serve as mount points
kernfs: Add support for always empty directories.
sysfs: Add support for permanently empty directories to serve as mount points.
sysfs: Create mountpoints with sysfs_create_mount_point
mnt: Update fs_fully_visible to test for permanently empty directories

 arch/s390/hypfs/inode.c      | 12 ++----
 drivers/firmware/efi/efi.c   |  6 +--
 fs/configfs/mount.c          | 10 ++---
 fs/debugfs/inode.c           | 11 ++---
 fs/fuse/inode.c              |  9 ++---
 fs/kernfs/dir.c              | 38 +++++++++++++++++-
 fs/kernfs/inode.c            |  2 +
 fs/libfs.c                   | 96 ++++++++++++++++++++++++++++++++++++++++++++
 fs/namespace.c               | 47 +++++++++++++++++++---
 fs/proc/generic.c            | 23 +++++++++++
 fs/proc/inode.c              |  4 ++
 fs/proc/internal.h           |  6 +++
 fs/proc/proc_sysctl.c        | 37 +++++++++++++++++
 fs/proc/root.c               |  9 ++---
 fs/pstore/inode.c            | 12 ++----
 fs/sysfs/dir.c               | 34 ++++++++++++++++
 fs/sysfs/mount.c             |  5 +--
 fs/tracefs/inode.c           |  6 +--
 include/linux/fs.h           |  4 +-
 include/linux/kernfs.h       |  3 ++
 include/linux/sysctl.h       |  3 ++
 include/linux/sysfs.h        | 16 ++++++++
 kernel/cgroup.c              | 10 ++---
 kernel/sysctl.c              |  8 +---
 security/inode.c             | 10 ++---
 security/selinux/selinuxfs.c | 11 +++--
 security/smack/smackfs.c     |  8 ++--
 27 files changed, 350 insertions(+), 90 deletions(-)

Eric

A message that is not in the archive (sent off-list or not yet received): [email protected]

#70 lore raw

PATCH 1/10 mnt: Refactor the logic for mounting sysfs and proc in a user namespace

Fresh mounts of proc and sysfs are a very special case that works very much like a bind mount. Unfortunately the current structure can not preserve the MNT_LOCK... mount flags. Therefore refactor the logic into a form that can be modified to preserve those lock bits.

Add a new filesystem flag FS_USERNS_VISIBLE that requires some mount of the filesystem be fully visible in the current mount namespace, before the filesystem may be mounted.

Move the logic for calling fs_fully_visible from proc and sysfs into fs/namespace.c where it has greater access to mount namespace state.

---
 fs/namespace.c     | 8 +++++++-
 fs/proc/root.c     | 5 +----
 fs/sysfs/mount.c   | 5 +----
 include/linux/fs.h | 2 +-
 4 files changed, 10 insertions(+), 10 deletions(-)
fs/namespace.c +7 -1
index 1b9e11167bae..8e7edaf60fe1 100644
@@ -2332,6 +2332,8 @@ unlock:
 	return err;
 }
 
+static bool fs_fully_visible(struct file_system_type *fs_type);
+
 /*
  * create a new mount for userspace and request it to be added into the
  * namespace's tree
@@ -2363,6 +2365,10 @@ static int do_new_mount(struct path *path, const char *fstype, int flags,
 			flags |= MS_NODEV;
 			mnt_flags |= MNT_NODEV | MNT_LOCK_NODEV;
 		}
+		if (type->fs_flags & FS_USERNS_VISIBLE) {
+			if (!fs_fully_visible(type))
+				return -EPERM;
+		}
 	}
 
 	mnt = vfs_kern_mount(type, flags, name, data);
@@ -3164,7 +3170,7 @@ bool current_chrooted(void)
 	return chrooted;
 }
 
-bool fs_fully_visible(struct file_system_type *type)
+static bool fs_fully_visible(struct file_system_type *type)
 {
 	struct mnt_namespace *ns = current->nsproxy->mnt_ns;
 	struct mount *mnt;
fs/proc/root.c +1 -4
index b7fa4bfe896a..64e1ab64bde6 100644
@@ -112,9 +112,6 @@ static struct dentry *proc_mount(struct file_system_type *fs_type,
 		ns = task_active_pid_ns(current);
 		options = data;
 
-		if (!capable(CAP_SYS_ADMIN) && !fs_fully_visible(fs_type))
-			return ERR_PTR(-EPERM);
-
 		/* Does the mounter have privilege over the pid namespace? */
 		if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN))
 			return ERR_PTR(-EPERM);
@@ -159,7 +156,7 @@ static struct file_system_type proc_fs_type = {
 	.name		= "proc",
 	.mount		= proc_mount,
 	.kill_sb	= proc_kill_sb,
-	.fs_flags	= FS_USERNS_MOUNT,
+	.fs_flags	= FS_USERNS_VISIBLE | FS_USERNS_MOUNT,
 };
 
 void __init proc_root_init(void)
fs/sysfs/mount.c +1 -4
index 8a49486bf30c..1c6ac6fcee9f 100644
@@ -31,9 +31,6 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type,
 	bool new_sb;
 
 	if (!(flags & MS_KERNMOUNT)) {
-		if (!capable(CAP_SYS_ADMIN) && !fs_fully_visible(fs_type))
-			return ERR_PTR(-EPERM);
-
 		if (!kobj_ns_current_may_mount(KOBJ_NS_TYPE_NET))
 			return ERR_PTR(-EPERM);
 	}
@@ -58,7 +55,7 @@ static struct file_system_type sysfs_fs_type = {
 	.name		= "sysfs",
 	.mount		= sysfs_mount,
 	.kill_sb	= sysfs_kill_sb,
-	.fs_flags	= FS_USERNS_MOUNT,
+	.fs_flags	= FS_USERNS_VISIBLE | FS_USERNS_MOUNT,
 };
 
 int __init sysfs_init(void)
include/linux/fs.h +1 -1
index 35ec87e490b1..2d24eeb8e59c 100644
@@ -1897,6 +1897,7 @@ struct file_system_type {
 #define FS_HAS_SUBTYPE		4
 #define FS_USERNS_MOUNT		8	/* Can be mounted by userns root */
 #define FS_USERNS_DEV_MOUNT	16 /* A userns mount does not imply MNT_NODEV */
+#define FS_USERNS_VISIBLE	32	/* FS must already be visible */
 #define FS_RENAME_DOES_D_MOVE	32768	/* FS will handle d_move() during rename() internally. */
 	struct dentry *(*mount) (struct file_system_type *, int,
 		       const char *, void *);
@@ -1984,7 +1985,6 @@ extern int vfs_ustat(dev_t, struct kstatfs *);
 extern int freeze_super(struct super_block *super);
 extern int thaw_super(struct super_block *super);
 extern bool our_mnt(struct vfsmount *mnt);
-extern bool fs_fully_visible(struct file_system_type *);
 
 extern int current_umask(void);
 
Signature · 1 line
2.2.1
#71 lore raw

PATCH 1/10 mnt: Refactor the logic for mounting sysfs and proc in a user namespace

In reply to a message not in the archive

Fresh mounts of proc and sysfs are a very special case that works very much like a bind mount. Unfortunately the current structure can not preserve the MNT_LOCK... mount flags. Therefore refactor the logic into a form that can be modified to preserve those lock bits.

Add a new filesystem flag FS_USERNS_VISIBLE that requires some mount of the filesystem be fully visible in the current mount namespace, before the filesystem may be mounted.

Move the logic for calling fs_fully_visible from proc and sysfs into fs/namespace.c where it has greater access to mount namespace state.

---
 fs/namespace.c     | 8 +++++++-
 fs/proc/root.c     | 5 +----
 fs/sysfs/mount.c   | 5 +----
 include/linux/fs.h | 2 +-
 4 files changed, 10 insertions(+), 10 deletions(-)
fs/namespace.c +7 -1
index 1b9e11167bae..8e7edaf60fe1 100644
@@ -2332,6 +2332,8 @@ unlock:
 	return err;
 }
 
+static bool fs_fully_visible(struct file_system_type *fs_type);
+
 /*
  * create a new mount for userspace and request it to be added into the
  * namespace's tree
@@ -2363,6 +2365,10 @@ static int do_new_mount(struct path *path, const char *fstype, int flags,
 			flags |= MS_NODEV;
 			mnt_flags |= MNT_NODEV | MNT_LOCK_NODEV;
 		}
+		if (type->fs_flags & FS_USERNS_VISIBLE) {
+			if (!fs_fully_visible(type))
+				return -EPERM;
+		}
 	}
 
 	mnt = vfs_kern_mount(type, flags, name, data);
@@ -3164,7 +3170,7 @@ bool current_chrooted(void)
 	return chrooted;
 }
 
-bool fs_fully_visible(struct file_system_type *type)
+static bool fs_fully_visible(struct file_system_type *type)
 {
 	struct mnt_namespace *ns = current->nsproxy->mnt_ns;
 	struct mount *mnt;
fs/proc/root.c +1 -4
index b7fa4bfe896a..64e1ab64bde6 100644
@@ -112,9 +112,6 @@ static struct dentry *proc_mount(struct file_system_type *fs_type,
 		ns = task_active_pid_ns(current);
 		options = data;
 
-		if (!capable(CAP_SYS_ADMIN) && !fs_fully_visible(fs_type))
-			return ERR_PTR(-EPERM);
-
 		/* Does the mounter have privilege over the pid namespace? */
 		if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN))
 			return ERR_PTR(-EPERM);
@@ -159,7 +156,7 @@ static struct file_system_type proc_fs_type = {
 	.name		= "proc",
 	.mount		= proc_mount,
 	.kill_sb	= proc_kill_sb,
-	.fs_flags	= FS_USERNS_MOUNT,
+	.fs_flags	= FS_USERNS_VISIBLE | FS_USERNS_MOUNT,
 };
 
 void __init proc_root_init(void)
fs/sysfs/mount.c +1 -4
index 8a49486bf30c..1c6ac6fcee9f 100644
@@ -31,9 +31,6 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type,
 	bool new_sb;
 
 	if (!(flags & MS_KERNMOUNT)) {
-		if (!capable(CAP_SYS_ADMIN) && !fs_fully_visible(fs_type))
-			return ERR_PTR(-EPERM);
-
 		if (!kobj_ns_current_may_mount(KOBJ_NS_TYPE_NET))
 			return ERR_PTR(-EPERM);
 	}
@@ -58,7 +55,7 @@ static struct file_system_type sysfs_fs_type = {
 	.name		= "sysfs",
 	.mount		= sysfs_mount,
 	.kill_sb	= sysfs_kill_sb,
-	.fs_flags	= FS_USERNS_MOUNT,
+	.fs_flags	= FS_USERNS_VISIBLE | FS_USERNS_MOUNT,
 };
 
 int __init sysfs_init(void)
include/linux/fs.h +1 -1
index 35ec87e490b1..2d24eeb8e59c 100644
@@ -1897,6 +1897,7 @@ struct file_system_type {
 #define FS_HAS_SUBTYPE		4
 #define FS_USERNS_MOUNT		8	/* Can be mounted by userns root */
 #define FS_USERNS_DEV_MOUNT	16 /* A userns mount does not imply MNT_NODEV */
+#define FS_USERNS_VISIBLE	32	/* FS must already be visible */
 #define FS_RENAME_DOES_D_MOVE	32768	/* FS will handle d_move() during rename() internally. */
 	struct dentry *(*mount) (struct file_system_type *, int,
 		       const char *, void *);
@@ -1984,7 +1985,6 @@ extern int vfs_ustat(dev_t, struct kstatfs *);
 extern int freeze_super(struct super_block *super);
 extern int thaw_super(struct super_block *super);
 extern bool our_mnt(struct vfsmount *mnt);
-extern bool fs_fully_visible(struct file_system_type *);
 
 extern int current_umask(void);
 
Signature · 1 line
2.2.1
#72 lore raw

PATCH 2/10 mnt: Modify fs_fully_visible to deal with mount attributes

In reply to a message not in the archive

Ignore an existing mount if it's locked attributes are less permissive than the new mounts attributes.

On success ensure the new mount locks all of the same attributes as the old mount.

---
 fs/namespace.c | 32 +++++++++++++++++++++++++++++---
 1 file changed, 29 insertions(+), 3 deletions(-)
fs/namespace.c +29 -3
index 8e7edaf60fe1..fccee9924e8c 100644
@@ -2332,7 +2332,7 @@ unlock:
 	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
@@ -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;
 		}
 	}
@@ -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;
 
@@ -3191,6 +3192,25 @@ 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_NOSUID) &&
+		    !(new_flags & MNT_NOSUID))
+			continue;
+		if ((mnt->mnt.mnt_flags & MNT_LOCK_NOEXEC) &&
+		    !(new_flags & MNT_NOEXEC))
+			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.
 		 */
@@ -3201,6 +3221,12 @@ 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_NOSUID   | \
+							MNT_LOCK_NOEXEC   | \
+							MNT_LOCK_ATIME);
 		visible = true;
 		goto found;
 	next:	;
Signature · 1 line
2.2.1
#73 lore raw

PATCH 3/10 vfs: Ignore unlocked mounts in fs_fully_visible

In reply to a message not in the archive

Limit the mounts fs_fully_visible considers to locked mounts. Unlocked can always be unmounted so considering them adds hassle but no security benefit.

---
 fs/namespace.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)
fs/namespace.c +6 -2
index fccee9924e8c..3ede0669b8d2 100644
@@ -3211,11 +3211,15 @@ static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags)
 		    ((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.
+		/* This mount is not fully visible if there are any
+		 * locked child mounts that cover anything except for
+		 * empty directories.
 		 */
 		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))
+				continue;
 			if (!S_ISDIR(inode->i_mode))
 				goto next;
 			if (inode->i_nlink > 2)
Signature · 1 line
2.2.1
#74 lore raw

PATCH 3/10 vfs: Ignore unlocked mounts in fs_fully_visible

In reply to a message not in the archive

Limit the mounts fs_fully_visible considers to locked mounts. Unlocked can always be unmounted so considering them adds hassle but no security benefit.

---
 fs/namespace.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)
fs/namespace.c +6 -2
index fccee9924e8c..3ede0669b8d2 100644
@@ -3211,11 +3211,15 @@ static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags)
 		    ((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.
+		/* This mount is not fully visible if there are any
+		 * locked child mounts that cover anything except for
+		 * empty directories.
 		 */
 		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))
+				continue;
 			if (!S_ISDIR(inode->i_mode))
 				goto next;
 			if (inode->i_nlink > 2)
Signature · 1 line
2.2.1
#75 lore raw

PATCH 4/10 fs: Add helper functions for permanently empty directories.

In reply to a message not in the archive

To ensure it is safe to mount proc and sysfs I need to check if filesystems that are mounted on top of them are mounted on truly empty directories. Given that some directories can gain entries over time, knowing that a directory is empty right now is insufficient.

Therefore add supporting infrastructure for permantently empty directories that proc and sysfs can use when they create mount points for filesystems and fs_fully_visible can use to test for permanently empty directories to ensure that nothing will be gained by mounting a fresh copy of proc or sysfs.

---
 fs/libfs.c         | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/fs.h |  2 ++
 2 files changed, 98 insertions(+)
fs/libfs.c +96 -0
index cb1fb4b9b637..02813592e121 100644
@@ -1093,3 +1093,99 @@ simple_nosetlease(struct file *filp, long arg, struct file_lock **flp,
 	return -EINVAL;
 }
 EXPORT_SYMBOL(simple_nosetlease);
+
+
+/*
+ * Operations for a permanently empty directory.
+ */
+static struct dentry *empty_dir_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
+{
+	return ERR_PTR(-ENOENT);
+}
+
+static int empty_dir_getattr(struct vfsmount *mnt, struct dentry *dentry,
+				 struct kstat *stat)
+{
+	struct inode *inode = d_inode(dentry);
+	generic_fillattr(inode, stat);
+	return 0;
+}
+
+static int empty_dir_setattr(struct dentry *dentry, struct iattr *attr)
+{
+	return -EPERM;
+}
+
+static int empty_dir_setxattr(struct dentry *dentry, const char *name,
+			      const void *value, size_t size, int flags)
+{
+	return -EOPNOTSUPP;
+}
+
+static ssize_t empty_dir_getxattr(struct dentry *dentry, const char *name,
+				  void *value, size_t size)
+{
+	return -EOPNOTSUPP;
+}
+
+static int empty_dir_removexattr(struct dentry *dentry, const char *name)
+{
+	return -EOPNOTSUPP;
+}
+
+static ssize_t empty_dir_listxattr(struct dentry *dentry, char *list, size_t size)
+{
+	return -EOPNOTSUPP;
+}
+
+static const struct inode_operations empty_dir_inode_operations = {
+	.lookup		= empty_dir_lookup,
+	.permission	= generic_permission,
+	.setattr	= empty_dir_setattr,
+	.getattr	= empty_dir_getattr,
+	.setxattr	= empty_dir_setxattr,
+	.getxattr	= empty_dir_getxattr,
+	.removexattr	= empty_dir_removexattr,
+	.listxattr	= empty_dir_listxattr,
+};
+
+static loff_t empty_dir_llseek(struct file *file, loff_t offset, int whence)
+{
+	/* An empty directory has two entries . and .. at offsets 0 and 1 */
+	return generic_file_llseek_size(file, offset, whence, 2, 2);
+}
+
+static int empty_dir_readdir(struct file *file, struct dir_context *ctx)
+{
+	dir_emit_dots(file, ctx);
+	return 0;
+}
+
+static const struct file_operations empty_dir_operations = {
+	.llseek		= empty_dir_llseek,
+	.read		= generic_read_dir,
+	.iterate	= empty_dir_readdir,
+	.fsync		= noop_fsync,
+};
+
+
+void make_empty_dir_inode(struct inode *inode)
+{
+	set_nlink(inode, 2);
+	inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
+	inode->i_uid = GLOBAL_ROOT_UID;
+	inode->i_gid = GLOBAL_ROOT_GID;
+	inode->i_rdev = 0;
+	inode->i_size = 2;
+	inode->i_blkbits = PAGE_SHIFT;
+	inode->i_blocks = 0;
+
+	inode->i_op = &empty_dir_inode_operations;
+	inode->i_fop = &empty_dir_operations;
+}
+
+bool is_empty_dir_inode(struct inode *inode)
+{
+	return (inode->i_fop == &empty_dir_operations) &&
+		(inode->i_op == &empty_dir_inode_operations);
+}
include/linux/fs.h +2 -0
index 2d24eeb8e59c..571aab91bfc0 100644
@@ -2780,6 +2780,8 @@ extern struct dentry *simple_lookup(struct inode *, struct dentry *, unsigned in
 extern ssize_t generic_read_dir(struct file *, char __user *, size_t, loff_t *);
 extern const struct file_operations simple_dir_operations;
 extern const struct inode_operations simple_dir_inode_operations;
+extern void make_empty_dir_inode(struct inode *inode);
+extern bool is_empty_dir_inode(struct inode *inode);
 struct tree_descr { char *name; const struct file_operations *ops; int mode; };
 struct dentry *d_alloc_name(struct dentry *, const char *);
 extern int simple_fill_super(struct super_block *, unsigned long, struct tree_descr *);
Signature · 1 line
2.2.1
#76 lore raw

PATCH 4/10 fs: Add helper functions for permanently empty directories.

In reply to a message not in the archive

To ensure it is safe to mount proc and sysfs I need to check if filesystems that are mounted on top of them are mounted on truly empty directories. Given that some directories can gain entries over time, knowing that a directory is empty right now is insufficient.

Therefore add supporting infrastructure for permantently empty directories that proc and sysfs can use when they create mount points for filesystems and fs_fully_visible can use to test for permanently empty directories to ensure that nothing will be gained by mounting a fresh copy of proc or sysfs.

---
 fs/libfs.c         | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/fs.h |  2 ++
 2 files changed, 98 insertions(+)
fs/libfs.c +96 -0
index cb1fb4b9b637..02813592e121 100644
@@ -1093,3 +1093,99 @@ simple_nosetlease(struct file *filp, long arg, struct file_lock **flp,
 	return -EINVAL;
 }
 EXPORT_SYMBOL(simple_nosetlease);
+
+
+/*
+ * Operations for a permanently empty directory.
+ */
+static struct dentry *empty_dir_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
+{
+	return ERR_PTR(-ENOENT);
+}
+
+static int empty_dir_getattr(struct vfsmount *mnt, struct dentry *dentry,
+				 struct kstat *stat)
+{
+	struct inode *inode = d_inode(dentry);
+	generic_fillattr(inode, stat);
+	return 0;
+}
+
+static int empty_dir_setattr(struct dentry *dentry, struct iattr *attr)
+{
+	return -EPERM;
+}
+
+static int empty_dir_setxattr(struct dentry *dentry, const char *name,
+			      const void *value, size_t size, int flags)
+{
+	return -EOPNOTSUPP;
+}
+
+static ssize_t empty_dir_getxattr(struct dentry *dentry, const char *name,
+				  void *value, size_t size)
+{
+	return -EOPNOTSUPP;
+}
+
+static int empty_dir_removexattr(struct dentry *dentry, const char *name)
+{
+	return -EOPNOTSUPP;
+}
+
+static ssize_t empty_dir_listxattr(struct dentry *dentry, char *list, size_t size)
+{
+	return -EOPNOTSUPP;
+}
+
+static const struct inode_operations empty_dir_inode_operations = {
+	.lookup		= empty_dir_lookup,
+	.permission	= generic_permission,
+	.setattr	= empty_dir_setattr,
+	.getattr	= empty_dir_getattr,
+	.setxattr	= empty_dir_setxattr,
+	.getxattr	= empty_dir_getxattr,
+	.removexattr	= empty_dir_removexattr,
+	.listxattr	= empty_dir_listxattr,
+};
+
+static loff_t empty_dir_llseek(struct file *file, loff_t offset, int whence)
+{
+	/* An empty directory has two entries . and .. at offsets 0 and 1 */
+	return generic_file_llseek_size(file, offset, whence, 2, 2);
+}
+
+static int empty_dir_readdir(struct file *file, struct dir_context *ctx)
+{
+	dir_emit_dots(file, ctx);
+	return 0;
+}
+
+static const struct file_operations empty_dir_operations = {
+	.llseek		= empty_dir_llseek,
+	.read		= generic_read_dir,
+	.iterate	= empty_dir_readdir,
+	.fsync		= noop_fsync,
+};
+
+
+void make_empty_dir_inode(struct inode *inode)
+{
+	set_nlink(inode, 2);
+	inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
+	inode->i_uid = GLOBAL_ROOT_UID;
+	inode->i_gid = GLOBAL_ROOT_GID;
+	inode->i_rdev = 0;
+	inode->i_size = 2;
+	inode->i_blkbits = PAGE_SHIFT;
+	inode->i_blocks = 0;
+
+	inode->i_op = &empty_dir_inode_operations;
+	inode->i_fop = &empty_dir_operations;
+}
+
+bool is_empty_dir_inode(struct inode *inode)
+{
+	return (inode->i_fop == &empty_dir_operations) &&
+		(inode->i_op == &empty_dir_inode_operations);
+}
include/linux/fs.h +2 -0
index 2d24eeb8e59c..571aab91bfc0 100644
@@ -2780,6 +2780,8 @@ extern struct dentry *simple_lookup(struct inode *, struct dentry *, unsigned in
 extern ssize_t generic_read_dir(struct file *, char __user *, size_t, loff_t *);
 extern const struct file_operations simple_dir_operations;
 extern const struct inode_operations simple_dir_inode_operations;
+extern void make_empty_dir_inode(struct inode *inode);
+extern bool is_empty_dir_inode(struct inode *inode);
 struct tree_descr { char *name; const struct file_operations *ops; int mode; };
 struct dentry *d_alloc_name(struct dentry *, const char *);
 extern int simple_fill_super(struct super_block *, unsigned long, struct tree_descr *);
Signature · 1 line
2.2.1
#77 lore raw

PATCH 5/10 sysctl: Allow creating permanently empty directories that serve as mountpoints.

In reply to a message not in the archive

Add a magic sysctl table sysctl_mount_point that when used to create a directory forces that directory to be permanently empty.

Update the code to use make_empty_dir_inode when accessing permanently empty directories.

Update the code to not allow adding to permanently empty directories.

Update /proc/sys/fs/binfmt_misc to be a permanently empty directory.

---
 fs/proc/proc_sysctl.c  | 37 +++++++++++++++++++++++++++++++++++++
 include/linux/sysctl.h |  3 +++
 kernel/sysctl.c        |  8 +-------
 3 files changed, 41 insertions(+), 7 deletions(-)
fs/proc/proc_sysctl.c +37 -0
index fea2561d773b..fdda62e6115e 100644
@@ -19,6 +19,28 @@ static const struct inode_operations proc_sys_inode_operations;
 static const struct file_operations proc_sys_dir_file_operations;
 static const struct inode_operations proc_sys_dir_operations;
 
+/* Support for permanently empty directories */
+
+struct ctl_table sysctl_mount_point[] = {
+	{ }
+};
+
+static bool is_empty_dir(struct ctl_table_header *head)
+{
+	return head->ctl_table[0].child == sysctl_mount_point;
+}
+
+static void set_empty_dir(struct ctl_dir *dir)
+{
+	dir->header.ctl_table[0].child = sysctl_mount_point;
+}
+
+static void clear_empty_dir(struct ctl_dir *dir)
+
+{
+	dir->header.ctl_table[0].child = NULL;
+}
+
 void proc_sys_poll_notify(struct ctl_table_poll *poll)
 {
 	if (!poll)
@@ -187,6 +209,17 @@ static int insert_header(struct ctl_dir *dir, struct ctl_table_header *header)
 	struct ctl_table *entry;
 	int err;
 
+	/* Is this a permanently empty directory? */
+	if (is_empty_dir(&dir->header))
+		return -EROFS;
+
+	/* Am I creating a permanently empty directory? */
+	if (header->ctl_table == sysctl_mount_point) {
+		if (!RB_EMPTY_ROOT(&dir->root))
+			return -EINVAL;
+		set_empty_dir(dir);
+	}
+
 	dir->header.nreg++;
 	header->parent = dir;
 	err = insert_links(header);
@@ -202,6 +235,8 @@ fail:
 	erase_header(header);
 	put_links(header);
 fail_links:
+	if (header->ctl_table == sysctl_mount_point)
+		clear_empty_dir(dir);
 	header->parent = NULL;
 	drop_sysctl_table(&dir->header);
 	return err;
@@ -419,6 +454,8 @@ static struct inode *proc_sys_make_inode(struct super_block *sb,
 		inode->i_mode |= S_IFDIR;
 		inode->i_op = &proc_sys_dir_operations;
 		inode->i_fop = &proc_sys_dir_file_operations;
+		if (is_empty_dir(head))
+			make_empty_dir_inode(inode);
 	}
 out:
 	return inode;
include/linux/sysctl.h +3 -0
index 795d5fea5697..fa7bc29925c9 100644
@@ -188,6 +188,9 @@ struct ctl_table_header *register_sysctl_paths(const struct ctl_path *path,
 void unregister_sysctl_table(struct ctl_table_header * table);
 
 extern int sysctl_init(void);
+
+extern struct ctl_table sysctl_mount_point[];
+
 #else /* CONFIG_SYSCTL */
 static inline struct ctl_table_header *register_sysctl_table(struct ctl_table * table)
 {
kernel/sysctl.c +1 -7
index 2082b1a88fb9..c3eee4c6d6c1 100644
@@ -1531,12 +1531,6 @@ static struct ctl_table vm_table[] = {
 	{ }
 };
 
-#if defined(CONFIG_BINFMT_MISC) || defined(CONFIG_BINFMT_MISC_MODULE)
-static struct ctl_table binfmt_misc_table[] = {
-	{ }
-};
-#endif
-
 static struct ctl_table fs_table[] = {
 	{
 		.procname	= "inode-nr",
@@ -1690,7 +1684,7 @@ static struct ctl_table fs_table[] = {
 	{
 		.procname	= "binfmt_misc",
 		.mode		= 0555,
-		.child		= binfmt_misc_table,
+		.child		= sysctl_mount_point,
 	},
 #endif
 	{
Signature · 1 line
2.2.1
#78 lore raw

PATCH 5/10 sysctl: Allow creating permanently empty directories that serve as mountpoints.

In reply to a message not in the archive

Add a magic sysctl table sysctl_mount_point that when used to create a directory forces that directory to be permanently empty.

Update the code to use make_empty_dir_inode when accessing permanently empty directories.

Update the code to not allow adding to permanently empty directories.

Update /proc/sys/fs/binfmt_misc to be a permanently empty directory.

---
 fs/proc/proc_sysctl.c  | 37 +++++++++++++++++++++++++++++++++++++
 include/linux/sysctl.h |  3 +++
 kernel/sysctl.c        |  8 +-------
 3 files changed, 41 insertions(+), 7 deletions(-)
fs/proc/proc_sysctl.c +37 -0
index fea2561d773b..fdda62e6115e 100644
@@ -19,6 +19,28 @@ static const struct inode_operations proc_sys_inode_operations;
 static const struct file_operations proc_sys_dir_file_operations;
 static const struct inode_operations proc_sys_dir_operations;
 
+/* Support for permanently empty directories */
+
+struct ctl_table sysctl_mount_point[] = {
+	{ }
+};
+
+static bool is_empty_dir(struct ctl_table_header *head)
+{
+	return head->ctl_table[0].child == sysctl_mount_point;
+}
+
+static void set_empty_dir(struct ctl_dir *dir)
+{
+	dir->header.ctl_table[0].child = sysctl_mount_point;
+}
+
+static void clear_empty_dir(struct ctl_dir *dir)
+
+{
+	dir->header.ctl_table[0].child = NULL;
+}
+
 void proc_sys_poll_notify(struct ctl_table_poll *poll)
 {
 	if (!poll)
@@ -187,6 +209,17 @@ static int insert_header(struct ctl_dir *dir, struct ctl_table_header *header)
 	struct ctl_table *entry;
 	int err;
 
+	/* Is this a permanently empty directory? */
+	if (is_empty_dir(&dir->header))
+		return -EROFS;
+
+	/* Am I creating a permanently empty directory? */
+	if (header->ctl_table == sysctl_mount_point) {
+		if (!RB_EMPTY_ROOT(&dir->root))
+			return -EINVAL;
+		set_empty_dir(dir);
+	}
+
 	dir->header.nreg++;
 	header->parent = dir;
 	err = insert_links(header);
@@ -202,6 +235,8 @@ fail:
 	erase_header(header);
 	put_links(header);
 fail_links:
+	if (header->ctl_table == sysctl_mount_point)
+		clear_empty_dir(dir);
 	header->parent = NULL;
 	drop_sysctl_table(&dir->header);
 	return err;
@@ -419,6 +454,8 @@ static struct inode *proc_sys_make_inode(struct super_block *sb,
 		inode->i_mode |= S_IFDIR;
 		inode->i_op = &proc_sys_dir_operations;
 		inode->i_fop = &proc_sys_dir_file_operations;
+		if (is_empty_dir(head))
+			make_empty_dir_inode(inode);
 	}
 out:
 	return inode;
include/linux/sysctl.h +3 -0
index 795d5fea5697..fa7bc29925c9 100644
@@ -188,6 +188,9 @@ struct ctl_table_header *register_sysctl_paths(const struct ctl_path *path,
 void unregister_sysctl_table(struct ctl_table_header * table);
 
 extern int sysctl_init(void);
+
+extern struct ctl_table sysctl_mount_point[];
+
 #else /* CONFIG_SYSCTL */
 static inline struct ctl_table_header *register_sysctl_table(struct ctl_table * table)
 {
kernel/sysctl.c +1 -7
index 2082b1a88fb9..c3eee4c6d6c1 100644
@@ -1531,12 +1531,6 @@ static struct ctl_table vm_table[] = {
 	{ }
 };
 
-#if defined(CONFIG_BINFMT_MISC) || defined(CONFIG_BINFMT_MISC_MODULE)
-static struct ctl_table binfmt_misc_table[] = {
-	{ }
-};
-#endif
-
 static struct ctl_table fs_table[] = {
 	{
 		.procname	= "inode-nr",
@@ -1690,7 +1684,7 @@ static struct ctl_table fs_table[] = {
 	{
 		.procname	= "binfmt_misc",
 		.mode		= 0555,
-		.child		= binfmt_misc_table,
+		.child		= sysctl_mount_point,
 	},
 #endif
 	{
Signature · 1 line
2.2.1
#79 lore raw

PATCH 6/10 proc: Allow creating permanently empty directories that serve as mount points

In reply to a message not in the archive

Add a new function proc_create_mount_point that when used to creates a directory that can not be added to.

Add a new function is_empty_pde to test if a function is a mount point.

Update the code to use make_empty_dir_inode when reporting a permanently empty directory to the vfs.

Update the code to not allow adding to permanently empty directories.

Update /proc/openprom and /proc/fs/nfsd to be permanently empty directories.

---
 fs/proc/generic.c  | 23 +++++++++++++++++++++++
 fs/proc/inode.c    |  4 ++++
 fs/proc/internal.h |  6 ++++++
 fs/proc/root.c     |  4 ++--
 4 files changed, 35 insertions(+), 2 deletions(-)
fs/proc/generic.c +23 -0
index df6327a2b865..e5dee5c3188e 100644
@@ -373,6 +373,10 @@ static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent,
 		WARN(1, "create '/proc/%s' by hand\n", qstr.name);
 		return NULL;
 	}
+	if (is_empty_pde(*parent)) {
+		WARN(1, "attempt to add to permanently empty directory");
+		return NULL;
+	}
 
 	ent = kzalloc(sizeof(struct proc_dir_entry) + qstr.len + 1, GFP_KERNEL);
 	if (!ent)
@@ -455,6 +459,25 @@ struct proc_dir_entry *proc_mkdir(const char *name,
 }
 EXPORT_SYMBOL(proc_mkdir);
 
+struct proc_dir_entry *proc_create_mount_point(const char *name)
+{
+	umode_t mode = S_IFDIR | S_IRUGO | S_IXUGO;
+	struct proc_dir_entry *ent, *parent = NULL;
+
+	ent = __proc_create(&parent, name, mode, 2);
+	if (ent) {
+		ent->data = NULL;
+		ent->proc_fops = NULL;
+		ent->proc_iops = NULL;
+		if (proc_register(parent, ent) < 0) {
+			kfree(ent);
+			parent->nlink--;
+			ent = NULL;
+		}
+	}
+	return ent;
+}
+
 struct proc_dir_entry *proc_create_data(const char *name, umode_t mode,
 					struct proc_dir_entry *parent,
 					const struct file_operations *proc_fops,
fs/proc/inode.c +4 -0
index 8272aaba1bb0..e3eb5524639f 100644
@@ -423,6 +423,10 @@ struct inode *proc_get_inode(struct super_block *sb, struct proc_dir_entry *de)
 		inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
 		PROC_I(inode)->pde = de;
 
+		if (is_empty_pde(de)) {
+			make_empty_dir_inode(inode);
+			return inode;
+		}
 		if (de->mode) {
 			inode->i_mode = de->mode;
 			inode->i_uid = de->uid;
fs/proc/internal.h +6 -0
index c835b94c0cd3..aa2781095bd1 100644
@@ -191,6 +191,12 @@ static inline struct proc_dir_entry *pde_get(struct proc_dir_entry *pde)
 }
 extern void pde_put(struct proc_dir_entry *);
 
+static inline bool is_empty_pde(const struct proc_dir_entry *pde)
+{
+	return S_ISDIR(pde->mode) && !pde->proc_iops;
+}
+struct proc_dir_entry *proc_create_mount_point(const char *name);
+
 /*
  * inode.c
  */
fs/proc/root.c +2 -2
index 64e1ab64bde6..68feb0f70e63 100644
@@ -179,10 +179,10 @@ void __init proc_root_init(void)
 #endif
 	proc_mkdir("fs", NULL);
 	proc_mkdir("driver", NULL);
-	proc_mkdir("fs/nfsd", NULL); /* somewhere for the nfsd filesystem to be mounted */
+	proc_create_mount_point("fs/nfsd"); /* somewhere for the nfsd filesystem to be mounted */
 #if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE)
 	/* just give it a mountpoint */
-	proc_mkdir("openprom", NULL);
+	proc_create_mount_point("openprom");
 #endif
 	proc_tty_init();
 	proc_mkdir("bus", NULL);
Signature · 1 line
2.2.1
#80 lore raw

PATCH 6/10 proc: Allow creating permanently empty directories that serve as mount points

In reply to a message not in the archive

Add a new function proc_create_mount_point that when used to creates a directory that can not be added to.

Add a new function is_empty_pde to test if a function is a mount point.

Update the code to use make_empty_dir_inode when reporting a permanently empty directory to the vfs.

Update the code to not allow adding to permanently empty directories.

Update /proc/openprom and /proc/fs/nfsd to be permanently empty directories.

---
 fs/proc/generic.c  | 23 +++++++++++++++++++++++
 fs/proc/inode.c    |  4 ++++
 fs/proc/internal.h |  6 ++++++
 fs/proc/root.c     |  4 ++--
 4 files changed, 35 insertions(+), 2 deletions(-)
fs/proc/generic.c +23 -0
index df6327a2b865..e5dee5c3188e 100644
@@ -373,6 +373,10 @@ static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent,
 		WARN(1, "create '/proc/%s' by hand\n", qstr.name);
 		return NULL;
 	}
+	if (is_empty_pde(*parent)) {
+		WARN(1, "attempt to add to permanently empty directory");
+		return NULL;
+	}
 
 	ent = kzalloc(sizeof(struct proc_dir_entry) + qstr.len + 1, GFP_KERNEL);
 	if (!ent)
@@ -455,6 +459,25 @@ struct proc_dir_entry *proc_mkdir(const char *name,
 }
 EXPORT_SYMBOL(proc_mkdir);
 
+struct proc_dir_entry *proc_create_mount_point(const char *name)
+{
+	umode_t mode = S_IFDIR | S_IRUGO | S_IXUGO;
+	struct proc_dir_entry *ent, *parent = NULL;
+
+	ent = __proc_create(&parent, name, mode, 2);
+	if (ent) {
+		ent->data = NULL;
+		ent->proc_fops = NULL;
+		ent->proc_iops = NULL;
+		if (proc_register(parent, ent) < 0) {
+			kfree(ent);
+			parent->nlink--;
+			ent = NULL;
+		}
+	}
+	return ent;
+}
+
 struct proc_dir_entry *proc_create_data(const char *name, umode_t mode,
 					struct proc_dir_entry *parent,
 					const struct file_operations *proc_fops,
fs/proc/inode.c +4 -0
index 8272aaba1bb0..e3eb5524639f 100644
@@ -423,6 +423,10 @@ struct inode *proc_get_inode(struct super_block *sb, struct proc_dir_entry *de)
 		inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
 		PROC_I(inode)->pde = de;
 
+		if (is_empty_pde(de)) {
+			make_empty_dir_inode(inode);
+			return inode;
+		}
 		if (de->mode) {
 			inode->i_mode = de->mode;
 			inode->i_uid = de->uid;
fs/proc/internal.h +6 -0
index c835b94c0cd3..aa2781095bd1 100644
@@ -191,6 +191,12 @@ static inline struct proc_dir_entry *pde_get(struct proc_dir_entry *pde)
 }
 extern void pde_put(struct proc_dir_entry *);
 
+static inline bool is_empty_pde(const struct proc_dir_entry *pde)
+{
+	return S_ISDIR(pde->mode) && !pde->proc_iops;
+}
+struct proc_dir_entry *proc_create_mount_point(const char *name);
+
 /*
  * inode.c
  */
fs/proc/root.c +2 -2
index 64e1ab64bde6..68feb0f70e63 100644
@@ -179,10 +179,10 @@ void __init proc_root_init(void)
 #endif
 	proc_mkdir("fs", NULL);
 	proc_mkdir("driver", NULL);
-	proc_mkdir("fs/nfsd", NULL); /* somewhere for the nfsd filesystem to be mounted */
+	proc_create_mount_point("fs/nfsd"); /* somewhere for the nfsd filesystem to be mounted */
 #if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE)
 	/* just give it a mountpoint */
-	proc_mkdir("openprom", NULL);
+	proc_create_mount_point("openprom");
 #endif
 	proc_tty_init();
 	proc_mkdir("bus", NULL);
Signature · 1 line
2.2.1
#81 lore raw

PATCH 7/10 kernfs: Add support for always empty directories.

In reply to a message not in the archive

Add a new function kernfs_create_empty_dir that can be used to create directory that can not be modified.

Update the code to use make_empty_dir_inode when reporting a permanently empty directory to the vfs.

Update the code to not allow adding to permanently empty directories.

---
 fs/kernfs/dir.c        | 38 +++++++++++++++++++++++++++++++++++++-
 fs/kernfs/inode.c      |  2 ++
 include/linux/kernfs.h |  3 +++
 3 files changed, 42 insertions(+), 1 deletion(-)
fs/kernfs/dir.c +37 -1
index f131fc23ffc4..47dc636d80ed 100644
@@ -585,6 +585,9 @@ int kernfs_add_one(struct kernfs_node *kn)
 		goto out_unlock;
 
 	ret = -ENOENT;
+	if (parent->flags & KERNFS_EMPTY_DIR)
+		goto out_unlock;
+
 	if ((parent->flags & KERNFS_ACTIVATED) && !kernfs_active(parent))
 		goto out_unlock;
 
@@ -776,6 +779,38 @@ struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent,
 	return ERR_PTR(rc);
 }
 
+/**
+ * kernfs_create_empty_dir - create an always empty directory
+ * @parent: parent in which to create a new directory
+ * @name: name of the new directory
+ *
+ * Returns the created node on success, ERR_PTR() value on failure.
+ */
+struct kernfs_node *kernfs_create_empty_dir(struct kernfs_node *parent,
+					    const char *name)
+{
+	struct kernfs_node *kn;
+	int rc;
+
+	/* allocate */
+	kn = kernfs_new_node(parent, name, S_IRUGO|S_IXUGO|S_IFDIR, KERNFS_DIR);
+	if (!kn)
+		return ERR_PTR(-ENOMEM);
+
+	kn->flags |= KERNFS_EMPTY_DIR;
+	kn->dir.root = parent->dir.root;
+	kn->ns = NULL;
+	kn->priv = NULL;
+
+	/* link in */
+	rc = kernfs_add_one(kn);
+	if (!rc)
+		return kn;
+
+	kernfs_put(kn);
+	return ERR_PTR(rc);
+}
+
 static struct dentry *kernfs_iop_lookup(struct inode *dir,
 					struct dentry *dentry,
 					unsigned int flags)
@@ -1247,7 +1282,8 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent,
 	mutex_lock(&kernfs_mutex);
 
 	error = -ENOENT;
-	if (!kernfs_active(kn) || !kernfs_active(new_parent))
+	if (!kernfs_active(kn) || !kernfs_active(new_parent) ||
+	    (new_parent->flags & KERNFS_EMPTY_DIR))
 		goto out;
 
 	error = 0;
fs/kernfs/inode.c +2 -0
index 2da8493a380b..756dd56aaf60 100644
@@ -296,6 +296,8 @@ static void kernfs_init_inode(struct kernfs_node *kn, struct inode *inode)
 	case KERNFS_DIR:
 		inode->i_op = &kernfs_dir_iops;
 		inode->i_fop = &kernfs_dir_fops;
+		if (kn->flags & KERNFS_EMPTY_DIR)
+			make_empty_dir_inode(inode);
 		break;
 	case KERNFS_FILE:
 		inode->i_size = kn->attr.size;
include/linux/kernfs.h +3 -0
index 71ecdab1671b..29d1896c3ba5 100644
@@ -45,6 +45,7 @@ enum kernfs_node_flag {
 	KERNFS_LOCKDEP		= 0x0100,
 	KERNFS_SUICIDAL		= 0x0400,
 	KERNFS_SUICIDED		= 0x0800,
+	KERNFS_EMPTY_DIR	= 0x1000,
 };
 
 /* @flags for kernfs_create_root() */
@@ -285,6 +286,8 @@ void kernfs_destroy_root(struct kernfs_root *root);
 struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent,
 					 const char *name, umode_t mode,
 					 void *priv, const void *ns);
+struct kernfs_node *kernfs_create_empty_dir(struct kernfs_node *parent,
+					    const char *name);
 struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent,
 					 const char *name,
 					 umode_t mode, loff_t size,
Signature · 1 line
2.2.1
#82 lore raw

PATCH 8/10 sysfs: Add support for permanently empty directories to serve as mount points.

In reply to a message not in the archive

Add two functions sysfs_create_mount_point and sysfs_remove_mount_point that hang a permanently empty directory off of a kobject or remove a permanently emptpy directory hanging from a kobject. Export these new functions so modular filesystems can use them.

---
 fs/sysfs/dir.c        | 34 ++++++++++++++++++++++++++++++++++
 include/linux/sysfs.h | 16 ++++++++++++++++
 2 files changed, 50 insertions(+)
fs/sysfs/dir.c +34 -0
index 0b45ff42f374..94374e435025 100644
@@ -121,3 +121,37 @@ int sysfs_move_dir_ns(struct kobject *kobj, struct kobject *new_parent_kobj,
 
 	return kernfs_rename_ns(kn, new_parent, kn->name, new_ns);
 }
+
+/**
+ * sysfs_create_mount_point - create an always empty directory
+ * @parent_kobj:  kobject that will contain this always empty directory
+ * @name: The name of the always empty directory to add
+ */
+int sysfs_create_mount_point(struct kobject *parent_kobj, const char *name)
+{
+	struct kernfs_node *kn, *parent = parent_kobj->sd;
+
+	kn = kernfs_create_empty_dir(parent, name);
+	if (IS_ERR(kn)) {
+		if (PTR_ERR(kn) == -EEXIST)
+			sysfs_warn_dup(parent, name);
+		return PTR_ERR(kn);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(sysfs_create_mount_point);
+
+/**
+ *	sysfs_remove_mount_point - remove an always empty directory.
+ *	@parent_kobj: kobject that will contain this always empty directory
+ *	@name: The name of the always empty directory to remove
+ *
+ */
+void sysfs_remove_mount_point(struct kobject *parent_kobj, const char *name)
+{
+	struct kernfs_node *parent = parent_kobj->sd;
+
+	kernfs_remove_by_name_ns(parent, name, NULL);
+}
+EXPORT_SYMBOL_GPL(sysfs_remove_mount_point);
include/linux/sysfs.h +16 -0
index 99382c0df17e..3e7e41acc451 100644
@@ -210,6 +210,10 @@ int __must_check sysfs_rename_dir_ns(struct kobject *kobj, const char *new_name,
 int __must_check sysfs_move_dir_ns(struct kobject *kobj,
 				   struct kobject *new_parent_kobj,
 				   const void *new_ns);
+int __must_check sysfs_create_mount_point(struct kobject *parent_kobj,
+					  const char *name);
+void sysfs_remove_mount_point(struct kobject *parent_kobj,
+			      const char *name);
 
 int __must_check sysfs_create_file_ns(struct kobject *kobj,
 				      const struct attribute *attr,
@@ -298,6 +302,18 @@ static inline int sysfs_move_dir_ns(struct kobject *kobj,
 	return 0;
 }
 
+static inline int sysfs_create_mount_point(struct kobject *parent_kobj,
+					   const char *name)
+{
+	return 0;
+}
+
+static inline void sysfs_remove_mount_point(struct kobject *parent_kobj,
+					    const char *name)
+{
+	return 0;
+}
+
 static inline int sysfs_create_file_ns(struct kobject *kobj,
 				       const struct attribute *attr,
 				       const void *ns)
Signature · 1 line
2.2.1
maintainer Acked-by on v1 8/10
#83 lore raw

Re: [CFT][PATCH 08/10] sysfs: Add support for permanently empty directories to serve as mount points.

Quoted 6 lines · Eric W. Biederman

Add two functions sysfs_create_mount_point and sysfs_remove_mount_point that hang a permanently empty directory off of a kobject or remove a permanently emptpy directory hanging from a kobject. Export these new functions so modular filesystems can use them.

Quoted 6 lines
---
 fs/sysfs/dir.c        | 34 ++++++++++++++++++++++++++++++++++
 include/linux/sysfs.h | 16 ++++++++++++++++
 2 files changed, 50 insertions(+)

A message that is not in the archive (sent off-list or not yet received): 87fv6xtgr2.fsf_-_-JOvCrm2gF+uungPnsOpG7nhyD016LWXt@public.gmane.org

#85 lore raw

Re: [CFT][PATCH 08/10] sysfs: Add support for permanently empty directories to serve as mount points.

Quoted 6 lines · Eric W. Biederman

Add two functions sysfs_create_mount_point and sysfs_remove_mount_point that hang a permanently empty directory off of a kobject or remove a permanently emptpy directory hanging from a kobject. Export these new functions so modular filesystems can use them.

Quoted 6 lines
---
 fs/sysfs/dir.c        | 34 ++++++++++++++++++++++++++++++++++
 include/linux/sysfs.h | 16 ++++++++++++++++
 2 files changed, 50 insertions(+)
#86 lore raw

PATCH 8/10 sysfs: Add support for permanently empty directories to serve as mount points.

In reply to a message not in the archive

Add two functions sysfs_create_mount_point and sysfs_remove_mount_point that hang a permanently empty directory off of a kobject or remove a permanently emptpy directory hanging from a kobject. Export these new functions so modular filesystems can use them.

---
 fs/sysfs/dir.c        | 34 ++++++++++++++++++++++++++++++++++
 include/linux/sysfs.h | 16 ++++++++++++++++
 2 files changed, 50 insertions(+)
fs/sysfs/dir.c +34 -0
index 0b45ff42f374..94374e435025 100644
@@ -121,3 +121,37 @@ int sysfs_move_dir_ns(struct kobject *kobj, struct kobject *new_parent_kobj,
 
 	return kernfs_rename_ns(kn, new_parent, kn->name, new_ns);
 }
+
+/**
+ * sysfs_create_mount_point - create an always empty directory
+ * @parent_kobj:  kobject that will contain this always empty directory
+ * @name: The name of the always empty directory to add
+ */
+int sysfs_create_mount_point(struct kobject *parent_kobj, const char *name)
+{
+	struct kernfs_node *kn, *parent = parent_kobj->sd;
+
+	kn = kernfs_create_empty_dir(parent, name);
+	if (IS_ERR(kn)) {
+		if (PTR_ERR(kn) == -EEXIST)
+			sysfs_warn_dup(parent, name);
+		return PTR_ERR(kn);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(sysfs_create_mount_point);
+
+/**
+ *	sysfs_remove_mount_point - remove an always empty directory.
+ *	@parent_kobj: kobject that will contain this always empty directory
+ *	@name: The name of the always empty directory to remove
+ *
+ */
+void sysfs_remove_mount_point(struct kobject *parent_kobj, const char *name)
+{
+	struct kernfs_node *parent = parent_kobj->sd;
+
+	kernfs_remove_by_name_ns(parent, name, NULL);
+}
+EXPORT_SYMBOL_GPL(sysfs_remove_mount_point);
include/linux/sysfs.h +16 -0
index 99382c0df17e..3e7e41acc451 100644
@@ -210,6 +210,10 @@ int __must_check sysfs_rename_dir_ns(struct kobject *kobj, const char *new_name,
 int __must_check sysfs_move_dir_ns(struct kobject *kobj,
 				   struct kobject *new_parent_kobj,
 				   const void *new_ns);
+int __must_check sysfs_create_mount_point(struct kobject *parent_kobj,
+					  const char *name);
+void sysfs_remove_mount_point(struct kobject *parent_kobj,
+			      const char *name);
 
 int __must_check sysfs_create_file_ns(struct kobject *kobj,
 				      const struct attribute *attr,
@@ -298,6 +302,18 @@ static inline int sysfs_move_dir_ns(struct kobject *kobj,
 	return 0;
 }
 
+static inline int sysfs_create_mount_point(struct kobject *parent_kobj,
+					   const char *name)
+{
+	return 0;
+}
+
+static inline void sysfs_remove_mount_point(struct kobject *parent_kobj,
+					    const char *name)
+{
+	return 0;
+}
+
 static inline int sysfs_create_file_ns(struct kobject *kobj,
 				       const struct attribute *attr,
 				       const void *ns)
Signature · 1 line
2.2.1
#87 lore raw

PATCH 9/10 sysfs: Create mountpoints with sysfs_create_mount_point

In reply to a message not in the archive

This allows for better documentation in the code and it allows for a simpler and fully correct version of fs_fully_visible to be written.

The mount points converted and their filesystems are:

/sys/hypervisor/s390/       s390_hypfs
/sys/kernel/config/         configfs
/sys/kernel/debug/          debugfs
/sys/firmware/efi/efivars/  efivarfs
/sys/fs/fuse/connections/   fusectl
/sys/fs/pstore/             pstore
/sys/kernel/tracing/        tracefs
/sys/fs/cgroup/             cgroup
/sys/kernel/security/       securityfs
/sys/fs/selinux/            selinuxfs
/sys/fs/smackfs/            smackfs
---
 arch/s390/hypfs/inode.c      | 12 ++++--------
 drivers/firmware/efi/efi.c   |  6 ++----
 fs/configfs/mount.c          | 10 ++++------
 fs/debugfs/inode.c           | 11 ++++-------
 fs/fuse/inode.c              |  9 +++------
 fs/pstore/inode.c            | 12 ++++--------
 fs/tracefs/inode.c           |  6 ++----
 kernel/cgroup.c              | 10 ++++------
 security/inode.c             | 10 ++++------
 security/selinux/selinuxfs.c | 11 +++++------
 security/smack/smackfs.c     |  8 ++++----
 11 files changed, 40 insertions(+), 65 deletions(-)
arch/s390/hypfs/inode.c +4 -8
index d3f896a35b98..2eeb0a0f506d 100644
@@ -456,8 +456,6 @@ static const struct super_operations hypfs_s_ops = {
 	.show_options	= hypfs_show_options,
 };
 
-static struct kobject *s390_kobj;
-
 static int __init hypfs_init(void)
 {
 	int rc;
@@ -481,18 +479,16 @@ static int __init hypfs_init(void)
 		rc = -ENODATA;
 		goto fail_hypfs_sprp_exit;
 	}
-	s390_kobj = kobject_create_and_add("s390", hypervisor_kobj);
-	if (!s390_kobj) {
-		rc = -ENOMEM;
+	rc = sysfs_create_mount_point(hypervisor_kobj, "s390");
+	if (rc)
 		goto fail_hypfs_diag0c_exit;
-	}
 	rc = register_filesystem(&hypfs_type);
 	if (rc)
 		goto fail_filesystem;
 	return 0;
 
 fail_filesystem:
-	kobject_put(s390_kobj);
+	sysfs_remove_mount_point(hypervisor_kobj, "s390");
 fail_hypfs_diag0c_exit:
 	hypfs_diag0c_exit();
 fail_hypfs_sprp_exit:
@@ -510,7 +506,7 @@ fail_dbfs_exit:
 static void __exit hypfs_exit(void)
 {
 	unregister_filesystem(&hypfs_type);
-	kobject_put(s390_kobj);
+	sysfs_remove_mount_point(hypervisor_kobj, "s390");
 	hypfs_diag0c_exit();
 	hypfs_sprp_exit();
 	hypfs_vm_exit();
drivers/firmware/efi/efi.c +2 -4
index 3061bb8629dc..e14363d12690 100644
@@ -65,7 +65,6 @@ static int __init parse_efi_cmdline(char *str)
 early_param("efi", parse_efi_cmdline);
 
 static struct kobject *efi_kobj;
-static struct kobject *efivars_kobj;
 
 /*
  * Let's not leave out systab information that snuck into
@@ -212,10 +211,9 @@ static int __init efisubsys_init(void)
 		goto err_remove_group;
 
 	/* and the standard mountpoint for efivarfs */
-	efivars_kobj = kobject_create_and_add("efivars", efi_kobj);
-	if (!efivars_kobj) {
+	error = sysfs_create_mount_point(efi_kobj, "efivars");
+	if (error) {
 		pr_err("efivars: Subsystem registration failed.\n");
-		error = -ENOMEM;
 		goto err_remove_group;
 	}
 
fs/configfs/mount.c +4 -6
index da94e41bdbf6..bca58da65e2b 100644
@@ -129,8 +129,6 @@ void configfs_release_fs(void)
 }
 
 
-static struct kobject *config_kobj;
-
 static int __init configfs_init(void)
 {
 	int err = -ENOMEM;
@@ -141,8 +139,8 @@ static int __init configfs_init(void)
 	if (!configfs_dir_cachep)
 		goto out;
 
-	config_kobj = kobject_create_and_add("config", kernel_kobj);
-	if (!config_kobj)
+	err = sysfs_create_mount_point(kernel_kobj, "config");
+	if (err)
 		goto out2;
 
 	err = register_filesystem(&configfs_fs_type);
@@ -152,7 +150,7 @@ static int __init configfs_init(void)
 	return 0;
 out3:
 	pr_err("Unable to register filesystem!\n");
-	kobject_put(config_kobj);
+	sysfs_remove_mount_point(kernel_kobj, "config");
 out2:
 	kmem_cache_destroy(configfs_dir_cachep);
 	configfs_dir_cachep = NULL;
@@ -163,7 +161,7 @@ out:
 static void __exit configfs_exit(void)
 {
 	unregister_filesystem(&configfs_fs_type);
-	kobject_put(config_kobj);
+	sysfs_remove_mount_point(kernel_kobj, "config");
 	kmem_cache_destroy(configfs_dir_cachep);
 	configfs_dir_cachep = NULL;
 }
fs/debugfs/inode.c +4 -7
index c1e7ffb0dab6..12756040ca20 100644
@@ -716,20 +716,17 @@ bool debugfs_initialized(void)
 }
 EXPORT_SYMBOL_GPL(debugfs_initialized);
 
-
-static struct kobject *debug_kobj;
-
 static int __init debugfs_init(void)
 {
 	int retval;
 
-	debug_kobj = kobject_create_and_add("debug", kernel_kobj);
-	if (!debug_kobj)
-		return -EINVAL;
+	retval = sysfs_create_mount_point(kernel_kobj, "debug");
+	if (retval)
+		return retval;
 
 	retval = register_filesystem(&debug_fs_type);
 	if (retval)
-		kobject_put(debug_kobj);
+		sysfs_remove_mount_point(kernel_kobj, "debug");
 	else
 		debugfs_registered = true;
 
fs/fuse/inode.c +3 -6
index 082ac1c97f39..18dacf9ed8ff 100644
@@ -1238,7 +1238,6 @@ static void fuse_fs_cleanup(void)
 }
 
 static struct kobject *fuse_kobj;
-static struct kobject *connections_kobj;
 
 static int fuse_sysfs_init(void)
 {
@@ -1250,11 +1249,9 @@ static int fuse_sysfs_init(void)
 		goto out_err;
 	}
 
-	connections_kobj = kobject_create_and_add("connections", fuse_kobj);
-	if (!connections_kobj) {
-		err = -ENOMEM;
+	err = sysfs_create_mount_point(fuse_kobj, "connections");
+	if (err)
 		goto out_fuse_unregister;
-	}
 
 	return 0;
 
@@ -1266,7 +1263,7 @@ static int fuse_sysfs_init(void)
 
 static void fuse_sysfs_cleanup(void)
 {
-	kobject_put(connections_kobj);
+	sysfs_remove_mount_point(fuse_kobj, "connections");
 	kobject_put(fuse_kobj);
 }
 
fs/pstore/inode.c +4 -8
index dc43b5f29305..3adcc4669fac 100644
@@ -461,22 +461,18 @@ static struct file_system_type pstore_fs_type = {
 	.kill_sb	= pstore_kill_sb,
 };
 
-static struct kobject *pstore_kobj;
-
 static int __init init_pstore_fs(void)
 {
-	int err = 0;
+	int err;
 
 	/* Create a convenient mount point for people to access pstore */
-	pstore_kobj = kobject_create_and_add("pstore", fs_kobj);
-	if (!pstore_kobj) {
-		err = -ENOMEM;
+	err = sysfs_create_mount_point(fs_kobj, "pstore");
+	if (err)
 		goto out;
-	}
 
 	err = register_filesystem(&pstore_fs_type);
 	if (err < 0)
-		kobject_put(pstore_kobj);
+		sysfs_remove_mount_point(fs_kobj, "pstore");
 
 out:
 	return err;
fs/tracefs/inode.c +2 -4
index d92bdf3b079a..a43df11a163f 100644
@@ -631,14 +631,12 @@ bool tracefs_initialized(void)
 	return tracefs_registered;
 }
 
-static struct kobject *trace_kobj;
-
 static int __init tracefs_init(void)
 {
 	int retval;
 
-	trace_kobj = kobject_create_and_add("tracing", kernel_kobj);
-	if (!trace_kobj)
+	retval = sysfs_create_mount_point(kernel_kobj, "tracing");
+	if (retval)
 		return -EINVAL;
 
 	retval = register_filesystem(&trace_fs_type);
kernel/cgroup.c +4 -6
index 469dd547770c..e8a5491be756 100644
@@ -1924,8 +1924,6 @@ static struct file_system_type cgroup_fs_type = {
 	.kill_sb = cgroup_kill_sb,
 };
 
-static struct kobject *cgroup_kobj;
-
 /**
  * task_cgroup_path - cgroup path of a task in the first cgroup hierarchy
  * @task: target task
@@ -5044,13 +5042,13 @@ int __init cgroup_init(void)
 			ss->bind(init_css_set.subsys[ssid]);
 	}
 
-	cgroup_kobj = kobject_create_and_add("cgroup", fs_kobj);
-	if (!cgroup_kobj)
-		return -ENOMEM;
+	err = sysfs_create_mount_point(fs_kobj, "cgroup");
+	if (err)
+		return err;
 
 	err = register_filesystem(&cgroup_fs_type);
 	if (err < 0) {
-		kobject_put(cgroup_kobj);
+		sysfs_remove_mount_point(fs_kobj, "cgroup");
 		return err;
 	}
 
security/inode.c +4 -6
index 91503b79c5f8..0e37e4fba8fa 100644
@@ -215,19 +215,17 @@ void securityfs_remove(struct dentry *dentry)
 }
 EXPORT_SYMBOL_GPL(securityfs_remove);
 
-static struct kobject *security_kobj;
-
 static int __init securityfs_init(void)
 {
 	int retval;
 
-	security_kobj = kobject_create_and_add("security", kernel_kobj);
-	if (!security_kobj)
-		return -EINVAL;
+	retval = sysfs_create_mount_point(kernel_kobj, "security");
+	if (retval)
+		return retval;
 
 	retval = register_filesystem(&fs_type);
 	if (retval)
-		kobject_put(security_kobj);
+		sysfs_remove_mount_point(kernel_kobj, "security");
 	return retval;
 }
 
security/selinux/selinuxfs.c +5 -6
index d2787cca1fcb..3d2201413028 100644
@@ -1853,7 +1853,6 @@ static struct file_system_type sel_fs_type = {
 };
 
 struct vfsmount *selinuxfs_mount;
-static struct kobject *selinuxfs_kobj;
 
 static int __init init_sel_fs(void)
 {
@@ -1862,13 +1861,13 @@ static int __init init_sel_fs(void)
 	if (!selinux_enabled)
 		return 0;
 
-	selinuxfs_kobj = kobject_create_and_add("selinux", fs_kobj);
-	if (!selinuxfs_kobj)
-		return -ENOMEM;
+	err = sysfs_create_mount_point(fs_kobj, "selinux");
+	if (err)
+		return err;
 
 	err = register_filesystem(&sel_fs_type);
 	if (err) {
-		kobject_put(selinuxfs_kobj);
+		sysfs_remove_mount_point(fs_kobj, "selinux");
 		return err;
 	}
 
@@ -1887,7 +1886,7 @@ __initcall(init_sel_fs);
 #ifdef CONFIG_SECURITY_SELINUX_DISABLE
 void exit_sel_fs(void)
 {
-	kobject_put(selinuxfs_kobj);
+	sysfs_remove_mount_point(fs_kobj, "selinux");
 	kern_unmount(selinuxfs_mount);
 	unregister_filesystem(&sel_fs_type);
 }
security/smack/smackfs.c +4 -4
index d9682985349e..ac4cac7c661a 100644
@@ -2241,16 +2241,16 @@ static const struct file_operations smk_revoke_subj_ops = {
 	.llseek		= generic_file_llseek,
 };
 
-static struct kset *smackfs_kset;
 /**
  * smk_init_sysfs - initialize /sys/fs/smackfs
  *
  */
 static int smk_init_sysfs(void)
 {
-	smackfs_kset = kset_create_and_add("smackfs", NULL, fs_kobj);
-	if (!smackfs_kset)
-		return -ENOMEM;
+	int err;
+	err = sysfs_create_mount_point(fs_kobj, "smackfs");
+	if (err)
+		return err;
 	return 0;
 }
 
Signature · 1 line
2.2.1
maintainer Acked-by on v1 9/10
#88 lore raw

Re: [CFT][PATCH 09/10] sysfs: Create mountpoints with sysfs_create_mount_point

Quoted 18 lines · Eric W. Biederman

This allows for better documentation in the code and it allows for a simpler and fully correct version of fs_fully_visible to be written.

The mount points converted and their filesystems are:

/sys/hypervisor/s390/       s390_hypfs
/sys/kernel/config/         configfs
/sys/kernel/debug/          debugfs
/sys/firmware/efi/efivars/  efivarfs
/sys/fs/fuse/connections/   fusectl
/sys/fs/pstore/             pstore
/sys/kernel/tracing/        tracefs
/sys/fs/cgroup/             cgroup
/sys/kernel/security/       securityfs
/sys/fs/selinux/            selinuxfs
/sys/fs/smackfs/            smackfs
Quoted 2 lines

A message that is not in the archive (sent off-list or not yet received): 87a8x5tgpp.fsf_-_-JOvCrm2gF+uungPnsOpG7nhyD016LWXt@public.gmane.org

#90 lore raw

Re: [CFT][PATCH 09/10] sysfs: Create mountpoints with sysfs_create_mount_point

Quoted 18 lines · Eric W. Biederman

This allows for better documentation in the code and it allows for a simpler and fully correct version of fs_fully_visible to be written.

The mount points converted and their filesystems are:

/sys/hypervisor/s390/       s390_hypfs
/sys/kernel/config/         configfs
/sys/kernel/debug/          debugfs
/sys/firmware/efi/efivars/  efivarfs
/sys/fs/fuse/connections/   fusectl
/sys/fs/pstore/             pstore
/sys/kernel/tracing/        tracefs
/sys/fs/cgroup/             cgroup
/sys/kernel/security/       securityfs
/sys/fs/selinux/            selinuxfs
/sys/fs/smackfs/            smackfs
Quoted 2 lines
#91 lore raw

PATCH 9/10 sysfs: Create mountpoints with sysfs_create_mount_point

In reply to a message not in the archive

This allows for better documentation in the code and it allows for a simpler and fully correct version of fs_fully_visible to be written.

The mount points converted and their filesystems are:

/sys/hypervisor/s390/       s390_hypfs
/sys/kernel/config/         configfs
/sys/kernel/debug/          debugfs
/sys/firmware/efi/efivars/  efivarfs
/sys/fs/fuse/connections/   fusectl
/sys/fs/pstore/             pstore
/sys/kernel/tracing/        tracefs
/sys/fs/cgroup/             cgroup
/sys/kernel/security/       securityfs
/sys/fs/selinux/            selinuxfs
/sys/fs/smackfs/            smackfs
---
 arch/s390/hypfs/inode.c      | 12 ++++--------
 drivers/firmware/efi/efi.c   |  6 ++----
 fs/configfs/mount.c          | 10 ++++------
 fs/debugfs/inode.c           | 11 ++++-------
 fs/fuse/inode.c              |  9 +++------
 fs/pstore/inode.c            | 12 ++++--------
 fs/tracefs/inode.c           |  6 ++----
 kernel/cgroup.c              | 10 ++++------
 security/inode.c             | 10 ++++------
 security/selinux/selinuxfs.c | 11 +++++------
 security/smack/smackfs.c     |  8 ++++----
 11 files changed, 40 insertions(+), 65 deletions(-)
arch/s390/hypfs/inode.c +4 -8
index d3f896a35b98..2eeb0a0f506d 100644
@@ -456,8 +456,6 @@ static const struct super_operations hypfs_s_ops = {
 	.show_options	= hypfs_show_options,
 };
 
-static struct kobject *s390_kobj;
-
 static int __init hypfs_init(void)
 {
 	int rc;
@@ -481,18 +479,16 @@ static int __init hypfs_init(void)
 		rc = -ENODATA;
 		goto fail_hypfs_sprp_exit;
 	}
-	s390_kobj = kobject_create_and_add("s390", hypervisor_kobj);
-	if (!s390_kobj) {
-		rc = -ENOMEM;
+	rc = sysfs_create_mount_point(hypervisor_kobj, "s390");
+	if (rc)
 		goto fail_hypfs_diag0c_exit;
-	}
 	rc = register_filesystem(&hypfs_type);
 	if (rc)
 		goto fail_filesystem;
 	return 0;
 
 fail_filesystem:
-	kobject_put(s390_kobj);
+	sysfs_remove_mount_point(hypervisor_kobj, "s390");
 fail_hypfs_diag0c_exit:
 	hypfs_diag0c_exit();
 fail_hypfs_sprp_exit:
@@ -510,7 +506,7 @@ fail_dbfs_exit:
 static void __exit hypfs_exit(void)
 {
 	unregister_filesystem(&hypfs_type);
-	kobject_put(s390_kobj);
+	sysfs_remove_mount_point(hypervisor_kobj, "s390");
 	hypfs_diag0c_exit();
 	hypfs_sprp_exit();
 	hypfs_vm_exit();
drivers/firmware/efi/efi.c +2 -4
index 3061bb8629dc..e14363d12690 100644
@@ -65,7 +65,6 @@ static int __init parse_efi_cmdline(char *str)
 early_param("efi", parse_efi_cmdline);
 
 static struct kobject *efi_kobj;
-static struct kobject *efivars_kobj;
 
 /*
  * Let's not leave out systab information that snuck into
@@ -212,10 +211,9 @@ static int __init efisubsys_init(void)
 		goto err_remove_group;
 
 	/* and the standard mountpoint for efivarfs */
-	efivars_kobj = kobject_create_and_add("efivars", efi_kobj);
-	if (!efivars_kobj) {
+	error = sysfs_create_mount_point(efi_kobj, "efivars");
+	if (error) {
 		pr_err("efivars: Subsystem registration failed.\n");
-		error = -ENOMEM;
 		goto err_remove_group;
 	}
 
fs/configfs/mount.c +4 -6
index da94e41bdbf6..bca58da65e2b 100644
@@ -129,8 +129,6 @@ void configfs_release_fs(void)
 }
 
 
-static struct kobject *config_kobj;
-
 static int __init configfs_init(void)
 {
 	int err = -ENOMEM;
@@ -141,8 +139,8 @@ static int __init configfs_init(void)
 	if (!configfs_dir_cachep)
 		goto out;
 
-	config_kobj = kobject_create_and_add("config", kernel_kobj);
-	if (!config_kobj)
+	err = sysfs_create_mount_point(kernel_kobj, "config");
+	if (err)
 		goto out2;
 
 	err = register_filesystem(&configfs_fs_type);
@@ -152,7 +150,7 @@ static int __init configfs_init(void)
 	return 0;
 out3:
 	pr_err("Unable to register filesystem!\n");
-	kobject_put(config_kobj);
+	sysfs_remove_mount_point(kernel_kobj, "config");
 out2:
 	kmem_cache_destroy(configfs_dir_cachep);
 	configfs_dir_cachep = NULL;
@@ -163,7 +161,7 @@ out:
 static void __exit configfs_exit(void)
 {
 	unregister_filesystem(&configfs_fs_type);
-	kobject_put(config_kobj);
+	sysfs_remove_mount_point(kernel_kobj, "config");
 	kmem_cache_destroy(configfs_dir_cachep);
 	configfs_dir_cachep = NULL;
 }
fs/debugfs/inode.c +4 -7
index c1e7ffb0dab6..12756040ca20 100644
@@ -716,20 +716,17 @@ bool debugfs_initialized(void)
 }
 EXPORT_SYMBOL_GPL(debugfs_initialized);
 
-
-static struct kobject *debug_kobj;
-
 static int __init debugfs_init(void)
 {
 	int retval;
 
-	debug_kobj = kobject_create_and_add("debug", kernel_kobj);
-	if (!debug_kobj)
-		return -EINVAL;
+	retval = sysfs_create_mount_point(kernel_kobj, "debug");
+	if (retval)
+		return retval;
 
 	retval = register_filesystem(&debug_fs_type);
 	if (retval)
-		kobject_put(debug_kobj);
+		sysfs_remove_mount_point(kernel_kobj, "debug");
 	else
 		debugfs_registered = true;
 
fs/fuse/inode.c +3 -6
index 082ac1c97f39..18dacf9ed8ff 100644
@@ -1238,7 +1238,6 @@ static void fuse_fs_cleanup(void)
 }
 
 static struct kobject *fuse_kobj;
-static struct kobject *connections_kobj;
 
 static int fuse_sysfs_init(void)
 {
@@ -1250,11 +1249,9 @@ static int fuse_sysfs_init(void)
 		goto out_err;
 	}
 
-	connections_kobj = kobject_create_and_add("connections", fuse_kobj);
-	if (!connections_kobj) {
-		err = -ENOMEM;
+	err = sysfs_create_mount_point(fuse_kobj, "connections");
+	if (err)
 		goto out_fuse_unregister;
-	}
 
 	return 0;
 
@@ -1266,7 +1263,7 @@ static int fuse_sysfs_init(void)
 
 static void fuse_sysfs_cleanup(void)
 {
-	kobject_put(connections_kobj);
+	sysfs_remove_mount_point(fuse_kobj, "connections");
 	kobject_put(fuse_kobj);
 }
 
fs/pstore/inode.c +4 -8
index dc43b5f29305..3adcc4669fac 100644
@@ -461,22 +461,18 @@ static struct file_system_type pstore_fs_type = {
 	.kill_sb	= pstore_kill_sb,
 };
 
-static struct kobject *pstore_kobj;
-
 static int __init init_pstore_fs(void)
 {
-	int err = 0;
+	int err;
 
 	/* Create a convenient mount point for people to access pstore */
-	pstore_kobj = kobject_create_and_add("pstore", fs_kobj);
-	if (!pstore_kobj) {
-		err = -ENOMEM;
+	err = sysfs_create_mount_point(fs_kobj, "pstore");
+	if (err)
 		goto out;
-	}
 
 	err = register_filesystem(&pstore_fs_type);
 	if (err < 0)
-		kobject_put(pstore_kobj);
+		sysfs_remove_mount_point(fs_kobj, "pstore");
 
 out:
 	return err;
fs/tracefs/inode.c +2 -4
index d92bdf3b079a..a43df11a163f 100644
@@ -631,14 +631,12 @@ bool tracefs_initialized(void)
 	return tracefs_registered;
 }
 
-static struct kobject *trace_kobj;
-
 static int __init tracefs_init(void)
 {
 	int retval;
 
-	trace_kobj = kobject_create_and_add("tracing", kernel_kobj);
-	if (!trace_kobj)
+	retval = sysfs_create_mount_point(kernel_kobj, "tracing");
+	if (retval)
 		return -EINVAL;
 
 	retval = register_filesystem(&trace_fs_type);
kernel/cgroup.c +4 -6
index 469dd547770c..e8a5491be756 100644
@@ -1924,8 +1924,6 @@ static struct file_system_type cgroup_fs_type = {
 	.kill_sb = cgroup_kill_sb,
 };
 
-static struct kobject *cgroup_kobj;
-
 /**
  * task_cgroup_path - cgroup path of a task in the first cgroup hierarchy
  * @task: target task
@@ -5044,13 +5042,13 @@ int __init cgroup_init(void)
 			ss->bind(init_css_set.subsys[ssid]);
 	}
 
-	cgroup_kobj = kobject_create_and_add("cgroup", fs_kobj);
-	if (!cgroup_kobj)
-		return -ENOMEM;
+	err = sysfs_create_mount_point(fs_kobj, "cgroup");
+	if (err)
+		return err;
 
 	err = register_filesystem(&cgroup_fs_type);
 	if (err < 0) {
-		kobject_put(cgroup_kobj);
+		sysfs_remove_mount_point(fs_kobj, "cgroup");
 		return err;
 	}
 
security/inode.c +4 -6
index 91503b79c5f8..0e37e4fba8fa 100644
@@ -215,19 +215,17 @@ void securityfs_remove(struct dentry *dentry)
 }
 EXPORT_SYMBOL_GPL(securityfs_remove);
 
-static struct kobject *security_kobj;
-
 static int __init securityfs_init(void)
 {
 	int retval;
 
-	security_kobj = kobject_create_and_add("security", kernel_kobj);
-	if (!security_kobj)
-		return -EINVAL;
+	retval = sysfs_create_mount_point(kernel_kobj, "security");
+	if (retval)
+		return retval;
 
 	retval = register_filesystem(&fs_type);
 	if (retval)
-		kobject_put(security_kobj);
+		sysfs_remove_mount_point(kernel_kobj, "security");
 	return retval;
 }
 
security/selinux/selinuxfs.c +5 -6
index d2787cca1fcb..3d2201413028 100644
@@ -1853,7 +1853,6 @@ static struct file_system_type sel_fs_type = {
 };
 
 struct vfsmount *selinuxfs_mount;
-static struct kobject *selinuxfs_kobj;
 
 static int __init init_sel_fs(void)
 {
@@ -1862,13 +1861,13 @@ static int __init init_sel_fs(void)
 	if (!selinux_enabled)
 		return 0;
 
-	selinuxfs_kobj = kobject_create_and_add("selinux", fs_kobj);
-	if (!selinuxfs_kobj)
-		return -ENOMEM;
+	err = sysfs_create_mount_point(fs_kobj, "selinux");
+	if (err)
+		return err;
 
 	err = register_filesystem(&sel_fs_type);
 	if (err) {
-		kobject_put(selinuxfs_kobj);
+		sysfs_remove_mount_point(fs_kobj, "selinux");
 		return err;
 	}
 
@@ -1887,7 +1886,7 @@ __initcall(init_sel_fs);
 #ifdef CONFIG_SECURITY_SELINUX_DISABLE
 void exit_sel_fs(void)
 {
-	kobject_put(selinuxfs_kobj);
+	sysfs_remove_mount_point(fs_kobj, "selinux");
 	kern_unmount(selinuxfs_mount);
 	unregister_filesystem(&sel_fs_type);
 }
security/smack/smackfs.c +4 -4
index d9682985349e..ac4cac7c661a 100644
@@ -2241,16 +2241,16 @@ static const struct file_operations smk_revoke_subj_ops = {
 	.llseek		= generic_file_llseek,
 };
 
-static struct kset *smackfs_kset;
 /**
  * smk_init_sysfs - initialize /sys/fs/smackfs
  *
  */
 static int smk_init_sysfs(void)
 {
-	smackfs_kset = kset_create_and_add("smackfs", NULL, fs_kobj);
-	if (!smackfs_kset)
-		return -ENOMEM;
+	int err;
+	err = sysfs_create_mount_point(fs_kobj, "smackfs");
+	if (err)
+		return err;
 	return 0;
 }
 
Signature · 1 line
2.2.1
#92 lore raw

PATCH 10/10 mnt: Update fs_fully_visible to test for permanently empty directories

In reply to a message not in the archive

fs_fully_visible attempts to make fresh mounts of proc and sysfs give the mounter no more access to proc and sysfs than if they could have by creating a bind mount. One aspect of proc and sysfs that makes this particularly tricky is that there are other filesystems that typically mount on top of proc and sysfs. As those filesystems are mounted on empty directories in practice it is safe to ignore them. However testing to ensure filesystems are mounted on empty directories has not been something the in kernel data structures have supported so the current test for an empty directory which checks to see if nlink <= 2 is a bit lacking.

proc and sysfs have recently been modified to use the new empty_dir infrastructure to create all of their dedicated mount points. Instead of testing for S_ISDIR(inode->i_mode) && i_nlink <= 2 to see if a directory is empty, test for is_empty_dir_inode(inode). That small change guaranteess mounts found on proc and sysfs really are safe to ignore, because the directories are not only empty but nothing can ever be added to them. This guarantees there is nothing to worry about when mounting proc and sysfs.

---
 fs/namespace.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)
fs/namespace.c +2 -3
index 3ede0669b8d2..eccd925c6e82 100644
@@ -3220,9 +3220,8 @@ static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags)
 			/* Only worry about locked mounts */
 			if (!(mnt->mnt.mnt_flags & MNT_LOCKED))
 				continue;
-			if (!S_ISDIR(inode->i_mode))
-				goto next;
-			if (inode->i_nlink > 2)
+			/* Is the directory permanetly empty? */
+			if (!is_empty_dir_inode(inode))
 				goto next;
 		}
 		/* Preserve the locked attributes */
Signature · 1 line
2.2.1
#93 lore raw

PATCH 10/10 mnt: Update fs_fully_visible to test for permanently empty directories

In reply to a message not in the archive

fs_fully_visible attempts to make fresh mounts of proc and sysfs give the mounter no more access to proc and sysfs than if they could have by creating a bind mount. One aspect of proc and sysfs that makes this particularly tricky is that there are other filesystems that typically mount on top of proc and sysfs. As those filesystems are mounted on empty directories in practice it is safe to ignore them. However testing to ensure filesystems are mounted on empty directories has not been something the in kernel data structures have supported so the current test for an empty directory which checks to see if nlink <= 2 is a bit lacking.

proc and sysfs have recently been modified to use the new empty_dir infrastructure to create all of their dedicated mount points. Instead of testing for S_ISDIR(inode->i_mode) && i_nlink <= 2 to see if a directory is empty, test for is_empty_dir_inode(inode). That small change guaranteess mounts found on proc and sysfs really are safe to ignore, because the directories are not only empty but nothing can ever be added to them. This guarantees there is nothing to worry about when mounting proc and sysfs.

---
 fs/namespace.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)
fs/namespace.c +2 -3
index 3ede0669b8d2..eccd925c6e82 100644
@@ -3220,9 +3220,8 @@ static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags)
 			/* Only worry about locked mounts */
 			if (!(mnt->mnt.mnt_flags & MNT_LOCKED))
 				continue;
-			if (!S_ISDIR(inode->i_mode))
-				goto next;
-			if (inode->i_nlink > 2)
+			/* Is the directory permanetly empty? */
+			if (!is_empty_dir_inode(inode))
 				goto next;
 		}
 		/* Preserve the locked attributes */
Signature · 1 line
2.2.1
#94 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

In reply to a message not in the archive

I had hoped to get some Tested-By's on that patch series.

Oh well. The fundamentals seem sound, and my biggest concern the implicit nodev does not apply so I will put this patchset in linux-next and aim at merging it in the next merge window. Hopefully that will leave enough time catch problems.

Eric

A message that is not in the archive (sent off-list or not yet received): [email protected]

#96 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

Quoted 1 line · Eric W. Biederman

I had hoped to get some Tested-By's on that patch series.

Sorry, I've been totally swamped.

I suspect that Sandstorm is okay, but I haven't had a chance to test it for real. Sandstorm makes only limited use of proc and sysfs in containers, but I'll see if I can test it for real this weekend.

Quoted 8 lines

Oh well. The fundamentals seem sound, and my biggest concern the implicit nodev does not apply so I will put this patchset in linux-next and aim at merging it in the next merge window. Hopefully that will leave enough time catch problems.

Eric

Signature · 2 lines
Andy Lutomirski
AMA Capital Management, LLC

A message that is not in the archive (sent off-list or not yet received): CALCETrUhXBR5WQ6gXr9KzGc4=7tph7kzopY29Hug4g+FhOzEKg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org

#98 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

Quoted 9 lines · Andy Lutomirski
Quoted 1 line · Eric W. Biederman

I had hoped to get some Tested-By's on that patch series.

Sorry, I've been totally swamped.

I suspect that Sandstorm is okay, but I haven't had a chance to test it for real. Sandstorm makes only limited use of proc and sysfs in containers, but I'll see if I can test it for real this weekend.

Thanks.

Eric

#99 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

In reply to a message not in the archive
Quoted 9 lines · Andy Lutomirski
Quoted 1 line · Eric W. Biederman

I had hoped to get some Tested-By's on that patch series.

Sorry, I've been totally swamped.

I suspect that Sandstorm is okay, but I haven't had a chance to test it for real. Sandstorm makes only limited use of proc and sysfs in containers, but I'll see if I can test it for real this weekend.

Testing this with unprivileged containers, I get

lxc-start: conf.c: lxc_mount_auto_mounts: 808 Operation not permitted - error mounting sysfs on /usr/lib/x86_64-linux-gnu/lxc/sys/devices/virtual/net flags 0

Quoted 17 lines
Quoted 7 lines

Oh well. The fundamentals seem sound, and my biggest concern the implicit nodev does not apply so I will put this patchset in linux-next and aim at merging it in the next merge window. Hopefully that will leave enough time catch problems.

Eric

Signature · 6 lines
Andy Lutomirski
AMA Capital Management, LLC
_______________________________________________
Containers mailing list
Containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org
https://lists.linuxfoundation.org/mailman/listinfo/containers
#100 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

In reply to Andy Lutomirski
Quoted 9 lines · Andy Lutomirski
Quoted 1 line · Eric W. Biederman

I had hoped to get some Tested-By's on that patch series.

Sorry, I've been totally swamped.

I suspect that Sandstorm is okay, but I haven't had a chance to test it for real. Sandstorm makes only limited use of proc and sysfs in containers, but I'll see if I can test it for real this weekend.

Testing this with unprivileged containers, I get

lxc-start: conf.c: lxc_mount_auto_mounts: 808 Operation not permitted - error mounting sysfs on /usr/lib/x86_64-linux-gnu/lxc/sys/devices/virtual/net flags 0

Quoted 17 lines
Quoted 7 lines

Oh well. The fundamentals seem sound, and my biggest concern the implicit nodev does not apply so I will put this patchset in linux-next and aim at merging it in the next merge window. Hopefully that will leave enough time catch problems.

Eric

Signature · 6 lines
Andy Lutomirski
AMA Capital Management, LLC
_______________________________________________
Containers mailing list
[email protected]
https://lists.linuxfoundation.org/mailman/listinfo/containers
#101 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

Quoted 11 lines · Serge Hallyn
Quoted 9 lines · Andy Lutomirski
Quoted 1 line · Eric W. Biederman

I had hoped to get some Tested-By's on that patch series.

Sorry, I've been totally swamped.

I suspect that Sandstorm is okay, but I haven't had a chance to test it for real. Sandstorm makes only limited use of proc and sysfs in containers, but I'll see if I can test it for real this weekend.

Quoted 5 lines

Testing this with unprivileged containers, I get

lxc-start: conf.c: lxc_mount_auto_mounts: 808 Operation not permitted
- error mounting sysfs on /usr/lib/x86_64-linux-gnu/lxc/sys/devices/virtual/net flags 0

Grr.. I was afraid this would break something. :(

Looking at my system I see that sysfs is currently mounted "nosuid,nodev,noexec"

Looking at the lxc-start code I don't see it as including any of those mount options. In practice for sysfs I think those options are meaningless (as there should be no devices and nothing executable in sysfs) but I can understand the past concerns with chmod on virtual filesystems that would incline people to use them, so I think the failure is reporting a legitimate security issue in the lxc userspace code where the the unprivileged code is currently attempting to give greater access to sysfs than was given by the original mount of sysfs.

As nosuid,nodev,noexec should not impair the operation of sysfs operation it looks like you can always specify those options and just make this concern go away.

Something like the untested patch below I expect.

src/lxc/conf.c +2 -2
index 9870455b3cae..d9ccd03afe68 100644
@@ -770,8 +770,8 @@ static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_ha
 		{ LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED, "%r/proc/sysrq-trigger",                             "%r/proc/sysrq-trigger",        NULL,       MS_BIND,                        NULL },
 		{ LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED, NULL,                                                "%r/proc/sysrq-trigger",        NULL,       MS_REMOUNT|MS_BIND|MS_RDONLY,   NULL },
 		{ LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_RW,    "proc",                                              "%r/proc",                      "proc",     MS_NODEV|MS_NOEXEC|MS_NOSUID,   NULL },
-		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_RW,     "sysfs",                                             "%r/sys",                       "sysfs",    0,                              NULL },
-		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_RO,     "sysfs",                                             "%r/sys",                       "sysfs",    MS_RDONLY,                      NULL },
+		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_RW,     "sysfs",                                             "%r/sys",                       "sysfs",    MS_NODEV|MS_NOEXEC|MS_NOSUID,   NULL },
+		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_RO,     "sysfs",                                             "%r/sys",                       "sysfs",    MS_NODEV|MS_NOEXEC|MS_NOSUID|MS_RDONLY, NULL },
 		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_MIXED,  "sysfs",                                             "%r/sys",                       "sysfs",    MS_NODEV|MS_NOEXEC|MS_NOSUID,   NULL },
 		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_MIXED,  "%r/sys",                                            "%r/sys",                       NULL,       MS_BIND,                        NULL },
 		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_MIXED,  NULL,                                                "%r/sys",                       NULL,       MS_REMOUNT|MS_BIND|MS_RDONLY,   NULL },

Alternately you can read the flags off of the original mount of proc or sysfs.

src/lxc/conf.c +3 -1
index 9870455b3cae..50ea49973e80 100644
@@ -712,7 +712,9 @@ static unsigned long add_required_remount_flags(const char *s, const char *d,
        struct statvfs sb;
        unsigned long required_flags = 0;
 
-       if (!(flags & MS_REMOUNT))
+       if (!(flags & MS_REMOUNT) &&
+           (strcmp(s, "proc") != 0) &&
+           (strcmp(s, "sysfs") != 0))
                return flags;
 
        if (!s)

Eric

#102 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

Quoted 33 lines · Eric W. Biederman
Quoted 11 lines · Serge Hallyn
Quoted 9 lines · Andy Lutomirski
Quoted 1 line · Eric W. Biederman

I had hoped to get some Tested-By's on that patch series.

Sorry, I've been totally swamped.

I suspect that Sandstorm is okay, but I haven't had a chance to test it for real. Sandstorm makes only limited use of proc and sysfs in containers, but I'll see if I can test it for real this weekend.

Quoted 5 lines

Testing this with unprivileged containers, I get

lxc-start: conf.c: lxc_mount_auto_mounts: 808 Operation not permitted
- error mounting sysfs on /usr/lib/x86_64-linux-gnu/lxc/sys/devices/virtual/net flags 0

Grr.. I was afraid this would break something. :(

Looking at my system I see that sysfs is currently mounted "nosuid,nodev,noexec"

Looking at the lxc-start code I don't see it as including any of those mount options. In practice for sysfs I think those options are meaningless (as there should be no devices and nothing executable in sysfs) but I can understand the past concerns with chmod on virtual filesystems that would incline people to use them, so I think the failure is reporting a legitimate security issue in the lxc userspace code where the the unprivileged code is currently attempting to give greater access to sysfs than was given by the original mount of sysfs.

Quoted 3 lines

As nosuid,nodev,noexec should not impair the operation of sysfs operation it looks like you can always specify those options and just make this concern go away.

Linus is pretty strict about not breaking the ABI, and this definitely counts as breaking the ABI. There's an exception for security issues, but is there really a security issue here? That is, do we lose anything important if we just drop the offending part of the patch set? As you've said, there shouldn't be sensitive device nodes, executables, or setuid files in proc or sysfs in the first place.

--Andy

A message that is not in the archive (sent off-list or not yet received): CALCETrXXax28s9kMTQ-zDx0MttQWG4rg2y-oz3bSGiumSL=3sg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org

#104 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

Quoted 39 lines · Andy Lutomirski
Quoted 33 lines · Eric W. Biederman
Quoted 11 lines · Serge Hallyn
Quoted 9 lines · Andy Lutomirski
Quoted 1 line · Eric W. Biederman

I had hoped to get some Tested-By's on that patch series.

Sorry, I've been totally swamped.

I suspect that Sandstorm is okay, but I haven't had a chance to test it for real. Sandstorm makes only limited use of proc and sysfs in containers, but I'll see if I can test it for real this weekend.

Quoted 5 lines

Testing this with unprivileged containers, I get

lxc-start: conf.c: lxc_mount_auto_mounts: 808 Operation not permitted
- error mounting sysfs on /usr/lib/x86_64-linux-gnu/lxc/sys/devices/virtual/net flags 0

Grr.. I was afraid this would break something. :(

Looking at my system I see that sysfs is currently mounted "nosuid,nodev,noexec"

Looking at the lxc-start code I don't see it as including any of those mount options. In practice for sysfs I think those options are meaningless (as there should be no devices and nothing executable in sysfs) but I can understand the past concerns with chmod on virtual filesystems that would incline people to use them, so I think the failure is reporting a legitimate security issue in the lxc userspace code where the the unprivileged code is currently attempting to give greater access to sysfs than was given by the original mount of sysfs.

Quoted 3 lines

As nosuid,nodev,noexec should not impair the operation of sysfs operation it looks like you can always specify those options and just make this concern go away.

Quoted 6 lines

Linus is pretty strict about not breaking the ABI, and this definitely counts as breaking the ABI. There's an exception for security issues, but is there really a security issue here? That is, do we lose anything important if we just drop the offending part of the patch set? As you've said, there shouldn't be sensitive device nodes, executables, or setuid files in proc or sysfs in the first place.

Speaking as a user of the mount() interfaces, I really think it would be less confusing overall if mount() simply ignored the requested flags when the caller doesn't have a choice. That is, in cases where mount() currently fails with EPERM when not given, say, MS_NOSUID, it should instead just pretend the caller actually set MS_NOSUID and go ahead with a nosuid mount. Or put another way, the absence of MS_NOSUID should not be interpreted as "remove the nosuid bit" but rather "don't set the nosuid bit if not required".

Consider:

- This approach will actually cause lxc to have the correct behavior, without any changes to lxc. I suspect that this generalizes: In the vast majority of cases, when users have failed to set MS_NOSUID, it's not because they are explicitly requesting that the flag be turned off, but rather that they didn't know it mattered.

- If a user actually *does* expect not passing MS_NOSUID to remove the nosuid bit, and they find instead that the nosuid bit is silently kept, I don't think they'll be confused: it's pretty obvious in context that this must be for security reasons.

- On the other hand, the current behavior *is* very confusing: mount() returns EPERM because of rules the caller probably doesn't know anything about. I've spent a fair amount of time frustrated by this sort of thing.

-Kenton

A message that is not in the archive (sent off-list or not yet received): CAOP=4wid+N_80iyPpiVMN96_fuHZZRGtYQ6AOPn-HFBj2H6Vgg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org

#106 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

Quoted 40 lines · Kenton Varda
Quoted 39 lines · Andy Lutomirski
Quoted 36 lines · Eric W. Biederman
Quoted 11 lines · Serge Hallyn
Quoted 9 lines · Andy Lutomirski
Quoted 1 line · Eric W. Biederman

I had hoped to get some Tested-By's on that patch series.

Sorry, I've been totally swamped.

I suspect that Sandstorm is okay, but I haven't had a chance to test it for real. Sandstorm makes only limited use of proc and sysfs in containers, but I'll see if I can test it for real this weekend.

Quoted 5 lines

Testing this with unprivileged containers, I get

lxc-start: conf.c: lxc_mount_auto_mounts: 808 Operation not permitted
- error mounting sysfs on /usr/lib/x86_64-linux-gnu/lxc/sys/devices/virtual/net flags 0

Grr.. I was afraid this would break something. :(

Looking at my system I see that sysfs is currently mounted "nosuid,nodev,noexec"

Looking at the lxc-start code I don't see it as including any of those mount options. In practice for sysfs I think those options are meaningless (as there should be no devices and nothing executable in sysfs) but I can understand the past concerns with chmod on virtual filesystems that would incline people to use them, so I think the failure is reporting a legitimate security issue in the lxc userspace code where the the unprivileged code is currently attempting to give greater access to sysfs than was given by the original mount of sysfs.

As nosuid,nodev,noexec should not impair the operation of sysfs operation it looks like you can always specify those options and just make this concern go away.

Quoted 6 lines
Quoted 6 lines

Linus is pretty strict about not breaking the ABI, and this definitely counts as breaking the ABI. There's an exception for security issues, but is there really a security issue here? That is, do we lose anything important if we just drop the offending part of the patch set? As you've said, there shouldn't be sensitive device nodes, executables, or setuid files in proc or sysfs in the first place.

We do need to enforce retaining the existing mount flags one way or another. Where this really matters is with MS_RDONLY. We don't want any old user to be able to mount /proc read-write when root mounted it read-only. There is a very real attack vector there. That attack almost works in docker container today and is avoided simply because docker mounts over a few files on proc.

Which leads to the second side of the reason for these changes. I am
fixing a very small but long standing ABI break. That is in some small
ways I broke some sandboxes and when I realized they were broken I could not imagine think how to fix the code until now.

It is the goal that user namespaces don't introduce anything for people to worry about security wise more than simply the ability to execute more kernel code. So at least when the kernel implementation is correct developers of existing applications simply do not need care. Sadly we are not quite there yet.

Quoted 8 lines

Speaking as a user of the mount() interfaces, I really think it would be less confusing overall if mount() simply ignored the requested flags when the caller doesn't have a choice. That is, in cases where mount() currently fails with EPERM when not given, say, MS_NOSUID, it should instead just pretend the caller actually set MS_NOSUID and go ahead with a nosuid mount. Or put another way, the absence of MS_NOSUID should not be interpreted as "remove the nosuid bit" but rather "don't set the nosuid bit if not required".

I am conflicted. Implicits are nice but confusing. If we can do something reliable and robust and maintainable here that is truly worth the cost I am all for it.

If I mount proc read-write I likely want to be able to write to proc files, and I will be much happier if the mount fails than if a bazillion syscalls later something else fails when it tries to write to proc.

Quoted 13 lines

Consider:

- This approach will actually cause lxc to have the correct behavior, without any changes to lxc. I suspect that this generalizes: In the vast majority of cases, when users have failed to set MS_NOSUID, it's not because they are explicitly requesting that the flag be turned off, but rather that they didn't know it mattered.

- If a user actually *does* expect not passing MS_NOSUID to remove the nosuid bit, and they find instead that the nosuid bit is silently kept, I don't think they'll be confused: it's pretty obvious in context that this must be for security reasons.

Quoted 4 lines

- On the other hand, the current behavior *is* very confusing: mount() returns EPERM because of rules the caller probably doesn't know anything about. I've spent a fair amount of time frustrated by this sort of thing.

My sympathies. This all started with an oh crap we overlooked corner case X and it actually matters, and the fixes were quite likely a little bit hasty. The only case where this really shows up is remount insode of a user namespace of filesystems that were mounted outside of the user namespace is where this all actually matters. And mounting new instances of proc and sysfs wind up being weird instances of that nonsense.

But please someone test sandstorm with this patchset and tell me if it bites you. The impetus to find a way to avoid breaking slightly buggy userspace is higher if it is more than unprivileged lxc that is broken.

Eric

A message that is not in the archive (sent off-list or not yet received): [email protected]

#108 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

Quoted 3 lines · Eric W. Biederman

But please someone test sandstorm with this patchset and tell me if it bites you. The impetus to find a way to avoid breaking slightly buggy userspace is higher if it is more than unprivileged lxc that is broken.

One of these days I'm going to learn how to compile and test kernels again (last time I did it was 1999). Unfortunately I don't think I have time at the moment, but hopefully Andy can do it.

I note, though, that we only have two mount() calls in the sandstorm codebase that seem like they could be affected:

run-bundle.c++:1264: KJ_SYSCALL(mount("proc", "proc", "proc", MS_NOSUID | MS_NODEV | MS_NOEXEC, ""));
minibox.c++:251: KJ_SYSCALL(mount("proc", vpath.cStr(), "proc", MS_NOSUID | MS_NODEV | MS_NOEXEC, ""),
supervisor.c++:921: KJ_SYSCALL(mount("/proc", "proc", nullptr, MS_BIND | MS_REC, nullptr));

The first two seem like they should be fine since they set all the flags (except readonly, which would be inappropriate for proc). I guess my habit of setting every security flag I see came in handy. The third case looks like it will be broken, BUT this line is in a debug-only code path, so I don't care. Also we have the ability to push any needed update within 24 hours, so we're generally in good shape.

We never mount sysfs in Sandstorm.

Quoted 3 lines

If I mount proc read-write I likely want to be able to write to proc files, and I will be much happier if the mount fails than if a bazillion syscalls later something else fails when it tries to write to proc.

I'm not sure that's true. Consider the broader context:
1) Your system's /proc is mounted read-only.
2) Now you're trying to mount a new proc in a new pid namespace, and you do *not* specify MS_READONLY.

What should we expect here? Let's back off a bit and state user intent:
1) The system administrator has set a system-wide policy that /proc may only be read, not written.
2) You made a PID namespace and it needed its own proc.

It seems intuitive here that the administrator's policy should apply in the namespace. Certainly everyone using the system and/or all software on the system already needs to be aware of this policy, since it's unusual and will break things. Running software on this system outside of any container already has the problem that syscalls randomly break, so why should it be surprising when this happens inside the container as well? Why do we need to go out of our way to break at mount() time?

-Kenton

#109 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

Am 28.05.2015 um 22:12 schrieb Kenton Varda:

Quoted 1 line

We never mount sysfs in Sandstorm.

sysfs is ABI and applications depend on it.
Even glibc is using sysfs. Currently it has
fallback paths but these may go away...

Thanks,
//richard

#110 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

Quoted 6 lines · Richard Weinberger

Am 28.05.2015 um 22:12 schrieb Kenton Varda:

Quoted 1 line

We never mount sysfs in Sandstorm.

sysfs is ABI and applications depend on it.
Even glibc is using sysfs. Currently it has
fallback paths but these may go away...

Off-topic, but Sandstorm isn't intended to provide a full Linux ABI. It is intended to provide a secure sandbox that can run apps that have been explicitly ported to Sandstorm. More background if you're interested:

https://github.com/sandstorm-io/sandstorm/wiki/Security-Practices-Overview#server-sandboxing
https://blog.sandstorm.io/news/2014-08-13-sandbox-security.html

-Kenton

A message that is not in the archive (sent off-list or not yet received): CAOP=4wiAA4SqvMn_rQJHOjg6M-75bi_G9Fx8ENgVnYdkT5WVQA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org

#112 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

Am 28.05.2015 um 23:07 schrieb Kenton Varda:

Quoted 11 lines · Richard Weinberger
Quoted 6 lines

Am 28.05.2015 um 22:12 schrieb Kenton Varda:

Quoted 1 line

We never mount sysfs in Sandstorm.

sysfs is ABI and applications depend on it.
Even glibc is using sysfs. Currently it has
fallback paths but these may go away...

Off-topic, but Sandstorm isn't intended to provide a full Linux ABI. It is intended to provide a secure sandbox that can run apps that have been explicitly ported to Sandstorm. More background if you're interested:

Ahh, the application needs to be Sandstorm aware. I was missing that detail. Thanks for pointing that out!

Thanks,
//richard

A message that is not in the archive (sent off-list or not yet received): 55677EE4.2040903-/[email protected]

#114 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

Quoted 6 lines · Richard Weinberger

Am 28.05.2015 um 22:12 schrieb Kenton Varda:

Quoted 1 line

We never mount sysfs in Sandstorm.

sysfs is ABI and applications depend on it.
Even glibc is using sysfs. Currently it has
fallback paths but these may go away...

Off-topic, but Sandstorm isn't intended to provide a full Linux ABI. It is intended to provide a secure sandbox that can run apps that have been explicitly ported to Sandstorm. More background if you're interested:

https://github.com/sandstorm-io/sandstorm/wiki/Security-Practices-Overview#server-sandboxing
https://blog.sandstorm.io/news/2014-08-13-sandbox-security.html

-Kenton

A message that is not in the archive (sent off-list or not yet received): CAOP=4wieEaR_wESNyba7EKPAhi6kf+ujxhoMAFKVRozqWtXHvQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org

#116 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

Am 28.05.2015 um 22:12 schrieb Kenton Varda:

Quoted 1 line

We never mount sysfs in Sandstorm.

sysfs is ABI and applications depend on it.
Even glibc is using sysfs. Currently it has
fallback paths but these may go away...

Thanks,
//richard

#117 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

In reply to a message not in the archive
Quoted 3 lines · Eric W. Biederman

But please someone test sandstorm with this patchset and tell me if it bites you. The impetus to find a way to avoid breaking slightly buggy userspace is higher if it is more than unprivileged lxc that is broken.

One of these days I'm going to learn how to compile and test kernels again (last time I did it was 1999). Unfortunately I don't think I have time at the moment, but hopefully Andy can do it.

I note, though, that we only have two mount() calls in the sandstorm codebase that seem like they could be affected:

run-bundle.c++:1264: KJ_SYSCALL(mount("proc", "proc", "proc", MS_NOSUID | MS_NODEV | MS_NOEXEC, ""));
minibox.c++:251: KJ_SYSCALL(mount("proc", vpath.cStr(), "proc", MS_NOSUID | MS_NODEV | MS_NOEXEC, ""),
supervisor.c++:921: KJ_SYSCALL(mount("/proc", "proc", nullptr, MS_BIND | MS_REC, nullptr));

The first two seem like they should be fine since they set all the flags (except readonly, which would be inappropriate for proc). I guess my habit of setting every security flag I see came in handy. The third case looks like it will be broken, BUT this line is in a debug-only code path, so I don't care. Also we have the ability to push any needed update within 24 hours, so we're generally in good shape.

We never mount sysfs in Sandstorm.

Quoted 3 lines

If I mount proc read-write I likely want to be able to write to proc files, and I will be much happier if the mount fails than if a bazillion syscalls later something else fails when it tries to write to proc.

I'm not sure that's true. Consider the broader context:
1) Your system's /proc is mounted read-only.
2) Now you're trying to mount a new proc in a new pid namespace, and you do *not* specify MS_READONLY.

What should we expect here? Let's back off a bit and state user intent:
1) The system administrator has set a system-wide policy that /proc may only be read, not written.
2) You made a PID namespace and it needed its own proc.

It seems intuitive here that the administrator's policy should apply in the namespace. Certainly everyone using the system and/or all software on the system already needs to be aware of this policy, since it's unusual and will break things. Running software on this system outside of any container already has the problem that syscalls randomly break, so why should it be surprising when this happens inside the container as well? Why do we need to go out of our way to break at mount() time?

-Kenton

#118 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

In reply to a message not in the archive
Quoted 4 lines · Eric W. Biederman
Quoted 1 line · Kenton Varda

On Thu, May 28, 2015 at 10:33 AM, Andy Lutomirski <[email protected]>

Quoted 46 lines · wrote:
Quoted 39 lines
Quoted 39 lines
Quoted 36 lines · Eric W. Biederman
Quoted 11 lines · Serge Hallyn
Quoted 9 lines · Andy Lutomirski
Quoted 1 line · Eric W. Biederman

I had hoped to get some Tested-By's on that patch series.

Sorry, I've been totally swamped.

I suspect that Sandstorm is okay, but I haven't had a chance to test it for real. Sandstorm makes only limited use of proc and sysfs in containers, but I'll see if I can test it for real this weekend.

Quoted 5 lines

Testing this with unprivileged containers, I get

lxc-start: conf.c: lxc_mount_auto_mounts: 808 Operation not permitted
- error mounting sysfs on /usr/lib/x86_64-linux-gnu/lxc/sys/devices/virtual/net flags 0

Grr.. I was afraid this would break something. :(

Looking at my system I see that sysfs is currently mounted "nosuid,nodev,noexec"

Looking at the lxc-start code I don't see it as including any of those mount options. In practice for sysfs I think those options are meaningless (as there should be no devices and nothing executable in sysfs) but I can understand the past concerns with chmod on virtual filesystems that would incline people to use them, so I think the failure is reporting a legitimate security issue in the lxc userspace code where the the unprivileged code is currently attempting to give greater access to sysfs than was given by the original mount of sysfs.

As nosuid,nodev,noexec should not impair the operation of sysfs operation it looks like you can always specify those options and just make this concern go away.

Quoted 6 lines
Quoted 6 lines

Linus is pretty strict about not breaking the ABI, and this definitely counts as breaking the ABI. There's an exception for security issues, but is there really a security issue here? That is, do we lose anything important if we just drop the offending part of the patch set? As you've said, there shouldn't be sensitive device nodes, executables, or setuid files in proc or sysfs in the first place.

Quoted 6 lines

We do need to enforce retaining the existing mount flags one way or another. Where this really matters is with MS_RDONLY. We don't want any old user to be able to mount /proc read-write when root mounted it read-only. There is a very real attack vector there. That attack almost works in docker container today and is avoided simply because docker mounts over a few files on proc.

You could drop the nosuid, noexec, and nodev changes and keep just the ro part. The ro part is probably not an ABI break in the sense of something that actually breaks real programs.

Quoted 21 lines

Which leads to the second side of the reason for these changes. I am
fixing a very small but long standing ABI break. That is in some small
ways I broke some sandboxes and when I realized they were broken I could not imagine think how to fix the code until now.

It is the goal that user namespaces don't introduce anything for people to worry about security wise more than simply the ability to execute more kernel code. So at least when the kernel implementation is correct developers of existing applications simply do not need care. Sadly we are not quite there yet.

Quoted 8 lines

Speaking as a user of the mount() interfaces, I really think it would be less confusing overall if mount() simply ignored the requested flags when the caller doesn't have a choice. That is, in cases where mount() currently fails with EPERM when not given, say, MS_NOSUID, it should instead just pretend the caller actually set MS_NOSUID and go ahead with a nosuid mount. Or put another way, the absence of MS_NOSUID should not be interpreted as "remove the nosuid bit" but rather "don't set the nosuid bit if not required".

Quoted 7 lines

I am conflicted. Implicits are nice but confusing. If we can do something reliable and robust and maintainable here that is truly worth the cost I am all for it.

If I mount proc read-write I likely want to be able to write to proc files, and I will be much happier if the mount fails than if a bazillion syscalls later something else fails when it tries to write to proc.

I agree. I don't like the implicit thing.

--Andy

#119 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

In reply to a message not in the archive

[resend due to HTML. Sorry.]

Quoted 50 lines · Eric W. Biederman
Quoted 40 lines · Kenton Varda
Quoted 39 lines · Andy Lutomirski
Quoted 36 lines · Eric W. Biederman
Quoted 11 lines · Serge Hallyn
Quoted 9 lines · Andy Lutomirski
Quoted 1 line · Eric W. Biederman

I had hoped to get some Tested-By's on that patch series.

Sorry, I've been totally swamped.

I suspect that Sandstorm is okay, but I haven't had a chance to test it for real. Sandstorm makes only limited use of proc and sysfs in containers, but I'll see if I can test it for real this weekend.

Quoted 5 lines

Testing this with unprivileged containers, I get

lxc-start: conf.c: lxc_mount_auto_mounts: 808 Operation not permitted
- error mounting sysfs on /usr/lib/x86_64-linux-gnu/lxc/sys/devices/virtual/net flags 0

Grr.. I was afraid this would break something. :(

Looking at my system I see that sysfs is currently mounted "nosuid,nodev,noexec"

Looking at the lxc-start code I don't see it as including any of those mount options. In practice for sysfs I think those options are meaningless (as there should be no devices and nothing executable in sysfs) but I can understand the past concerns with chmod on virtual filesystems that would incline people to use them, so I think the failure is reporting a legitimate security issue in the lxc userspace code where the the unprivileged code is currently attempting to give greater access to sysfs than was given by the original mount of sysfs.

As nosuid,nodev,noexec should not impair the operation of sysfs operation it looks like you can always specify those options and just make this concern go away.

Quoted 6 lines
Quoted 6 lines

Linus is pretty strict about not breaking the ABI, and this definitely counts as breaking the ABI. There's an exception for security issues, but is there really a security issue here? That is, do we lose anything important if we just drop the offending part of the patch set? As you've said, there shouldn't be sensitive device nodes, executables, or setuid files in proc or sysfs in the first place.

Quoted 6 lines

We do need to enforce retaining the existing mount flags one way or another. Where this really matters is with MS_RDONLY. We don't want any old user to be able to mount /proc read-write when root mounted it read-only. There is a very real attack vector there. That attack almost works in docker container today and is avoided simply because docker mounts over a few files on proc.

You could drop the nosuid, noexec, and nodev changes and keep just the ro part. The ro part is probably not an ABI break in the sense of something that actually breaks real programs.

Quoted 21 lines

Which leads to the second side of the reason for these changes. I am
fixing a very small but long standing ABI break. That is in some small
ways I broke some sandboxes and when I realized they were broken I could not imagine think how to fix the code until now.

It is the goal that user namespaces don't introduce anything for people to worry about security wise more than simply the ability to execute more kernel code. So at least when the kernel implementation is correct developers of existing applications simply do not need care. Sadly we are not quite there yet.

Quoted 8 lines

Speaking as a user of the mount() interfaces, I really think it would be less confusing overall if mount() simply ignored the requested flags when the caller doesn't have a choice. That is, in cases where mount() currently fails with EPERM when not given, say, MS_NOSUID, it should instead just pretend the caller actually set MS_NOSUID and go ahead with a nosuid mount. Or put another way, the absence of MS_NOSUID should not be interpreted as "remove the nosuid bit" but rather "don't set the nosuid bit if not required".

Quoted 7 lines

I am conflicted. Implicits are nice but confusing. If we can do something reliable and robust and maintainable here that is truly worth the cost I am all for it.

If I mount proc read-write I likely want to be able to write to proc files, and I will be much happier if the mount fails than if a bazillion syscalls later something else fails when it tries to write to proc.

I agree. I don't like the implicit thing.

#120 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

In reply to Eric W. Biederman

[resend due to HTML. Sorry.]

Quoted 50 lines · Eric W. Biederman
Quoted 40 lines · Kenton Varda
Quoted 39 lines · Andy Lutomirski
Quoted 36 lines · Eric W. Biederman
Quoted 11 lines · Serge Hallyn
Quoted 9 lines · Andy Lutomirski
Quoted 1 line · Eric W. Biederman

I had hoped to get some Tested-By's on that patch series.

Sorry, I've been totally swamped.

I suspect that Sandstorm is okay, but I haven't had a chance to test it for real. Sandstorm makes only limited use of proc and sysfs in containers, but I'll see if I can test it for real this weekend.

Quoted 5 lines

Testing this with unprivileged containers, I get

lxc-start: conf.c: lxc_mount_auto_mounts: 808 Operation not permitted
- error mounting sysfs on /usr/lib/x86_64-linux-gnu/lxc/sys/devices/virtual/net flags 0

Grr.. I was afraid this would break something. :(

Looking at my system I see that sysfs is currently mounted "nosuid,nodev,noexec"

Looking at the lxc-start code I don't see it as including any of those mount options. In practice for sysfs I think those options are meaningless (as there should be no devices and nothing executable in sysfs) but I can understand the past concerns with chmod on virtual filesystems that would incline people to use them, so I think the failure is reporting a legitimate security issue in the lxc userspace code where the the unprivileged code is currently attempting to give greater access to sysfs than was given by the original mount of sysfs.

As nosuid,nodev,noexec should not impair the operation of sysfs operation it looks like you can always specify those options and just make this concern go away.

Quoted 6 lines
Quoted 6 lines

Linus is pretty strict about not breaking the ABI, and this definitely counts as breaking the ABI. There's an exception for security issues, but is there really a security issue here? That is, do we lose anything important if we just drop the offending part of the patch set? As you've said, there shouldn't be sensitive device nodes, executables, or setuid files in proc or sysfs in the first place.

Quoted 6 lines

We do need to enforce retaining the existing mount flags one way or another. Where this really matters is with MS_RDONLY. We don't want any old user to be able to mount /proc read-write when root mounted it read-only. There is a very real attack vector there. That attack almost works in docker container today and is avoided simply because docker mounts over a few files on proc.

You could drop the nosuid, noexec, and nodev changes and keep just the ro part. The ro part is probably not an ABI break in the sense of something that actually breaks real programs.

Quoted 21 lines

Which leads to the second side of the reason for these changes. I am
fixing a very small but long standing ABI break. That is in some small
ways I broke some sandboxes and when I realized they were broken I could not imagine think how to fix the code until now.

It is the goal that user namespaces don't introduce anything for people to worry about security wise more than simply the ability to execute more kernel code. So at least when the kernel implementation is correct developers of existing applications simply do not need care. Sadly we are not quite there yet.

Quoted 8 lines

Speaking as a user of the mount() interfaces, I really think it would be less confusing overall if mount() simply ignored the requested flags when the caller doesn't have a choice. That is, in cases where mount() currently fails with EPERM when not given, say, MS_NOSUID, it should instead just pretend the caller actually set MS_NOSUID and go ahead with a nosuid mount. Or put another way, the absence of MS_NOSUID should not be interpreted as "remove the nosuid bit" but rather "don't set the nosuid bit if not required".

Quoted 7 lines

I am conflicted. Implicits are nice but confusing. If we can do something reliable and robust and maintainable here that is truly worth the cost I am all for it.

If I mount proc read-write I likely want to be able to write to proc files, and I will be much happier if the mount fails than if a bazillion syscalls later something else fails when it tries to write to proc.

I agree. I don't like the implicit thing.

A message that is not in the archive (sent off-list or not yet received): CALCETrXO21Y7PR=pKqaqJb1YZArNyjAv7Z-J44O53FcfLM_0Tw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org

#122 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

Quoted 10 lines · Andy Lutomirski
Quoted 8 lines · Eric W. Biederman

Kenton Varda <[email protected]> writes:

We do need to enforce retaining the existing mount flags one way or another. Where this really matters is with MS_RDONLY. We don't want any old user to be able to mount /proc read-write when root mounted it read-only. There is a very real attack vector there. That attack almost works in docker container today and is avoided simply because docker mounts over a few files on proc.

Quoted 3 lines

You could drop the nosuid, noexec, and nodev changes and keep just the ro part. The ro part is probably not an ABI break in the sense of something that actually breaks real programs.

As a change simply removing the code from the existing patches that worries about nosuid, noexec, and the nodev flags is certainly doable. It is the best proposal I have heard so far.

I remain unconvinced about ignoring those flags:
- There are clearly people who think it matters (or else proc and sysfs would not have those flags specified).

- There have been times when it actually has mattered. Aka when files like /proc/self/env could be chmodded and used for privilege escalation.

- The code in lxc and libvirt-lxc so far has been clearly buggy.
* lxc only has problems with sysfs (in some configurations).
* libvirt-lxc only has problems on a bind mount remount of proc after remounting proc properly.

So I am leaning towards enforcing all of the mount flags including nosuid, noexec, and nodev. Then when the next subtle bug in proc or sysfs with respect to chmod shows up I will be able to sleep soundly at night because the mount flags of those filesystems allow a mitigation, and I did not sabatage the mitigation.

Plus contemplating code that just enforces a couple of mount flags but not all of the feels wrong.

I don't think it is actually a maintainable position to just enforce a couple of those flags. If nothing else I would expect someone to look at the code and to generate a bug fix to start enforcing the rest of the flags. Or perhaps it is in a few years time and something gets refactored and the enforcing starts happening by virtue of using a new common function that no-one realizes will be a problem.

Additionally if we don't enforce nosuid, noexec, and nodev people are going to ask questions, that will be hard to explain. When what is truly desirable is to say that sysfs and proc are a little odd but they don't allow anything that a bind mount won't.

I can be persuaded otherwise but right now I do think the kernel code needs to enforce nosuid, noexec, and nodev as it is a security issue (if only a defence in depth one), and a maintenance issue as I do not believe in the long term it is a maintanable or an explicable position.

Quoted 13 lines
Quoted 13 lines
Quoted 8 lines

Speaking as a user of the mount() interfaces, I really think it would be less confusing overall if mount() simply ignored the requested flags when the caller doesn't have a choice. That is, in cases where mount() currently fails with EPERM when not given, say, MS_NOSUID, it should instead just pretend the caller actually set MS_NOSUID and go ahead with a nosuid mount. Or put another way, the absence of MS_NOSUID should not be interpreted as "remove the nosuid bit" but rather "don't set the nosuid bit if not required".

I am conflicted. Implicits are nice but confusing. If we can do something reliable and robust and maintainable here that is truly worth the cost I am all for it.

Quoted 5 lines
Quoted 3 lines

If I mount proc read-write I likely want to be able to write to proc files, and I will be much happier if the mount fails than if a bazillion syscalls later something else fails when it tries to write to proc.

I agree. I don't like the implicit thing.

My memory returns of our last round of looking at this and for whatever it's warts the existing mount API for remounting filesystems needs to have the flags have exactly the same meaning as at mount time. There are existing userspace applications that depend on that behavior.

Implicits for only the locked mount flags is a little different but still ick.

Eric

A message that is not in the archive (sent off-list or not yet received): [email protected]

#124 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

Quoted 2 lines · Eric W. Biederman

Implicits for only the locked mount flags is a little different but still ick.

FWIW, I only ever meant to advocate for this for locked flags, i.e. cases where the only other option is to throw EPERM. Clearly when the user has permission, the exact requested flags should be applied, or all kinds of things break.

It seems to me that if we can fix the security issue without breaking userspace, we should. Sometimes we end up with icky APIs to avoid breaking userspace. (Though IMO implicitly preserving locked bits is not icky at all.)

-Kenton

#125 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

In reply to a message not in the archive
Quoted 32 lines · Eric W. Biederman
Quoted 10 lines · Andy Lutomirski
Quoted 8 lines · Eric W. Biederman

Kenton Varda <[email protected]> writes:

We do need to enforce retaining the existing mount flags one way or another. Where this really matters is with MS_RDONLY. We don't want any old user to be able to mount /proc read-write when root mounted it read-only. There is a very real attack vector there. That attack almost works in docker container today and is avoided simply because docker mounts over a few files on proc.

Quoted 3 lines

You could drop the nosuid, noexec, and nodev changes and keep just the ro part. The ro part is probably not an ABI break in the sense of something that actually breaks real programs.

As a change simply removing the code from the existing patches that worries about nosuid, noexec, and the nodev flags is certainly doable. It is the best proposal I have heard so far.

I remain unconvinced about ignoring those flags:
- There are clearly people who think it matters (or else proc and sysfs would not have those flags specified).

- There have been times when it actually has mattered. Aka when files like /proc/self/env could be chmodded and used for privilege escalation.

- The code in lxc and libvirt-lxc so far has been clearly buggy.
* lxc only has problems with sysfs (in some configurations).
* libvirt-lxc only has problems on a bind mount remount of proc after remounting proc properly.

Quoted 5 lines

So I am leaning towards enforcing all of the mount flags including nosuid, noexec, and nodev. Then when the next subtle bug in proc or sysfs with respect to chmod shows up I will be able to sleep soundly at night because the mount flags of those filesystems allow a mitigation, and I did not sabatage the mitigation.

One option would be to break the nosuid, nodev, and noexec parts into their own patch and then avoid tagging that patch for -stable if at all possible. It would be nice to avoid another -stable ABI break if at all possible.

--Andy

#126 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

Quoted 4 lines · Andy Lutomirski

One option would be to break the nosuid, nodev, and noexec parts into their own patch and then avoid tagging that patch for -stable if at all possible. It would be nice to avoid another -stable ABI break if at all possible.

So I don't think we actually have anything that could be called an ABI break in the whole mess, but it is definitely a behavioral change that is a regression for lxc and libvirt-lxc that prevents them from starting.

nodev does not actually matter because of the implicit silliness that is being added right now.

We do want those programs fixed and after those programs are fixed we can safely begin failing mount when those attributes are being cleared in a fresh mount.

So it looks to me like the best thing to do is to print a warning whenever lxc or libvirt-lxc gets it wrong, which should ensure the authors are sufficiently pestered that in a kernel release or 3 we can begin enforcing those attributes. Especially as the discussion on the fix for those applications has already begun.

And if folks would double check the patch I am going to post in a moment to ensure that lxc and libvirt-lxc continue to start I would appreciate it.

Eric

A message that is not in the archive (sent off-list or not yet received): [email protected]

#128 lore raw

[CFT][PATCH 11/10] mnt: Avoid unnecessary regressions in fs_fully_visible

Not allowing programs to clear nosuid, nodev, and noexec on new mounts of sysfs or proc will cause lxc and libvirt-lxc to fail to start (a regression). There are no device nodes or executables on sysfs or proc today which means clearing these flags is harmless today.

Instead of failing the fresh mounts of sysfs and proc emit a warning when these flags are improprely cleared. We only reach this point because lxc and libvirt-lxc clear flags they mount flags had not intended to.

In a couple of kernel releases when lxc and libvirt-lxc have been fixed we can start failing fresh mounts proc and sysfs that clear nosuid, nodev and noexec. Userspace clearly means to enforce those attributes and historically they have avoided bugs.

---
 fs/namespace.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)
fs/namespace.c +27 -0
index eccd925c6e82..eaa49b628d28 100644
@@ -3198,6 +3198,7 @@ static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags)
 		if ((mnt->mnt.mnt_flags & MNT_LOCK_READONLY) &&
 		    !(new_flags & MNT_READONLY))
 			continue;
+#if 0		/* Avoid unnecessary regressions */
 		if ((mnt->mnt.mnt_flags & MNT_LOCK_NODEV) &&
 		    !(new_flags & MNT_NODEV))
 			continue;
@@ -3207,6 +3208,7 @@ static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags)
 		if ((mnt->mnt.mnt_flags & MNT_LOCK_NOEXEC) &&
 		    !(new_flags & MNT_NOEXEC))
 			continue;
+#endif
 		if ((mnt->mnt.mnt_flags & MNT_LOCK_ATIME) &&
 		    ((mnt->mnt.mnt_flags & MNT_ATIME_MASK) != (new_flags & MNT_ATIME_MASK)))
 			continue;
@@ -3226,10 +3228,35 @@ static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags)
 		}
 		/* Preserve the locked attributes */
 		*new_mnt_flags |= mnt->mnt.mnt_flags & (MNT_LOCK_READONLY | \
+						/* Avoid unnecessary regressions \
 							MNT_LOCK_NODEV    | \
 							MNT_LOCK_NOSUID   | \
 							MNT_LOCK_NOEXEC   | \
+						 */ \
 							MNT_LOCK_ATIME);
+		/* For now, warn about the "harmless" but invalid mnt flags */
+		{
+			bool nodev = false, nosuid = false, noexec = false;
+			if ((mnt->mnt.mnt_flags & MNT_LOCK_NODEV) &&
+			    !(new_flags & MNT_NODEV))
+				nodev = true;
+			if ((mnt->mnt.mnt_flags & MNT_LOCK_NOSUID) &&
+			    !(new_flags & MNT_NOSUID))
+				nosuid = true;
+			if ((mnt->mnt.mnt_flags & MNT_LOCK_NOEXEC) &&
+			    !(new_flags & MNT_NOEXEC))
+				noexec = true;
+
+			if ((nodev || nosuid || noexec) && printk_ratelimit()) {
+				printk(KERN_INFO
+				       "warning: process `%s' clears %s%s%sin mount of %s\n",
+				       current->comm,
+				       nodev ? "nodev ":"",
+				       nosuid ? "nosuid ":"",
+				       noexec ? "noexec ":"",
+				       type->name);
+			}
+		}
 		visible = true;
 		goto found;
 	next:	;
Signature · 1 line
2.2.1

A message that is not in the archive (sent off-list or not yet received): 87eglseboh.fsf_-_-JOvCrm2gF+uungPnsOpG7nhyD016LWXt@public.gmane.org

#130 lore raw

[CFT][PATCH 11/10] mnt: Avoid unnecessary regressions in fs_fully_visible (take 2)

Not allowing programs to clear nosuid and noexec on new mounts of sysfs or proc will cause lxc and libvirt-lxc to fail to start (a regression). There are no executables files on sysfs or proc today which means clearing these flags is harmless today.

Instead of failing the fresh mounts of sysfs and proc emit a warning when these flags are improprely cleared. We only reach this point because lxc and libvirt-lxc clear flags they mount flags had not intended to.

In a couple of kernel releases when lxc and libvirt-lxc have been fixed we can start failing fresh mounts proc and sysfs that clear nosuid and noexec. Userspace clearly means to enforce those attributes and enforcing these attributes have historically avoided bugs in the setattr implementations of proc and sysfs.

---

Now with warning on problematic remounts as well. nodev is also ignored because it is not currently problematic.

 fs/namespace.c        | 33 +++++++++++++++++++++++++++++++++
 include/linux/mount.h |  5 +++++
 2 files changed, 38 insertions(+)
fs/namespace.c +33 -0
index eccd925c6e82..3c3f8172c734 100644
@@ -2162,6 +2162,18 @@ static int do_remount(struct path *path, int flags, int mnt_flags,
 	    ((mnt->mnt.mnt_flags & MNT_ATIME_MASK) != (mnt_flags & MNT_ATIME_MASK))) {
 		return -EPERM;
 	}
+	if ((mnt->mnt.mnt_flags & MNT_WARN_NOSUID) &&
+	    !(mnt_flags & MNT_NOSUID) && printk_ratelimit()) {
+		printk(KERN_INFO
+		       "warning: process `%s' clears nosuid in remount of %s\n",
+		       current->comm, sb->s_type->name);
+	}
+	if ((mnt->mnt.mnt_flags & MNT_WARN_NOEXEC) &&
+	    !(mnt_flags & MNT_NOEXEC) && printk_ratelimit()) {
+		printk(KERN_INFO
+		       "warning: process `%s' clears noexec in remount of %s\n",
+		       current->comm, sb->s_type->name);
+	}
 
 	err = security_sb_remount(sb, data);
 	if (err)
@@ -3201,12 +3213,14 @@ static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags)
 		if ((mnt->mnt.mnt_flags & MNT_LOCK_NODEV) &&
 		    !(new_flags & MNT_NODEV))
 			continue;
+#if 0		/* Avoid unnecessary regressions */
 		if ((mnt->mnt.mnt_flags & MNT_LOCK_NOSUID) &&
 		    !(new_flags & MNT_NOSUID))
 			continue;
 		if ((mnt->mnt.mnt_flags & MNT_LOCK_NOEXEC) &&
 		    !(new_flags & MNT_NOEXEC))
 			continue;
+#endif
 		if ((mnt->mnt.mnt_flags & MNT_LOCK_ATIME) &&
 		    ((mnt->mnt.mnt_flags & MNT_ATIME_MASK) != (new_flags & MNT_ATIME_MASK)))
 			continue;
@@ -3227,9 +3241,28 @@ static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags)
 		/* Preserve the locked attributes */
 		*new_mnt_flags |= mnt->mnt.mnt_flags & (MNT_LOCK_READONLY | \
 							MNT_LOCK_NODEV    | \
+						/* Avoid unnecessary regressions \
 							MNT_LOCK_NOSUID   | \
 							MNT_LOCK_NOEXEC   | \
+						 */ \
 							MNT_LOCK_ATIME);
+		/* For now, warn about the "harmless" but invalid mnt flags */
+		if (mnt->mnt.mnt_flags & MNT_LOCK_NOSUID) {
+			*new_mnt_flags |= MNT_WARN_NOSUID;
+			if (!(new_flags & MNT_NOSUID) && printk_ratelimit()) {
+				printk(KERN_INFO
+				       "warning: process `%s' clears nosuid in mount of %s\n",
+				       current->comm, type->name);
+			}
+		}
+		if (mnt->mnt.mnt_flags & MNT_LOCK_NOEXEC) {
+			*new_mnt_flags |= MNT_WARN_NOEXEC;
+			if (!(new_flags & MNT_NOEXEC) && printk_ratelimit()) {
+				printk(KERN_INFO
+				       "warning: process `%s' clears noexec in mount of %s\n",
+				       current->comm, type->name);
+			}
+		}
 		visible = true;
 		goto found;
 	next:	;
include/linux/mount.h +5 -0
index f822c3c11377..a9ac188413fd 100644
@@ -52,6 +52,11 @@ struct mnt_namespace;
 
 #define MNT_INTERNAL	0x4000
 
+/* These warning options should be removed in a few kernel releases
+ * once userspace has been fixed.
+ */
+#define MNT_WARN_NOSUID		0x010000
+#define MNT_WARN_NOEXEC		0x020000
 #define MNT_LOCK_ATIME		0x040000
 #define MNT_LOCK_NOEXEC		0x080000
 #define MNT_LOCK_NOSUID		0x100000
Signature · 1 line
2.2.1

A message that is not in the archive (sent off-list or not yet received): 874mmodral.fsf_-_-JOvCrm2gF+uungPnsOpG7nhyD016LWXt@public.gmane.org

#132 lore raw

Re: [CFT][PATCH 11/10] mnt: Avoid unnecessary regressions in fs_fully_visible (take 2)

Quoted 82 lines · Eric W. Biederman

Not allowing programs to clear nosuid and noexec on new mounts of sysfs or proc will cause lxc and libvirt-lxc to fail to start (a regression). There are no executables files on sysfs or proc today which means clearing these flags is harmless today.

Instead of failing the fresh mounts of sysfs and proc emit a warning when these flags are improprely cleared. We only reach this point because lxc and libvirt-lxc clear flags they mount flags had not intended to.

In a couple of kernel releases when lxc and libvirt-lxc have been fixed we can start failing fresh mounts proc and sysfs that clear nosuid and noexec. Userspace clearly means to enforce those attributes and enforcing these attributes have historically avoided bugs in the setattr implementations of proc and sysfs.

---

Now with warning on problematic remounts as well. nodev is also ignored because it is not currently problematic.

 fs/namespace.c        | 33 +++++++++++++++++++++++++++++++++
 include/linux/mount.h |  5 +++++
 2 files changed, 38 insertions(+)
fs/namespace.c +23 -0
index eccd925c6e82..3c3f8172c734 100644
@@ -2162,6 +2162,18 @@ static int do_remount(struct path *path, int flags, int mnt_flags,
 	    ((mnt->mnt.mnt_flags & MNT_ATIME_MASK) != (mnt_flags & MNT_ATIME_MASK))) {
 		return -EPERM;
 	}
+	if ((mnt->mnt.mnt_flags & MNT_WARN_NOSUID) &&
+	    !(mnt_flags & MNT_NOSUID) && printk_ratelimit()) {
+		printk(KERN_INFO
+		       "warning: process `%s' clears nosuid in remount of %s\n",
+		       current->comm, sb->s_type->name);
+	}
+	if ((mnt->mnt.mnt_flags & MNT_WARN_NOEXEC) &&
+	    !(mnt_flags & MNT_NOEXEC) && printk_ratelimit()) {
+		printk(KERN_INFO
+		       "warning: process `%s' clears noexec in remount of %s\n",
+		       current->comm, sb->s_type->name);
+	}
 
 	err = security_sb_remount(sb, data);
 	if (err)
@@ -3201,12 +3213,14 @@ static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags)
 		if ((mnt->mnt.mnt_flags & MNT_LOCK_NODEV) &&
 		    !(new_flags & MNT_NODEV))
 			continue;
+#if 0		/* Avoid unnecessary regressions */
 		if ((mnt->mnt.mnt_flags & MNT_LOCK_NOSUID) &&
 		    !(new_flags & MNT_NOSUID))
 			continue;
 		if ((mnt->mnt.mnt_flags & MNT_LOCK_NOEXEC) &&
 		    !(new_flags & MNT_NOEXEC))
 			continue;
+#endif
 		if ((mnt->mnt.mnt_flags & MNT_LOCK_ATIME) &&
 		    ((mnt->mnt.mnt_flags & MNT_ATIME_MASK) != (new_flags & MNT_ATIME_MASK)))
 			continue;
@@ -3227,9 +3241,28 @@ static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags)
 		/* Preserve the locked attributes */
 		*new_mnt_flags |= mnt->mnt.mnt_flags & (MNT_LOCK_READONLY | \
 							MNT_LOCK_NODEV    | \
+						/* Avoid unnecessary regressions \
 							MNT_LOCK_NOSUID   | \
 							MNT_LOCK_NOEXEC   | \
+						 */ \
 							MNT_LOCK_ATIME);
+		/* For now, warn about the "harmless" but invalid mnt flags */
+		if (mnt->mnt.mnt_flags & MNT_LOCK_NOSUID) {
+			*new_mnt_flags |= MNT_WARN_NOSUID;
+			if (!(new_flags & MNT_NOSUID) && printk_ratelimit()) {
+				printk(KERN_INFO
+				       "warning: process `%s' clears nosuid in mount of %s\n",
+				       current->comm, type->name);

fs/namespace.c static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags) · line 3265

Quoted 10 lines
fs/namespace.c +10 -0
+			}
+		}
+		if (mnt->mnt.mnt_flags & MNT_LOCK_NOEXEC) {
+			*new_mnt_flags |= MNT_WARN_NOEXEC;
+			if (!(new_flags & MNT_NOEXEC) && printk_ratelimit()) {
+				printk(KERN_INFO
+				       "warning: process `%s' clears noexec in mount of %s\n",
+				       current->comm, type->name);
+			}
+		}

Adding this to a stable kernel is not going to be ok, sorry. We can't start being noisy in system logs for things that were working just fine.

greg k-h

#133 lore raw

Re: [CFT][PATCH 11/10] mnt: Avoid unnecessary regressions in fs_fully_visible (take 2)

In reply to a message not in the archive
Quoted 82 lines · Eric W. Biederman

Not allowing programs to clear nosuid and noexec on new mounts of sysfs or proc will cause lxc and libvirt-lxc to fail to start (a regression). There are no executables files on sysfs or proc today which means clearing these flags is harmless today.

Instead of failing the fresh mounts of sysfs and proc emit a warning when these flags are improprely cleared. We only reach this point because lxc and libvirt-lxc clear flags they mount flags had not intended to.

In a couple of kernel releases when lxc and libvirt-lxc have been fixed we can start failing fresh mounts proc and sysfs that clear nosuid and noexec. Userspace clearly means to enforce those attributes and enforcing these attributes have historically avoided bugs in the setattr implementations of proc and sysfs.

---

Now with warning on problematic remounts as well. nodev is also ignored because it is not currently problematic.

 fs/namespace.c        | 33 +++++++++++++++++++++++++++++++++
 include/linux/mount.h |  5 +++++
 2 files changed, 38 insertions(+)
fs/namespace.c +23 -0
index eccd925c6e82..3c3f8172c734 100644
@@ -2162,6 +2162,18 @@ static int do_remount(struct path *path, int flags, int mnt_flags,
 	    ((mnt->mnt.mnt_flags & MNT_ATIME_MASK) != (mnt_flags & MNT_ATIME_MASK))) {
 		return -EPERM;
 	}
+	if ((mnt->mnt.mnt_flags & MNT_WARN_NOSUID) &&
+	    !(mnt_flags & MNT_NOSUID) && printk_ratelimit()) {
+		printk(KERN_INFO
+		       "warning: process `%s' clears nosuid in remount of %s\n",
+		       current->comm, sb->s_type->name);
+	}
+	if ((mnt->mnt.mnt_flags & MNT_WARN_NOEXEC) &&
+	    !(mnt_flags & MNT_NOEXEC) && printk_ratelimit()) {
+		printk(KERN_INFO
+		       "warning: process `%s' clears noexec in remount of %s\n",
+		       current->comm, sb->s_type->name);
+	}
 
 	err = security_sb_remount(sb, data);
 	if (err)
@@ -3201,12 +3213,14 @@ static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags)
 		if ((mnt->mnt.mnt_flags & MNT_LOCK_NODEV) &&
 		    !(new_flags & MNT_NODEV))
 			continue;
+#if 0		/* Avoid unnecessary regressions */
 		if ((mnt->mnt.mnt_flags & MNT_LOCK_NOSUID) &&
 		    !(new_flags & MNT_NOSUID))
 			continue;
 		if ((mnt->mnt.mnt_flags & MNT_LOCK_NOEXEC) &&
 		    !(new_flags & MNT_NOEXEC))
 			continue;
+#endif
 		if ((mnt->mnt.mnt_flags & MNT_LOCK_ATIME) &&
 		    ((mnt->mnt.mnt_flags & MNT_ATIME_MASK) != (new_flags & MNT_ATIME_MASK)))
 			continue;
@@ -3227,9 +3241,28 @@ static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags)
 		/* Preserve the locked attributes */
 		*new_mnt_flags |= mnt->mnt.mnt_flags & (MNT_LOCK_READONLY | \
 							MNT_LOCK_NODEV    | \
+						/* Avoid unnecessary regressions \
 							MNT_LOCK_NOSUID   | \
 							MNT_LOCK_NOEXEC   | \
+						 */ \
 							MNT_LOCK_ATIME);
+		/* For now, warn about the "harmless" but invalid mnt flags */
+		if (mnt->mnt.mnt_flags & MNT_LOCK_NOSUID) {
+			*new_mnt_flags |= MNT_WARN_NOSUID;
+			if (!(new_flags & MNT_NOSUID) && printk_ratelimit()) {
+				printk(KERN_INFO
+				       "warning: process `%s' clears nosuid in mount of %s\n",
+				       current->comm, type->name);

fs/namespace.c static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags) · line 3265

Quoted 10 lines
fs/namespace.c +10 -0
+			}
+		}
+		if (mnt->mnt.mnt_flags & MNT_LOCK_NOEXEC) {
+			*new_mnt_flags |= MNT_WARN_NOEXEC;
+			if (!(new_flags & MNT_NOEXEC) && printk_ratelimit()) {
+				printk(KERN_INFO
+				       "warning: process `%s' clears noexec in mount of %s\n",
+				       current->comm, type->name);
+			}
+		}

Adding this to a stable kernel is not going to be ok, sorry. We can't start being noisy in system logs for things that were working just fine.

greg k-h

#134 lore raw

[CFT][PATCH 11/10] mnt: Avoid unnecessary regressions in fs_fully_visible (take 2)

In reply to a message not in the archive

Not allowing programs to clear nosuid and noexec on new mounts of sysfs or proc will cause lxc and libvirt-lxc to fail to start (a regression). There are no executables files on sysfs or proc today which means clearing these flags is harmless today.

Instead of failing the fresh mounts of sysfs and proc emit a warning when these flags are improprely cleared. We only reach this point because lxc and libvirt-lxc clear flags they mount flags had not intended to.

In a couple of kernel releases when lxc and libvirt-lxc have been fixed we can start failing fresh mounts proc and sysfs that clear nosuid and noexec. Userspace clearly means to enforce those attributes and enforcing these attributes have historically avoided bugs in the setattr implementations of proc and sysfs.

---

Now with warning on problematic remounts as well. nodev is also ignored because it is not currently problematic.

 fs/namespace.c        | 33 +++++++++++++++++++++++++++++++++
 include/linux/mount.h |  5 +++++
 2 files changed, 38 insertions(+)
fs/namespace.c +33 -0
index eccd925c6e82..3c3f8172c734 100644
@@ -2162,6 +2162,18 @@ static int do_remount(struct path *path, int flags, int mnt_flags,
 	    ((mnt->mnt.mnt_flags & MNT_ATIME_MASK) != (mnt_flags & MNT_ATIME_MASK))) {
 		return -EPERM;
 	}
+	if ((mnt->mnt.mnt_flags & MNT_WARN_NOSUID) &&
+	    !(mnt_flags & MNT_NOSUID) && printk_ratelimit()) {
+		printk(KERN_INFO
+		       "warning: process `%s' clears nosuid in remount of %s\n",
+		       current->comm, sb->s_type->name);
+	}
+	if ((mnt->mnt.mnt_flags & MNT_WARN_NOEXEC) &&
+	    !(mnt_flags & MNT_NOEXEC) && printk_ratelimit()) {
+		printk(KERN_INFO
+		       "warning: process `%s' clears noexec in remount of %s\n",
+		       current->comm, sb->s_type->name);
+	}
 
 	err = security_sb_remount(sb, data);
 	if (err)
@@ -3201,12 +3213,14 @@ static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags)
 		if ((mnt->mnt.mnt_flags & MNT_LOCK_NODEV) &&
 		    !(new_flags & MNT_NODEV))
 			continue;
+#if 0		/* Avoid unnecessary regressions */
 		if ((mnt->mnt.mnt_flags & MNT_LOCK_NOSUID) &&
 		    !(new_flags & MNT_NOSUID))
 			continue;
 		if ((mnt->mnt.mnt_flags & MNT_LOCK_NOEXEC) &&
 		    !(new_flags & MNT_NOEXEC))
 			continue;
+#endif
 		if ((mnt->mnt.mnt_flags & MNT_LOCK_ATIME) &&
 		    ((mnt->mnt.mnt_flags & MNT_ATIME_MASK) != (new_flags & MNT_ATIME_MASK)))
 			continue;
@@ -3227,9 +3241,28 @@ static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags)
 		/* Preserve the locked attributes */
 		*new_mnt_flags |= mnt->mnt.mnt_flags & (MNT_LOCK_READONLY | \
 							MNT_LOCK_NODEV    | \
+						/* Avoid unnecessary regressions \
 							MNT_LOCK_NOSUID   | \
 							MNT_LOCK_NOEXEC   | \
+						 */ \
 							MNT_LOCK_ATIME);
+		/* For now, warn about the "harmless" but invalid mnt flags */
+		if (mnt->mnt.mnt_flags & MNT_LOCK_NOSUID) {
+			*new_mnt_flags |= MNT_WARN_NOSUID;
+			if (!(new_flags & MNT_NOSUID) && printk_ratelimit()) {
+				printk(KERN_INFO
+				       "warning: process `%s' clears nosuid in mount of %s\n",
+				       current->comm, type->name);
+			}
+		}
+		if (mnt->mnt.mnt_flags & MNT_LOCK_NOEXEC) {
+			*new_mnt_flags |= MNT_WARN_NOEXEC;
+			if (!(new_flags & MNT_NOEXEC) && printk_ratelimit()) {
+				printk(KERN_INFO
+				       "warning: process `%s' clears noexec in mount of %s\n",
+				       current->comm, type->name);
+			}
+		}
 		visible = true;
 		goto found;
 	next:	;
include/linux/mount.h +5 -0
index f822c3c11377..a9ac188413fd 100644
@@ -52,6 +52,11 @@ struct mnt_namespace;
 
 #define MNT_INTERNAL	0x4000
 
+/* These warning options should be removed in a few kernel releases
+ * once userspace has been fixed.
+ */
+#define MNT_WARN_NOSUID		0x010000
+#define MNT_WARN_NOEXEC		0x020000
 #define MNT_LOCK_ATIME		0x040000
 #define MNT_LOCK_NOEXEC		0x080000
 #define MNT_LOCK_NOSUID		0x100000
Signature · 1 line
2.2.1
#135 lore raw

Re: [CFT][PATCH 11/10] mnt: Avoid unnecessary regressions in fs_fully_visible

In reply to a message not in the archive
Quoted 11 lines · Eric W. Biederman

Not allowing programs to clear nosuid, nodev, and noexec on new mounts of sysfs or proc will cause lxc and libvirt-lxc to fail to start (a regression). There are no device nodes or executables on sysfs or proc today which means clearing these flags is harmless today.

Instead of failing the fresh mounts of sysfs and proc emit a warning when these flags are improprely cleared. We only reach this point because lxc and libvirt-lxc clear flags they mount flags had not intended to.

Quoted 4 lines

In a couple of kernel releases when lxc and libvirt-lxc have been fixed we can start failing fresh mounts proc and sysfs that clear nosuid, nodev and noexec. Userspace clearly means to enforce those attributes and historically they have avoided bugs.

At the very least, I think this should be folded in so that the ABI doesn't break in the middle of the series.

--Andy

A message that is not in the archive (sent off-list or not yet received): CALCETrWwtFaiaYGLoq4EPkrgcq9nEA2GseVfP3iBkbYZ8NfGPg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org

#137 lore raw

Re: [CFT][PATCH 11/10] mnt: Avoid unnecessary regressions in fs_fully_visible

Quoted 12 lines · Andy Lutomirski
Quoted 11 lines · Eric W. Biederman

Not allowing programs to clear nosuid, nodev, and noexec on new mounts of sysfs or proc will cause lxc and libvirt-lxc to fail to start (a regression). There are no device nodes or executables on sysfs or proc today which means clearing these flags is harmless today.

Instead of failing the fresh mounts of sysfs and proc emit a warning when these flags are improprely cleared. We only reach this point because lxc and libvirt-lxc clear flags they mount flags had not intended to.

Quoted 7 lines
Quoted 4 lines

In a couple of kernel releases when lxc and libvirt-lxc have been fixed we can start failing fresh mounts proc and sysfs that clear nosuid, nodev and noexec. Userspace clearly means to enforce those attributes and historically they have avoided bugs.

At the very least, I think this should be folded in so that the ABI doesn't break in the middle of the series.

Nothing in any of these patches has ever broken the ABI. The bits have always been interpreted with the same meaning.

I have been going back and forth on exactly the best way to handle this because I don't like breaking working executables even for valid reasons.

I think I have finally reach my personal peace on this issue.

Not requiring the presence of nosuid and noexec on a fresh mount of proc and sysfs if the original mount has nosuid or noexec is a security issue as what proc and sysfs implement in the future can not be known.

The one possible way to remedy this is to implicity add nosuid and noexec as appropriate unfortunately that would break the ABI as it changes the interpretation of the bits in the userspace interface, and the day proc or sysfs changes and we honest to truly want to enable suid exectuables on proc or sysfs we would not be able to. :( So implicitly adding attributes is out.

As the current implementation of proc and sysfs are known I agree it does not make sense to backport the enforcement of nosuid and
noexec. So I have split the patch. See my for-testing branch
and shortly my for-next branch.

It only takes two or three line patches in the affected userspace executables, and a 5 minute test. So a warning printk does not actually make sense.

If the authors of lxc and libvirt-lxc have not taken the time to fix their code by the time this code lands in a stable release (in 2 months or so) no amount of other warnings are going to be enough.

Eric

#138 lore raw

Re: [CFT][PATCH 11/10] mnt: Avoid unnecessary regressions in fs_fully_visible

In reply to a message not in the archive
Quoted 12 lines · Andy Lutomirski
Quoted 11 lines · Eric W. Biederman

Not allowing programs to clear nosuid, nodev, and noexec on new mounts of sysfs or proc will cause lxc and libvirt-lxc to fail to start (a regression). There are no device nodes or executables on sysfs or proc today which means clearing these flags is harmless today.

Instead of failing the fresh mounts of sysfs and proc emit a warning when these flags are improprely cleared. We only reach this point because lxc and libvirt-lxc clear flags they mount flags had not intended to.

Quoted 7 lines
Quoted 4 lines

In a couple of kernel releases when lxc and libvirt-lxc have been fixed we can start failing fresh mounts proc and sysfs that clear nosuid, nodev and noexec. Userspace clearly means to enforce those attributes and historically they have avoided bugs.

At the very least, I think this should be folded in so that the ABI doesn't break in the middle of the series.

Nothing in any of these patches has ever broken the ABI. The bits have always been interpreted with the same meaning.

I have been going back and forth on exactly the best way to handle this because I don't like breaking working executables even for valid reasons.

I think I have finally reach my personal peace on this issue.

Not requiring the presence of nosuid and noexec on a fresh mount of proc and sysfs if the original mount has nosuid or noexec is a security issue as what proc and sysfs implement in the future can not be known.

The one possible way to remedy this is to implicity add nosuid and noexec as appropriate unfortunately that would break the ABI as it changes the interpretation of the bits in the userspace interface, and the day proc or sysfs changes and we honest to truly want to enable suid exectuables on proc or sysfs we would not be able to. :( So implicitly adding attributes is out.

As the current implementation of proc and sysfs are known I agree it does not make sense to backport the enforcement of nosuid and
noexec. So I have split the patch. See my for-testing branch
and shortly my for-next branch.

It only takes two or three line patches in the affected userspace executables, and a 5 minute test. So a warning printk does not actually make sense.

If the authors of lxc and libvirt-lxc have not taken the time to fix their code by the time this code lands in a stable release (in 2 months or so) no amount of other warnings are going to be enough.

Eric

#139 lore raw

Re: [CFT][PATCH 11/10] mnt: Avoid unnecessary regressions in fs_fully_visible

In reply to a message not in the archive
Quoted 11 lines · Eric W. Biederman

Not allowing programs to clear nosuid, nodev, and noexec on new mounts of sysfs or proc will cause lxc and libvirt-lxc to fail to start (a regression). There are no device nodes or executables on sysfs or proc today which means clearing these flags is harmless today.

Instead of failing the fresh mounts of sysfs and proc emit a warning when these flags are improprely cleared. We only reach this point because lxc and libvirt-lxc clear flags they mount flags had not intended to.

Quoted 4 lines

In a couple of kernel releases when lxc and libvirt-lxc have been fixed we can start failing fresh mounts proc and sysfs that clear nosuid, nodev and noexec. Userspace clearly means to enforce those attributes and historically they have avoided bugs.

At the very least, I think this should be folded in so that the ABI doesn't break in the middle of the series.

--Andy

#140 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

In reply to a message not in the archive
Quoted 18 lines · Eric W. Biederman
Quoted 4 lines · Andy Lutomirski

One option would be to break the nosuid, nodev, and noexec parts into their own patch and then avoid tagging that patch for -stable if at all possible. It would be nice to avoid another -stable ABI break if at all possible.

So I don't think we actually have anything that could be called an ABI break in the whole mess, but it is definitely a behavioral change that is a regression for lxc and libvirt-lxc that prevents them from starting.

nodev does not actually matter because of the implicit silliness that is being added right now.

We do want those programs fixed and after those programs are fixed we can safely begin failing mount when those attributes are being cleared in a fresh mount.

Quoted 5 lines

So it looks to me like the best thing to do is to print a warning whenever lxc or libvirt-lxc gets it wrong, which should ensure the authors are sufficiently pestered that in a kernel release or 3 we can begin enforcing those attributes. Especially as the discussion on the fix for those applications has already begun.

"pestering" never works, look at some of the SCSI drivers for examples of how a distro will just patch out the "warning this driver is using an old api and needs to be fixed" messages.

You can't break stuff like this, people will get upset :(

greg k-h

#141 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

Quoted 25 lines · Greg Kroah-Hartman
Quoted 18 lines · Eric W. Biederman
Quoted 4 lines · Andy Lutomirski

One option would be to break the nosuid, nodev, and noexec parts into their own patch and then avoid tagging that patch for -stable if at all possible. It would be nice to avoid another -stable ABI break if at all possible.

So I don't think we actually have anything that could be called an ABI break in the whole mess, but it is definitely a behavioral change that is a regression for lxc and libvirt-lxc that prevents them from starting.

nodev does not actually matter because of the implicit silliness that is being added right now.

We do want those programs fixed and after those programs are fixed we can safely begin failing mount when those attributes are being cleared in a fresh mount.

Quoted 5 lines

So it looks to me like the best thing to do is to print a warning whenever lxc or libvirt-lxc gets it wrong, which should ensure the authors are sufficiently pestered that in a kernel release or 3 we can begin enforcing those attributes. Especially as the discussion on the fix for those applications has already begun.

Quoted 5 lines

"pestering" never works, look at some of the SCSI drivers for examples of how a distro will just patch out the "warning this driver is using an old api and needs to be fixed" messages.

You can't break stuff like this, people will get upset :(

A) To the best of my knowledge there are two programs on the face of the planet where this matters. (lxc and libvirt-lxc)

B) The code in those two programs is buggy. That is the code in those two programs does not do what the authors intended. That is fixing those programs is something that should be done regardless of what I do in the kernel. I have already reached out to the developers of those programs. The pestering in the kernel is a form of reminder, not the primary source of communication.

C) These bugs really are security holes. Currently they do not appear exploitable (thank goodness) but they are security holes.

Since they are not currently exploitable it does make sense to give people a little time to get their act together.

The bugs are larger then the case that is being hit here, this is just where they are noticed.

D) Letting people know that there is a problem as part of a larger effort has actually worked for me. Distro's have stopped enabling the sysctl system call.

E) Given that I have not audited sysfs and proc closely in recent years I may actually be wrong. Those bugs may actually be exploitable. All it takes is chmod to be supported on one file that can be made executable. That bug has existed in the past and I don't doubt someone will overlook something and we will see the bug again in the future.

So it is my best judgment that I disable the code that stops containers from starting and just making it a warning (for now). Then in a release or so I start failing these operations instead of warning.

This is the most fair and reasonable I can see to be.

The only other choice I can see is to say I don't care it is a security issue I am breaking your sloopy insecure code.

Am I being too nice with these security bugs?

Eric

A message that is not in the archive (sent off-list or not yet received): [email protected]

#143 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

Quoted 68 lines · ebiederm-aS9lmoZGLiVWk0Htik3J/[email protected] (Eric W. Biederman) writes:
Quoted 25 lines · Greg Kroah-Hartman
Quoted 18 lines · Eric W. Biederman
Quoted 4 lines · Andy Lutomirski

One option would be to break the nosuid, nodev, and noexec parts into their own patch and then avoid tagging that patch for -stable if at all possible. It would be nice to avoid another -stable ABI break if at all possible.

So I don't think we actually have anything that could be called an ABI break in the whole mess, but it is definitely a behavioral change that is a regression for lxc and libvirt-lxc that prevents them from starting.

nodev does not actually matter because of the implicit silliness that is being added right now.

We do want those programs fixed and after those programs are fixed we can safely begin failing mount when those attributes are being cleared in a fresh mount.

Quoted 5 lines

So it looks to me like the best thing to do is to print a warning whenever lxc or libvirt-lxc gets it wrong, which should ensure the authors are sufficiently pestered that in a kernel release or 3 we can begin enforcing those attributes. Especially as the discussion on the fix for those applications has already begun.

Quoted 5 lines

"pestering" never works, look at some of the SCSI drivers for examples of how a distro will just patch out the "warning this driver is using an old api and needs to be fixed" messages.

You can't break stuff like this, people will get upset :(

A) To the best of my knowledge there are two programs on the face of the planet where this matters. (lxc and libvirt-lxc)

B) The code in those two programs is buggy. That is the code in those two programs does not do what the authors intended. That is fixing those programs is something that should be done regardless of what I do in the kernel. I have already reached out to the developers of those programs. The pestering in the kernel is a form of reminder, not the primary source of communication.

C) These bugs really are security holes. Currently they do not appear exploitable (thank goodness) but they are security holes.

Since they are not currently exploitable it does make sense to give people a little time to get their act together.

The bugs are larger then the case that is being hit here, this is just where they are noticed.

D) Letting people know that there is a problem as part of a larger effort has actually worked for me. Distro's have stopped enabling the sysctl system call.

E) Given that I have not audited sysfs and proc closely in recent years I may actually be wrong. Those bugs may actually be exploitable. All it takes is chmod to be supported on one file that can be made executable. That bug has existed in the past and I don't doubt someone will overlook something and we will see the bug again in the future.

So it is my best judgment that I disable the code that stops containers from starting and just making it a warning (for now). Then in a release or so I start failing these operations instead of warning.

Quoted 6 lines

This is the most fair and reasonable I can see to be.

The only other choice I can see is to say I don't care it is a security issue I am breaking your sloopy insecure code.

Am I being too nice with these security bugs?

Thinking about it a little more. There is a possibility that sometime in the future that someone will deliberately add a suid executable as a file in proc or sysfs and have a good reason for doing so.

Some sysadmin or sandbox builder with special requirements may then disable suid and exec on proc because in their sandbox (not linux in general) having access to that executable is a bad thing. At which we have an exploitable security issue if nosuid and noexec are not enforced.

Or in other words I am not smarter than the bad guys. This is a security issue. I can not ignore nosuid and noexec indefinitely. I have to make those cases fail at some point. At that point current unfixed versions of lxc and libvirt-lxc will break.

A warning is the nicest I can imagine being.

Eric

#144 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

In reply to a message not in the archive
Quoted 63 lines · Eric W. Biederman
Quoted 25 lines · Greg Kroah-Hartman
Quoted 18 lines · Eric W. Biederman
Quoted 4 lines · Andy Lutomirski

One option would be to break the nosuid, nodev, and noexec parts into their own patch and then avoid tagging that patch for -stable if at all possible. It would be nice to avoid another -stable ABI break if at all possible.

So I don't think we actually have anything that could be called an ABI break in the whole mess, but it is definitely a behavioral change that is a regression for lxc and libvirt-lxc that prevents them from starting.

nodev does not actually matter because of the implicit silliness that is being added right now.

We do want those programs fixed and after those programs are fixed we can safely begin failing mount when those attributes are being cleared in a fresh mount.

Quoted 5 lines

So it looks to me like the best thing to do is to print a warning whenever lxc or libvirt-lxc gets it wrong, which should ensure the authors are sufficiently pestered that in a kernel release or 3 we can begin enforcing those attributes. Especially as the discussion on the fix for those applications has already begun.

Quoted 5 lines

"pestering" never works, look at some of the SCSI drivers for examples of how a distro will just patch out the "warning this driver is using an old api and needs to be fixed" messages.

You can't break stuff like this, people will get upset :(

A) To the best of my knowledge there are two programs on the face of the planet where this matters. (lxc and libvirt-lxc)

B) The code in those two programs is buggy. That is the code in those two programs does not do what the authors intended. That is fixing those programs is something that should be done regardless of what I do in the kernel. I have already reached out to the developers of those programs. The pestering in the kernel is a form of reminder, not the primary source of communication.

C) These bugs really are security holes. Currently they do not appear exploitable (thank goodness) but they are security holes.

Since they are not currently exploitable it does make sense to give people a little time to get their act together.

The bugs are larger then the case that is being hit here, this is just where they are noticed.

D) Letting people know that there is a problem as part of a larger effort has actually worked for me. Distro's have stopped enabling the sysctl system call.

E) Given that I have not audited sysfs and proc closely in recent years I may actually be wrong. Those bugs may actually be exploitable. All it takes is chmod to be supported on one file that can be made executable. That bug has existed in the past and I don't doubt someone will overlook something and we will see the bug again in the future.

Quoted 6 lines

So it is my best judgment that I disable the code that stops containers from starting and just making it a warning (for now). Then in a release or so I start failing these operations instead of warning.

This is the most fair and reasonable I can see to be.

While I generally like & support the kernel standard that userspace must never be broken, as libvirt LXC maintainer I think what Eric proposes is acceptable from the libvirt POV.

We'll get the fix into libvirt LXC in this month's release and backport it to our stable branches. So as long as there are a few months/releases grace period between this being a kernel warning and it turning into a hard error, libvirt users will have the fix already, or at least have it easily available to them.

Regards,
Daniel

Signature · 4 lines
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|
#145 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

In reply to a message not in the archive
Quoted 63 lines · Eric W. Biederman
Quoted 25 lines · Greg Kroah-Hartman
Quoted 18 lines · Eric W. Biederman
Quoted 4 lines · Andy Lutomirski

One option would be to break the nosuid, nodev, and noexec parts into their own patch and then avoid tagging that patch for -stable if at all possible. It would be nice to avoid another -stable ABI break if at all possible.

So I don't think we actually have anything that could be called an ABI break in the whole mess, but it is definitely a behavioral change that is a regression for lxc and libvirt-lxc that prevents them from starting.

nodev does not actually matter because of the implicit silliness that is being added right now.

We do want those programs fixed and after those programs are fixed we can safely begin failing mount when those attributes are being cleared in a fresh mount.

Quoted 5 lines

So it looks to me like the best thing to do is to print a warning whenever lxc or libvirt-lxc gets it wrong, which should ensure the authors are sufficiently pestered that in a kernel release or 3 we can begin enforcing those attributes. Especially as the discussion on the fix for those applications has already begun.

Quoted 5 lines

"pestering" never works, look at some of the SCSI drivers for examples of how a distro will just patch out the "warning this driver is using an old api and needs to be fixed" messages.

You can't break stuff like this, people will get upset :(

A) To the best of my knowledge there are two programs on the face of the planet where this matters. (lxc and libvirt-lxc)

B) The code in those two programs is buggy. That is the code in those two programs does not do what the authors intended. That is fixing those programs is something that should be done regardless of what I do in the kernel. I have already reached out to the developers of those programs. The pestering in the kernel is a form of reminder, not the primary source of communication.

C) These bugs really are security holes. Currently they do not appear exploitable (thank goodness) but they are security holes.

Since they are not currently exploitable it does make sense to give people a little time to get their act together.

The bugs are larger then the case that is being hit here, this is just where they are noticed.

D) Letting people know that there is a problem as part of a larger effort has actually worked for me. Distro's have stopped enabling the sysctl system call.

E) Given that I have not audited sysfs and proc closely in recent years I may actually be wrong. Those bugs may actually be exploitable. All it takes is chmod to be supported on one file that can be made executable. That bug has existed in the past and I don't doubt someone will overlook something and we will see the bug again in the future.

Quoted 6 lines

So it is my best judgment that I disable the code that stops containers from starting and just making it a warning (for now). Then in a release or so I start failing these operations instead of warning.

This is the most fair and reasonable I can see to be.

While I generally like & support the kernel standard that userspace must never be broken, as libvirt LXC maintainer I think what Eric proposes is acceptable from the libvirt POV.

We'll get the fix into libvirt LXC in this month's release and backport it to our stable branches. So as long as there are a few months/releases grace period between this being a kernel warning and it turning into a hard error, libvirt users will have the fix already, or at least have it easily available to them.

Regards,
Daniel

Signature · 4 lines
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|

A message that is not in the archive (sent off-list or not yet received): [email protected]

#147 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

Quoted 25 lines · Greg Kroah-Hartman
Quoted 18 lines · Eric W. Biederman
Quoted 4 lines · Andy Lutomirski

One option would be to break the nosuid, nodev, and noexec parts into their own patch and then avoid tagging that patch for -stable if at all possible. It would be nice to avoid another -stable ABI break if at all possible.

So I don't think we actually have anything that could be called an ABI break in the whole mess, but it is definitely a behavioral change that is a regression for lxc and libvirt-lxc that prevents them from starting.

nodev does not actually matter because of the implicit silliness that is being added right now.

We do want those programs fixed and after those programs are fixed we can safely begin failing mount when those attributes are being cleared in a fresh mount.

Quoted 5 lines

So it looks to me like the best thing to do is to print a warning whenever lxc or libvirt-lxc gets it wrong, which should ensure the authors are sufficiently pestered that in a kernel release or 3 we can begin enforcing those attributes. Especially as the discussion on the fix for those applications has already begun.

Quoted 5 lines

"pestering" never works, look at some of the SCSI drivers for examples of how a distro will just patch out the "warning this driver is using an old api and needs to be fixed" messages.

You can't break stuff like this, people will get upset :(

A) To the best of my knowledge there are two programs on the face of the planet where this matters. (lxc and libvirt-lxc)

B) The code in those two programs is buggy. That is the code in those two programs does not do what the authors intended. That is fixing those programs is something that should be done regardless of what I do in the kernel. I have already reached out to the developers of those programs. The pestering in the kernel is a form of reminder, not the primary source of communication.

C) These bugs really are security holes. Currently they do not appear exploitable (thank goodness) but they are security holes.

Since they are not currently exploitable it does make sense to give people a little time to get their act together.

The bugs are larger then the case that is being hit here, this is just where they are noticed.

D) Letting people know that there is a problem as part of a larger effort has actually worked for me. Distro's have stopped enabling the sysctl system call.

E) Given that I have not audited sysfs and proc closely in recent years I may actually be wrong. Those bugs may actually be exploitable. All it takes is chmod to be supported on one file that can be made executable. That bug has existed in the past and I don't doubt someone will overlook something and we will see the bug again in the future.

So it is my best judgment that I disable the code that stops containers from starting and just making it a warning (for now). Then in a release or so I start failing these operations instead of warning.

This is the most fair and reasonable I can see to be.

The only other choice I can see is to say I don't care it is a security issue I am breaking your sloopy insecure code.

Am I being too nice with these security bugs?

Eric

A message that is not in the archive (sent off-list or not yet received): CALCETrVEA0Ug+3aj5rjupqZub-1tPLw+szzbs4kTyEyVvNs7qg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org

#149 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

Quoted 4 lines · Andy Lutomirski

One option would be to break the nosuid, nodev, and noexec parts into their own patch and then avoid tagging that patch for -stable if at all possible. It would be nice to avoid another -stable ABI break if at all possible.

So I don't think we actually have anything that could be called an ABI break in the whole mess, but it is definitely a behavioral change that is a regression for lxc and libvirt-lxc that prevents them from starting.

nodev does not actually matter because of the implicit silliness that is being added right now.

We do want those programs fixed and after those programs are fixed we can safely begin failing mount when those attributes are being cleared in a fresh mount.

So it looks to me like the best thing to do is to print a warning whenever lxc or libvirt-lxc gets it wrong, which should ensure the authors are sufficiently pestered that in a kernel release or 3 we can begin enforcing those attributes. Especially as the discussion on the fix for those applications has already begun.

And if folks would double check the patch I am going to post in a moment to ensure that lxc and libvirt-lxc continue to start I would appreciate it.

Eric

#150 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

In reply to a message not in the archive
Quoted 10 lines · Andy Lutomirski
Quoted 8 lines · Eric W. Biederman

Kenton Varda <[email protected]> writes:

We do need to enforce retaining the existing mount flags one way or another. Where this really matters is with MS_RDONLY. We don't want any old user to be able to mount /proc read-write when root mounted it read-only. There is a very real attack vector there. That attack almost works in docker container today and is avoided simply because docker mounts over a few files on proc.

Quoted 3 lines

You could drop the nosuid, noexec, and nodev changes and keep just the ro part. The ro part is probably not an ABI break in the sense of something that actually breaks real programs.

As a change simply removing the code from the existing patches that worries about nosuid, noexec, and the nodev flags is certainly doable. It is the best proposal I have heard so far.

I remain unconvinced about ignoring those flags:
- There are clearly people who think it matters (or else proc and sysfs would not have those flags specified).

- There have been times when it actually has mattered. Aka when files like /proc/self/env could be chmodded and used for privilege escalation.

- The code in lxc and libvirt-lxc so far has been clearly buggy.
* lxc only has problems with sysfs (in some configurations).
* libvirt-lxc only has problems on a bind mount remount of proc after remounting proc properly.

So I am leaning towards enforcing all of the mount flags including nosuid, noexec, and nodev. Then when the next subtle bug in proc or sysfs with respect to chmod shows up I will be able to sleep soundly at night because the mount flags of those filesystems allow a mitigation, and I did not sabatage the mitigation.

Plus contemplating code that just enforces a couple of mount flags but not all of the feels wrong.

I don't think it is actually a maintainable position to just enforce a couple of those flags. If nothing else I would expect someone to look at the code and to generate a bug fix to start enforcing the rest of the flags. Or perhaps it is in a few years time and something gets refactored and the enforcing starts happening by virtue of using a new common function that no-one realizes will be a problem.

Additionally if we don't enforce nosuid, noexec, and nodev people are going to ask questions, that will be hard to explain. When what is truly desirable is to say that sysfs and proc are a little odd but they don't allow anything that a bind mount won't.

I can be persuaded otherwise but right now I do think the kernel code needs to enforce nosuid, noexec, and nodev as it is a security issue (if only a defence in depth one), and a maintenance issue as I do not believe in the long term it is a maintanable or an explicable position.

Quoted 13 lines
Quoted 13 lines
Quoted 8 lines

Speaking as a user of the mount() interfaces, I really think it would be less confusing overall if mount() simply ignored the requested flags when the caller doesn't have a choice. That is, in cases where mount() currently fails with EPERM when not given, say, MS_NOSUID, it should instead just pretend the caller actually set MS_NOSUID and go ahead with a nosuid mount. Or put another way, the absence of MS_NOSUID should not be interpreted as "remove the nosuid bit" but rather "don't set the nosuid bit if not required".

I am conflicted. Implicits are nice but confusing. If we can do something reliable and robust and maintainable here that is truly worth the cost I am all for it.

Quoted 5 lines
Quoted 3 lines

If I mount proc read-write I likely want to be able to write to proc files, and I will be much happier if the mount fails than if a bazillion syscalls later something else fails when it tries to write to proc.

I agree. I don't like the implicit thing.

My memory returns of our last round of looking at this and for whatever it's warts the existing mount API for remounting filesystems needs to have the flags have exactly the same meaning as at mount time. There are existing userspace applications that depend on that behavior.

Implicits for only the locked mount flags is a little different but still ick.

Eric

#151 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

In reply to a message not in the archive
Quoted 40 lines · Kenton Varda
Quoted 39 lines · Andy Lutomirski
Quoted 36 lines · Eric W. Biederman
Quoted 11 lines · Serge Hallyn
Quoted 9 lines · Andy Lutomirski
Quoted 1 line · Eric W. Biederman

I had hoped to get some Tested-By's on that patch series.

Sorry, I've been totally swamped.

I suspect that Sandstorm is okay, but I haven't had a chance to test it for real. Sandstorm makes only limited use of proc and sysfs in containers, but I'll see if I can test it for real this weekend.

Quoted 5 lines

Testing this with unprivileged containers, I get

lxc-start: conf.c: lxc_mount_auto_mounts: 808 Operation not permitted
- error mounting sysfs on /usr/lib/x86_64-linux-gnu/lxc/sys/devices/virtual/net flags 0

Grr.. I was afraid this would break something. :(

Looking at my system I see that sysfs is currently mounted "nosuid,nodev,noexec"

Looking at the lxc-start code I don't see it as including any of those mount options. In practice for sysfs I think those options are meaningless (as there should be no devices and nothing executable in sysfs) but I can understand the past concerns with chmod on virtual filesystems that would incline people to use them, so I think the failure is reporting a legitimate security issue in the lxc userspace code where the the unprivileged code is currently attempting to give greater access to sysfs than was given by the original mount of sysfs.

As nosuid,nodev,noexec should not impair the operation of sysfs operation it looks like you can always specify those options and just make this concern go away.

Quoted 6 lines
Quoted 6 lines

Linus is pretty strict about not breaking the ABI, and this definitely counts as breaking the ABI. There's an exception for security issues, but is there really a security issue here? That is, do we lose anything important if we just drop the offending part of the patch set? As you've said, there shouldn't be sensitive device nodes, executables, or setuid files in proc or sysfs in the first place.

We do need to enforce retaining the existing mount flags one way or another. Where this really matters is with MS_RDONLY. We don't want any old user to be able to mount /proc read-write when root mounted it read-only. There is a very real attack vector there. That attack almost works in docker container today and is avoided simply because docker mounts over a few files on proc.

Which leads to the second side of the reason for these changes. I am
fixing a very small but long standing ABI break. That is in some small
ways I broke some sandboxes and when I realized they were broken I could not imagine think how to fix the code until now.

It is the goal that user namespaces don't introduce anything for people to worry about security wise more than simply the ability to execute more kernel code. So at least when the kernel implementation is correct developers of existing applications simply do not need care. Sadly we are not quite there yet.

Quoted 8 lines

Speaking as a user of the mount() interfaces, I really think it would be less confusing overall if mount() simply ignored the requested flags when the caller doesn't have a choice. That is, in cases where mount() currently fails with EPERM when not given, say, MS_NOSUID, it should instead just pretend the caller actually set MS_NOSUID and go ahead with a nosuid mount. Or put another way, the absence of MS_NOSUID should not be interpreted as "remove the nosuid bit" but rather "don't set the nosuid bit if not required".

I am conflicted. Implicits are nice but confusing. If we can do something reliable and robust and maintainable here that is truly worth the cost I am all for it.

If I mount proc read-write I likely want to be able to write to proc files, and I will be much happier if the mount fails than if a bazillion syscalls later something else fails when it tries to write to proc.

Quoted 13 lines

Consider:

- This approach will actually cause lxc to have the correct behavior, without any changes to lxc. I suspect that this generalizes: In the vast majority of cases, when users have failed to set MS_NOSUID, it's not because they are explicitly requesting that the flag be turned off, but rather that they didn't know it mattered.

- If a user actually *does* expect not passing MS_NOSUID to remove the nosuid bit, and they find instead that the nosuid bit is silently kept, I don't think they'll be confused: it's pretty obvious in context that this must be for security reasons.

Quoted 4 lines

- On the other hand, the current behavior *is* very confusing: mount() returns EPERM because of rules the caller probably doesn't know anything about. I've spent a fair amount of time frustrated by this sort of thing.

My sympathies. This all started with an oh crap we overlooked corner case X and it actually matters, and the fixes were quite likely a little bit hasty. The only case where this really shows up is remount insode of a user namespace of filesystems that were mounted outside of the user namespace is where this all actually matters. And mounting new instances of proc and sysfs wind up being weird instances of that nonsense.

But please someone test sandstorm with this patchset and tell me if it bites you. The impetus to find a way to avoid breaking slightly buggy userspace is higher if it is more than unprivileged lxc that is broken.

Eric

A message that is not in the archive (sent off-list or not yet received): [email protected]

#153 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

Quoted 33 lines · Eric W. Biederman
Quoted 11 lines · Serge Hallyn
Quoted 9 lines · Andy Lutomirski
Quoted 1 line · Eric W. Biederman

I had hoped to get some Tested-By's on that patch series.

Sorry, I've been totally swamped.

I suspect that Sandstorm is okay, but I haven't had a chance to test it for real. Sandstorm makes only limited use of proc and sysfs in containers, but I'll see if I can test it for real this weekend.

Quoted 5 lines

Testing this with unprivileged containers, I get

lxc-start: conf.c: lxc_mount_auto_mounts: 808 Operation not permitted
- error mounting sysfs on /usr/lib/x86_64-linux-gnu/lxc/sys/devices/virtual/net flags 0

Grr.. I was afraid this would break something. :(

Looking at my system I see that sysfs is currently mounted "nosuid,nodev,noexec"

Looking at the lxc-start code I don't see it as including any of those mount options. In practice for sysfs I think those options are meaningless (as there should be no devices and nothing executable in sysfs) but I can understand the past concerns with chmod on virtual filesystems that would incline people to use them, so I think the failure is reporting a legitimate security issue in the lxc userspace code where the the unprivileged code is currently attempting to give greater access to sysfs than was given by the original mount of sysfs.

Quoted 3 lines

As nosuid,nodev,noexec should not impair the operation of sysfs operation it looks like you can always specify those options and just make this concern go away.

Linus is pretty strict about not breaking the ABI, and this definitely counts as breaking the ABI. There's an exception for security issues, but is there really a security issue here? That is, do we lose anything important if we just drop the offending part of the patch set? As you've said, there shouldn't be sensitive device nodes, executables, or setuid files in proc or sysfs in the first place.

--Andy

#154 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

In reply to a message not in the archive
Quoted 44 lines · Eric W. Biederman
Quoted 11 lines · Serge Hallyn
Quoted 9 lines · Andy Lutomirski
Quoted 1 line · Eric W. Biederman

I had hoped to get some Tested-By's on that patch series.

Sorry, I've been totally swamped.

I suspect that Sandstorm is okay, but I haven't had a chance to test it for real. Sandstorm makes only limited use of proc and sysfs in containers, but I'll see if I can test it for real this weekend.

Quoted 5 lines

Testing this with unprivileged containers, I get

lxc-start: conf.c: lxc_mount_auto_mounts: 808 Operation not permitted
- error mounting sysfs on /usr/lib/x86_64-linux-gnu/lxc/sys/devices/virtual/net flags 0

Grr.. I was afraid this would break something. :(

Looking at my system I see that sysfs is currently mounted "nosuid,nodev,noexec"

Looking at the lxc-start code I don't see it as including any of those mount options. In practice for sysfs I think those options are meaningless (as there should be no devices and nothing executable in sysfs) but I can understand the past concerns with chmod on virtual filesystems that would incline people to use them, so I think the failure is reporting a legitimate security issue in the lxc userspace code where the the unprivileged code is currently attempting to give greater access to sysfs than was given by the original mount of sysfs.

As nosuid,nodev,noexec should not impair the operation of sysfs operation it looks like you can always specify those options and just make this concern go away.

Something like the untested patch below I expect.

src/lxc/conf.c +0 -0
index 9870455b3cae..d9ccd03afe68 100644

src/lxc/conf.c static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_ha · line 777

Quoted 10 lines
src/lxc/conf.c +2 -2
@@ -770,8 +770,8 @@ static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_ha
 		{ LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED, "%r/proc/sysrq-trigger",                             "%r/proc/sysrq-trigger",        NULL,       MS_BIND,                        NULL },
 		{ LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED, NULL,                                                "%r/proc/sysrq-trigger",        NULL,       MS_REMOUNT|MS_BIND|MS_RDONLY,   NULL },
 		{ LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_RW,    "proc",                                              "%r/proc",                      "proc",     MS_NODEV|MS_NOEXEC|MS_NOSUID,   NULL },
-		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_RW,     "sysfs",                                             "%r/sys",                       "sysfs",    0,                              NULL },
-		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_RO,     "sysfs",                                             "%r/sys",                       "sysfs",    MS_RDONLY,                      NULL },
+		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_RW,     "sysfs",                                             "%r/sys",                       "sysfs",    MS_NODEV|MS_NOEXEC|MS_NOSUID,   NULL },
+		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_RO,     "sysfs",                                             "%r/sys",                       "sysfs",    MS_NODEV|MS_NOEXEC|MS_NOSUID|MS_RDONLY, NULL },
 		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_MIXED,  "sysfs",                                             "%r/sys",                       "sysfs",    MS_NODEV|MS_NOEXEC|MS_NOSUID,   NULL },
 		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_MIXED,  "%r/sys",                                            "%r/sys",                       NULL,       MS_BIND,                        NULL },
 		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_MIXED,  NULL,                                                "%r/sys",                       NULL,       MS_REMOUNT|MS_BIND|MS_RDONLY,   NULL },

fwiw - the first one works, the second one does not due to an apparent inability to statvfs the origin.

Quoted 23 lines

Alternately you can read the flags off of the original mount of proc or sysfs.

src/lxc/conf.c +3 -1
index 9870455b3cae..50ea49973e80 100644
@@ -712,7 +712,9 @@ static unsigned long add_required_remount_flags(const char *s, const char *d,
        struct statvfs sb;
        unsigned long required_flags = 0;
 
-       if (!(flags & MS_REMOUNT))
+       if (!(flags & MS_REMOUNT) &&
+           (strcmp(s, "proc") != 0) &&
+           (strcmp(s, "sysfs") != 0))
                return flags;
 
        if (!s)

Eric
_______________________________________________
Containers mailing list Containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org
https://lists.linuxfoundation.org/mailman/listinfo/containers

maintainer
#155 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

In reply to Eric W. Biederman
Quoted 44 lines · Eric W. Biederman
Quoted 11 lines · Serge Hallyn
Quoted 9 lines · Andy Lutomirski
Quoted 1 line · Eric W. Biederman

I had hoped to get some Tested-By's on that patch series.

Sorry, I've been totally swamped.

I suspect that Sandstorm is okay, but I haven't had a chance to test it for real. Sandstorm makes only limited use of proc and sysfs in containers, but I'll see if I can test it for real this weekend.

Quoted 5 lines

Testing this with unprivileged containers, I get

lxc-start: conf.c: lxc_mount_auto_mounts: 808 Operation not permitted
- error mounting sysfs on /usr/lib/x86_64-linux-gnu/lxc/sys/devices/virtual/net flags 0

Grr.. I was afraid this would break something. :(

Looking at my system I see that sysfs is currently mounted "nosuid,nodev,noexec"

Looking at the lxc-start code I don't see it as including any of those mount options. In practice for sysfs I think those options are meaningless (as there should be no devices and nothing executable in sysfs) but I can understand the past concerns with chmod on virtual filesystems that would incline people to use them, so I think the failure is reporting a legitimate security issue in the lxc userspace code where the the unprivileged code is currently attempting to give greater access to sysfs than was given by the original mount of sysfs.

As nosuid,nodev,noexec should not impair the operation of sysfs operation it looks like you can always specify those options and just make this concern go away.

Something like the untested patch below I expect.

src/lxc/conf.c +0 -0
index 9870455b3cae..d9ccd03afe68 100644

src/lxc/conf.c static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_ha · line 777

Quoted 10 lines
src/lxc/conf.c +2 -2
@@ -770,8 +770,8 @@ static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_ha
 		{ LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED, "%r/proc/sysrq-trigger",                             "%r/proc/sysrq-trigger",        NULL,       MS_BIND,                        NULL },
 		{ LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED, NULL,                                                "%r/proc/sysrq-trigger",        NULL,       MS_REMOUNT|MS_BIND|MS_RDONLY,   NULL },
 		{ LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_RW,    "proc",                                              "%r/proc",                      "proc",     MS_NODEV|MS_NOEXEC|MS_NOSUID,   NULL },
-		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_RW,     "sysfs",                                             "%r/sys",                       "sysfs",    0,                              NULL },
-		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_RO,     "sysfs",                                             "%r/sys",                       "sysfs",    MS_RDONLY,                      NULL },
+		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_RW,     "sysfs",                                             "%r/sys",                       "sysfs",    MS_NODEV|MS_NOEXEC|MS_NOSUID,   NULL },
+		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_RO,     "sysfs",                                             "%r/sys",                       "sysfs",    MS_NODEV|MS_NOEXEC|MS_NOSUID|MS_RDONLY, NULL },
 		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_MIXED,  "sysfs",                                             "%r/sys",                       "sysfs",    MS_NODEV|MS_NOEXEC|MS_NOSUID,   NULL },
 		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_MIXED,  "%r/sys",                                            "%r/sys",                       NULL,       MS_BIND,                        NULL },
 		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_MIXED,  NULL,                                                "%r/sys",                       NULL,       MS_REMOUNT|MS_BIND|MS_RDONLY,   NULL },

fwiw - the first one works, the second one does not due to an apparent inability to statvfs the origin.

Quoted 23 lines

Alternately you can read the flags off of the original mount of proc or sysfs.

src/lxc/conf.c +3 -1
index 9870455b3cae..50ea49973e80 100644
@@ -712,7 +712,9 @@ static unsigned long add_required_remount_flags(const char *s, const char *d,
        struct statvfs sb;
        unsigned long required_flags = 0;
 
-       if (!(flags & MS_REMOUNT))
+       if (!(flags & MS_REMOUNT) &&
+           (strcmp(s, "proc") != 0) &&
+           (strcmp(s, "sysfs") != 0))
                return flags;
 
        if (!s)

Eric
_______________________________________________
Containers mailing list
[email protected]
https://lists.linuxfoundation.org/mailman/listinfo/containers

A message that is not in the archive (sent off-list or not yet received): [email protected]

#157 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

Quoted 50 lines · Serge E. Hallyn
Quoted 49 lines · Eric W. Biederman
Quoted 11 lines · Serge Hallyn
Quoted 9 lines · Andy Lutomirski
Quoted 1 line · Eric W. Biederman

I had hoped to get some Tested-By's on that patch series.

Sorry, I've been totally swamped.

I suspect that Sandstorm is okay, but I haven't had a chance to test it for real. Sandstorm makes only limited use of proc and sysfs in containers, but I'll see if I can test it for real this weekend.

Quoted 5 lines

Testing this with unprivileged containers, I get

lxc-start: conf.c: lxc_mount_auto_mounts: 808 Operation not permitted
- error mounting sysfs on /usr/lib/x86_64-linux-gnu/lxc/sys/devices/virtual/net flags 0

Grr.. I was afraid this would break something. :(

Looking at my system I see that sysfs is currently mounted "nosuid,nodev,noexec"

Looking at the lxc-start code I don't see it as including any of those mount options. In practice for sysfs I think those options are meaningless (as there should be no devices and nothing executable in sysfs) but I can understand the past concerns with chmod on virtual filesystems that would incline people to use them, so I think the failure is reporting a legitimate security issue in the lxc userspace code where the the unprivileged code is currently attempting to give greater access to sysfs than was given by the original mount of sysfs.

As nosuid,nodev,noexec should not impair the operation of sysfs operation it looks like you can always specify those options and just make this concern go away.

Something like the untested patch below I expect.

src/lxc/conf.c +0 -2
index 9870455b3cae..d9ccd03afe68 100644
@@ -770,8 +770,8 @@ static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_ha
 		{ LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED, "%r/proc/sysrq-trigger",                             "%r/proc/sysrq-trigger",        NULL,       MS_BIND,                        NULL },
 		{ LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED, NULL,                                                "%r/proc/sysrq-trigger",        NULL,       MS_REMOUNT|MS_BIND|MS_RDONLY,   NULL },
 		{ LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_RW,    "proc",                                              "%r/proc",                      "proc",     MS_NODEV|MS_NOEXEC|MS_NOSUID,   NULL },
-		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_RW,     "sysfs",                                             "%r/sys",                       "sysfs",    0,                              NULL },
-		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_RO,     "sysfs",                                             "%r/sys",                       "sysfs",    MS_RDONLY,                      NULL },
Quoted 8 lines

src/lxc/conf.c static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_ha · line 777

Quoted 5 lines
src/lxc/conf.c +2 -0
+		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_RW,     "sysfs",                                             "%r/sys",                       "sysfs",    MS_NODEV|MS_NOEXEC|MS_NOSUID,   NULL },
+		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_RO,     "sysfs",                                             "%r/sys",                       "sysfs",    MS_NODEV|MS_NOEXEC|MS_NOSUID|MS_RDONLY, NULL },
 		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_MIXED,  "sysfs",                                             "%r/sys",                       "sysfs",    MS_NODEV|MS_NOEXEC|MS_NOSUID,   NULL },
 		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_MIXED,  "%r/sys",                                            "%r/sys",                       NULL,       MS_BIND,                        NULL },
 		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_MIXED,  NULL,                                                "%r/sys",                       NULL,       MS_REMOUNT|MS_BIND|MS_RDONLY,   NULL },

fwiw - the first one works, the second one does not due to an apparent inability to statvfs the origin.

Good to hear. That confirms there are no other gotchas waiting in the wings.

Apparently my second suggested patch is buggy due to an invalid source string. The source would need to be %r/proc or %r/sysfs to use statvfs productively.

Quoted 23 lines
Quoted 23 lines

Alternately you can read the flags off of the original mount of proc or sysfs.

src/lxc/conf.c +3 -1
index 9870455b3cae..50ea49973e80 100644
@@ -712,7 +712,9 @@ static unsigned long add_required_remount_flags(const char *s, const char *d,
        struct statvfs sb;
        unsigned long required_flags = 0;
 
-       if (!(flags & MS_REMOUNT))
+       if (!(flags & MS_REMOUNT) &&
+           (strcmp(s, "proc") != 0) &&
+           (strcmp(s, "sysfs") != 0))
                return flags;
 
        if (!s)

Eric
_______________________________________________
Containers mailing list Containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org
https://lists.linuxfoundation.org/mailman/listinfo/containers

maintainer
#158 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

Quoted 61 lines · Eric W. Biederman
Quoted 50 lines · Serge E. Hallyn
Quoted 49 lines · Eric W. Biederman
Quoted 11 lines · Serge Hallyn
Quoted 9 lines · Andy Lutomirski
Quoted 1 line · Eric W. Biederman

I had hoped to get some Tested-By's on that patch series.

Sorry, I've been totally swamped.

I suspect that Sandstorm is okay, but I haven't had a chance to test it for real. Sandstorm makes only limited use of proc and sysfs in containers, but I'll see if I can test it for real this weekend.

Quoted 5 lines

Testing this with unprivileged containers, I get

lxc-start: conf.c: lxc_mount_auto_mounts: 808 Operation not permitted
- error mounting sysfs on /usr/lib/x86_64-linux-gnu/lxc/sys/devices/virtual/net flags 0

Grr.. I was afraid this would break something. :(

Looking at my system I see that sysfs is currently mounted "nosuid,nodev,noexec"

Looking at the lxc-start code I don't see it as including any of those mount options. In practice for sysfs I think those options are meaningless (as there should be no devices and nothing executable in sysfs) but I can understand the past concerns with chmod on virtual filesystems that would incline people to use them, so I think the failure is reporting a legitimate security issue in the lxc userspace code where the the unprivileged code is currently attempting to give greater access to sysfs than was given by the original mount of sysfs.

As nosuid,nodev,noexec should not impair the operation of sysfs operation it looks like you can always specify those options and just make this concern go away.

Something like the untested patch below I expect.

src/lxc/conf.c +0 -2
index 9870455b3cae..d9ccd03afe68 100644
@@ -770,8 +770,8 @@ static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_ha
 		{ LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED, "%r/proc/sysrq-trigger",                             "%r/proc/sysrq-trigger",        NULL,       MS_BIND,                        NULL },
 		{ LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED, NULL,                                                "%r/proc/sysrq-trigger",        NULL,       MS_REMOUNT|MS_BIND|MS_RDONLY,   NULL },
 		{ LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_RW,    "proc",                                              "%r/proc",                      "proc",     MS_NODEV|MS_NOEXEC|MS_NOSUID,   NULL },
-		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_RW,     "sysfs",                                             "%r/sys",                       "sysfs",    0,                              NULL },
-		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_RO,     "sysfs",                                             "%r/sys",                       "sysfs",    MS_RDONLY,                      NULL },
Quoted 8 lines

src/lxc/conf.c static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_ha · line 777

Quoted 5 lines
src/lxc/conf.c +2 -0
+		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_RW,     "sysfs",                                             "%r/sys",                       "sysfs",    MS_NODEV|MS_NOEXEC|MS_NOSUID,   NULL },
+		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_RO,     "sysfs",                                             "%r/sys",                       "sysfs",    MS_NODEV|MS_NOEXEC|MS_NOSUID|MS_RDONLY, NULL },
 		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_MIXED,  "sysfs",                                             "%r/sys",                       "sysfs",    MS_NODEV|MS_NOEXEC|MS_NOSUID,   NULL },
 		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_MIXED,  "%r/sys",                                            "%r/sys",                       NULL,       MS_BIND,                        NULL },
 		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_MIXED,  NULL,                                                "%r/sys",                       NULL,       MS_REMOUNT|MS_BIND|MS_RDONLY,   NULL },

fwiw - the first one works, the second one does not due to an apparent inability to statvfs the origin.

Quoted 6 lines

Good to hear. That confirms there are no other gotchas waiting in the wings.

Apparently my second suggested patch is buggy due to an invalid source string. The source would need to be %r/proc or %r/sysfs to use statvfs productively.

Right, in these cases they're only passing in "sysfs". The first way is more explicit anyway (though may not help some people who have a "lxc.mount.entry = sysfs sys sysfs ro 0 0" line in their configuration instead, so maybe we'll have to go with the second after all, d'oh. I'll have to look into it next week)

A message that is not in the archive (sent off-list or not yet received): [email protected]

#160 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

Quoted 61 lines · Eric W. Biederman
Quoted 50 lines · Serge E. Hallyn
Quoted 49 lines · Eric W. Biederman
Quoted 11 lines · Serge Hallyn
Quoted 9 lines · Andy Lutomirski
Quoted 1 line · Eric W. Biederman

I had hoped to get some Tested-By's on that patch series.

Sorry, I've been totally swamped.

I suspect that Sandstorm is okay, but I haven't had a chance to test it for real. Sandstorm makes only limited use of proc and sysfs in containers, but I'll see if I can test it for real this weekend.

Quoted 5 lines

Testing this with unprivileged containers, I get

lxc-start: conf.c: lxc_mount_auto_mounts: 808 Operation not permitted
- error mounting sysfs on /usr/lib/x86_64-linux-gnu/lxc/sys/devices/virtual/net flags 0

Grr.. I was afraid this would break something. :(

Looking at my system I see that sysfs is currently mounted "nosuid,nodev,noexec"

Looking at the lxc-start code I don't see it as including any of those mount options. In practice for sysfs I think those options are meaningless (as there should be no devices and nothing executable in sysfs) but I can understand the past concerns with chmod on virtual filesystems that would incline people to use them, so I think the failure is reporting a legitimate security issue in the lxc userspace code where the the unprivileged code is currently attempting to give greater access to sysfs than was given by the original mount of sysfs.

As nosuid,nodev,noexec should not impair the operation of sysfs operation it looks like you can always specify those options and just make this concern go away.

Something like the untested patch below I expect.

src/lxc/conf.c +0 -2
index 9870455b3cae..d9ccd03afe68 100644
@@ -770,8 +770,8 @@ static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_ha
 		{ LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED, "%r/proc/sysrq-trigger",                             "%r/proc/sysrq-trigger",        NULL,       MS_BIND,                        NULL },
 		{ LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED, NULL,                                                "%r/proc/sysrq-trigger",        NULL,       MS_REMOUNT|MS_BIND|MS_RDONLY,   NULL },
 		{ LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_RW,    "proc",                                              "%r/proc",                      "proc",     MS_NODEV|MS_NOEXEC|MS_NOSUID,   NULL },
-		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_RW,     "sysfs",                                             "%r/sys",                       "sysfs",    0,                              NULL },
-		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_RO,     "sysfs",                                             "%r/sys",                       "sysfs",    MS_RDONLY,                      NULL },
Quoted 8 lines

src/lxc/conf.c static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_ha · line 777

Quoted 5 lines
src/lxc/conf.c +2 -0
+		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_RW,     "sysfs",                                             "%r/sys",                       "sysfs",    MS_NODEV|MS_NOEXEC|MS_NOSUID,   NULL },
+		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_RO,     "sysfs",                                             "%r/sys",                       "sysfs",    MS_NODEV|MS_NOEXEC|MS_NOSUID|MS_RDONLY, NULL },
 		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_MIXED,  "sysfs",                                             "%r/sys",                       "sysfs",    MS_NODEV|MS_NOEXEC|MS_NOSUID,   NULL },
 		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_MIXED,  "%r/sys",                                            "%r/sys",                       NULL,       MS_BIND,                        NULL },
 		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_MIXED,  NULL,                                                "%r/sys",                       NULL,       MS_REMOUNT|MS_BIND|MS_RDONLY,   NULL },

fwiw - the first one works, the second one does not due to an apparent inability to statvfs the origin.

Quoted 6 lines

Good to hear. That confirms there are no other gotchas waiting in the wings.

Apparently my second suggested patch is buggy due to an invalid source string. The source would need to be %r/proc or %r/sysfs to use statvfs productively.

Right, in these cases they're only passing in "sysfs". The first way is more explicit anyway (though may not help some people who have a "lxc.mount.entry = sysfs sys sysfs ro 0 0" line in their configuration instead, so maybe we'll have to go with the second after all, d'oh. I'll have to look into it next week)

#161 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

In reply to a message not in the archive
Quoted 50 lines · Serge E. Hallyn
Quoted 49 lines · Eric W. Biederman
Quoted 11 lines · Serge Hallyn
Quoted 9 lines · Andy Lutomirski
Quoted 1 line · Eric W. Biederman

I had hoped to get some Tested-By's on that patch series.

Sorry, I've been totally swamped.

I suspect that Sandstorm is okay, but I haven't had a chance to test it for real. Sandstorm makes only limited use of proc and sysfs in containers, but I'll see if I can test it for real this weekend.

Quoted 5 lines

Testing this with unprivileged containers, I get

lxc-start: conf.c: lxc_mount_auto_mounts: 808 Operation not permitted
- error mounting sysfs on /usr/lib/x86_64-linux-gnu/lxc/sys/devices/virtual/net flags 0

Grr.. I was afraid this would break something. :(

Looking at my system I see that sysfs is currently mounted "nosuid,nodev,noexec"

Looking at the lxc-start code I don't see it as including any of those mount options. In practice for sysfs I think those options are meaningless (as there should be no devices and nothing executable in sysfs) but I can understand the past concerns with chmod on virtual filesystems that would incline people to use them, so I think the failure is reporting a legitimate security issue in the lxc userspace code where the the unprivileged code is currently attempting to give greater access to sysfs than was given by the original mount of sysfs.

As nosuid,nodev,noexec should not impair the operation of sysfs operation it looks like you can always specify those options and just make this concern go away.

Something like the untested patch below I expect.

src/lxc/conf.c +0 -2
index 9870455b3cae..d9ccd03afe68 100644
@@ -770,8 +770,8 @@ static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_ha
 		{ LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED, "%r/proc/sysrq-trigger",                             "%r/proc/sysrq-trigger",        NULL,       MS_BIND,                        NULL },
 		{ LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED, NULL,                                                "%r/proc/sysrq-trigger",        NULL,       MS_REMOUNT|MS_BIND|MS_RDONLY,   NULL },
 		{ LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_RW,    "proc",                                              "%r/proc",                      "proc",     MS_NODEV|MS_NOEXEC|MS_NOSUID,   NULL },
-		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_RW,     "sysfs",                                             "%r/sys",                       "sysfs",    0,                              NULL },
-		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_RO,     "sysfs",                                             "%r/sys",                       "sysfs",    MS_RDONLY,                      NULL },
Quoted 8 lines

src/lxc/conf.c static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_ha · line 777

Quoted 5 lines
src/lxc/conf.c +2 -0
+		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_RW,     "sysfs",                                             "%r/sys",                       "sysfs",    MS_NODEV|MS_NOEXEC|MS_NOSUID,   NULL },
+		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_RO,     "sysfs",                                             "%r/sys",                       "sysfs",    MS_NODEV|MS_NOEXEC|MS_NOSUID|MS_RDONLY, NULL },
 		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_MIXED,  "sysfs",                                             "%r/sys",                       "sysfs",    MS_NODEV|MS_NOEXEC|MS_NOSUID,   NULL },
 		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_MIXED,  "%r/sys",                                            "%r/sys",                       NULL,       MS_BIND,                        NULL },
 		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_MIXED,  NULL,                                                "%r/sys",                       NULL,       MS_REMOUNT|MS_BIND|MS_RDONLY,   NULL },

fwiw - the first one works, the second one does not due to an apparent inability to statvfs the origin.

Good to hear. That confirms there are no other gotchas waiting in the wings.

Apparently my second suggested patch is buggy due to an invalid source string. The source would need to be %r/proc or %r/sysfs to use statvfs productively.

Quoted 23 lines
Quoted 23 lines

Alternately you can read the flags off of the original mount of proc or sysfs.

src/lxc/conf.c +3 -1
index 9870455b3cae..50ea49973e80 100644
@@ -712,7 +712,9 @@ static unsigned long add_required_remount_flags(const char *s, const char *d,
        struct statvfs sb;
        unsigned long required_flags = 0;
 
-       if (!(flags & MS_REMOUNT))
+       if (!(flags & MS_REMOUNT) &&
+           (strcmp(s, "proc") != 0) &&
+           (strcmp(s, "sysfs") != 0))
                return flags;
 
        if (!s)

Eric
_______________________________________________
Containers mailing list Containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org
https://lists.linuxfoundation.org/mailman/listinfo/containers

#162 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

In reply to Serge Hallyn
Quoted 11 lines · Serge Hallyn
Quoted 9 lines · Andy Lutomirski
Quoted 1 line · Eric W. Biederman

I had hoped to get some Tested-By's on that patch series.

Sorry, I've been totally swamped.

I suspect that Sandstorm is okay, but I haven't had a chance to test it for real. Sandstorm makes only limited use of proc and sysfs in containers, but I'll see if I can test it for real this weekend.

Quoted 5 lines

Testing this with unprivileged containers, I get

lxc-start: conf.c: lxc_mount_auto_mounts: 808 Operation not permitted
- error mounting sysfs on /usr/lib/x86_64-linux-gnu/lxc/sys/devices/virtual/net flags 0

Grr.. I was afraid this would break something. :(

Looking at my system I see that sysfs is currently mounted "nosuid,nodev,noexec"

Looking at the lxc-start code I don't see it as including any of those mount options. In practice for sysfs I think those options are meaningless (as there should be no devices and nothing executable in sysfs) but I can understand the past concerns with chmod on virtual filesystems that would incline people to use them, so I think the failure is reporting a legitimate security issue in the lxc userspace code where the the unprivileged code is currently attempting to give greater access to sysfs than was given by the original mount of sysfs.

As nosuid,nodev,noexec should not impair the operation of sysfs operation it looks like you can always specify those options and just make this concern go away.

Something like the untested patch below I expect.

src/lxc/conf.c +2 -2
index 9870455b3cae..d9ccd03afe68 100644
@@ -770,8 +770,8 @@ static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_ha
 		{ LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED, "%r/proc/sysrq-trigger",                             "%r/proc/sysrq-trigger",        NULL,       MS_BIND,                        NULL },
 		{ LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED, NULL,                                                "%r/proc/sysrq-trigger",        NULL,       MS_REMOUNT|MS_BIND|MS_RDONLY,   NULL },
 		{ LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_RW,    "proc",                                              "%r/proc",                      "proc",     MS_NODEV|MS_NOEXEC|MS_NOSUID,   NULL },
-		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_RW,     "sysfs",                                             "%r/sys",                       "sysfs",    0,                              NULL },
-		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_RO,     "sysfs",                                             "%r/sys",                       "sysfs",    MS_RDONLY,                      NULL },
+		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_RW,     "sysfs",                                             "%r/sys",                       "sysfs",    MS_NODEV|MS_NOEXEC|MS_NOSUID,   NULL },
+		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_RO,     "sysfs",                                             "%r/sys",                       "sysfs",    MS_NODEV|MS_NOEXEC|MS_NOSUID|MS_RDONLY, NULL },
 		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_MIXED,  "sysfs",                                             "%r/sys",                       "sysfs",    MS_NODEV|MS_NOEXEC|MS_NOSUID,   NULL },
 		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_MIXED,  "%r/sys",                                            "%r/sys",                       NULL,       MS_BIND,                        NULL },
 		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_MIXED,  NULL,                                                "%r/sys",                       NULL,       MS_REMOUNT|MS_BIND|MS_RDONLY,   NULL },

Alternately you can read the flags off of the original mount of proc or sysfs.

src/lxc/conf.c +3 -1
index 9870455b3cae..50ea49973e80 100644
@@ -712,7 +712,9 @@ static unsigned long add_required_remount_flags(const char *s, const char *d,
        struct statvfs sb;
        unsigned long required_flags = 0;
 
-       if (!(flags & MS_REMOUNT))
+       if (!(flags & MS_REMOUNT) &&
+           (strcmp(s, "proc") != 0) &&
+           (strcmp(s, "sysfs") != 0))
                return flags;
 
        if (!s)

Eric

#163 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

In reply to Serge Hallyn

Am 28.05.2015 um 16:08 schrieb Serge Hallyn:

Quoted 7 lines · Andy Lutomirski
Quoted 6 lines
Quoted 1 line · Eric W. Biederman

I had hoped to get some Tested-By's on that patch series.

Sorry, I've been totally swamped.

Quoted 8 lines
Quoted 3 lines

I suspect that Sandstorm is okay, but I haven't had a chance to test it for real. Sandstorm makes only limited use of proc and sysfs in containers, but I'll see if I can test it for real this weekend.

Testing this with unprivileged containers, I get

lxc-start: conf.c: lxc_mount_auto_mounts: 808 Operation not permitted - error mounting sysfs on /usr/lib/x86_64-linux-gnu/lxc/sys/devices/virtual/net flags 0

FWIW, it breaks also libvirt-lxc:
Error: internal error: guest failed to start: Failed to re-mount /proc/sys on /proc/sys flags=1021: Operation not permitted

Thanks,
//richard

A message that is not in the archive (sent off-list or not yet received): 55676E32.3050006-/[email protected]

#165 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

Quoted 12 lines · Richard Weinberger

Am 28.05.2015 um 16:08 schrieb Serge Hallyn:

Quoted 11 lines · Andy Lutomirski
Quoted 9 lines
Quoted 1 line · Eric W. Biederman

I had hoped to get some Tested-By's on that patch series.

Sorry, I've been totally swamped.

I suspect that Sandstorm is okay, but I haven't had a chance to test it for real. Sandstorm makes only limited use of proc and sysfs in containers, but I'll see if I can test it for real this weekend.

Quoted 7 lines
Quoted 4 lines

Testing this with unprivileged containers, I get

lxc-start: conf.c: lxc_mount_auto_mounts: 808 Operation not permitted - error mounting sysfs on /usr/lib/x86_64-linux-gnu/lxc/sys/devices/virtual/net flags 0

FWIW, it breaks also libvirt-lxc:
Error: internal error: guest failed to start: Failed to re-mount /proc/sys on /proc/sys flags=1021: Operation not permitted

Interesting. I had not anticipated a failure there? And it is failing in remount? Oh that is interesting.

That implies that there is some flag of the original mount of /proc that the remount of /proc/sys is clearing, and that previously

The flags specified are current rdonly,remount,bind so I expect there are some other flags on proc that libvirt-lxc is clearing by accident and we did not fail before because the kernel was not enforcing things.

What are the mount flags in a working libvirt-lxc?

Eric

#166 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

Am 28.05.2015 um 21:57 schrieb Eric W. Biederman:

Quoted 6 lines
Quoted 2 lines

FWIW, it breaks also libvirt-lxc:
Error: internal error: guest failed to start: Failed to re-mount /proc/sys on /proc/sys flags=1021: Operation not permitted

Interesting. I had not anticipated a failure there? And it is failing in remount? Oh that is interesting.

Quoted 6 lines

That implies that there is some flag of the original mount of /proc that the remount of /proc/sys is clearing, and that previously

The flags specified are current rdonly,remount,bind so I expect there are some other flags on proc that libvirt-lxc is clearing by accident and we did not fail before because the kernel was not enforcing things.

Please see:
http://libvirt.org/git/?p=libvirt.git;a=blob;f=src/lxc/lxc_container.c;h=9a9ae5c2aaf0f90ff472f24fda43c077b44998c7;hb=HEAD#l933
lxcContainerMountBasicFS()

and:
http://libvirt.org/git/?p=libvirt.git;a=blob;f=src/lxc/lxc_container.c;h=9a9ae5c2aaf0f90ff472f24fda43c077b44998c7;hb=HEAD#l850
lxcBasicMounts

Quoted 1 line

What are the mount flags in a working libvirt-lxc?

See:
test1:~ # cat /proc/self/mountinfo
147 100 0:30 /srv/container/test1/rootfs / rw,relatime - btrfs /dev/sda2 rw,space_cache
149 147 0:56 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw
150 149 0:56 /sys /proc/sys ro,nodev,relatime - proc proc rw
151 150 0:3 /sys/net/ipv4 /proc/sys/net/ipv4 rw,nosuid,nodev,noexec,relatime - proc proc rw
152 150 0:3 /sys/net/ipv6 /proc/sys/net/ipv6 rw,nosuid,nodev,noexec,relatime - proc proc rw
153 147 0:57 / /sys ro,nodev,relatime - sysfs sysfs rw
154 149 0:53 /meminfo /proc/meminfo rw,nosuid,nodev,relatime - fuse libvirt rw,user_id=0,group_id=0,allow_other
155 153 0:58 / /sys/fs/cgroup rw,nosuid,nodev,noexec,relatime - tmpfs tmpfs rw,size=64k,mode=755,uid=10000,gid=10000
156 155 0:22 /machine.slice/machine-lxc\134x2dtest1.scope /sys/fs/cgroup/cpu,cpuacct rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,cpu,cpuacct 157 155 0:21 /machine.slice/machine-lxc\134x2dtest1.scope /sys/fs/cgroup/cpuset rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,cpuset 158 155 0:23 /machine.slice/machine-lxc\134x2dtest1.scope /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,memory 159 155 0:24 /machine.slice/machine-lxc\134x2dtest1.scope /sys/fs/cgroup/devices rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,devices 160 155 0:25 /machine.slice/machine-lxc\134x2dtest1.scope /sys/fs/cgroup/freezer rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,freezer 161 155 0:27 /machine.slice/machine-lxc\134x2dtest1.scope /sys/fs/cgroup/blkio rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,blkio 162 155 0:26 /machine.slice/machine-lxc\134x2dtest1.scope /sys/fs/cgroup/net_cls,net_prio rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,net_cls,net_prio 163 155 0:28 /machine.slice/machine-lxc\134x2dtest1.scope /sys/fs/cgroup/perf_event rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,perf_event 164 155 0:19 /machine.slice/machine-lxc\134x2dtest1.scope /sys/fs/cgroup/systemd rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd
165 147 0:52 / /dev rw,nosuid,relatime - tmpfs devfs rw,size=64k,mode=755
166 165 0:51 / /dev/pts rw,nosuid,relatime - devpts devpts rw,gid=10005,mode=620,ptmxmode=666
167 165 0:51 /ptmx /dev/ptmx rw,nosuid,relatime - devpts devpts rw,gid=10005,mode=620,ptmxmode=666
101 165 0:55 / /dev/shm rw,nosuid,nodev - tmpfs tmpfs rw,uid=10000,gid=10000
102 147 0:59 / /run rw,nosuid,nodev - tmpfs tmpfs rw,mode=755,uid=10000,gid=10000
103 165 0:54 / /dev/mqueue rw,nodev,relatime - mqueue mqueue rw
104 147 0:59 / /var/run rw,nosuid,nodev - tmpfs tmpfs rw,mode=755,uid=10000,gid=10000
105 147 0:59 /lock /var/lock rw,nosuid,nodev - tmpfs tmpfs rw,mode=755,uid=10000,gid=10000

If you need more info, please let me know. :-)

Thanks,
//richard

A message that is not in the archive (sent off-list or not yet received): 55677AEF.1090809-/[email protected]

#168 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

Quoted 22 lines · Richard Weinberger

Am 28.05.2015 um 21:57 schrieb Eric W. Biederman:

Quoted 6 lines
Quoted 2 lines

FWIW, it breaks also libvirt-lxc:
Error: internal error: guest failed to start: Failed to re-mount /proc/sys on /proc/sys flags=1021: Operation not permitted

Interesting. I had not anticipated a failure there? And it is failing in remount? Oh that is interesting.

Quoted 6 lines

That implies that there is some flag of the original mount of /proc that the remount of /proc/sys is clearing, and that previously

The flags specified are current rdonly,remount,bind so I expect there are some other flags on proc that libvirt-lxc is clearing by accident and we did not fail before because the kernel was not enforcing things.

Please see:
http://libvirt.org/git/?p=libvirt.git;a=blob;f=src/lxc/lxc_container.c;h=9a9ae5c2aaf0f90ff472f24fda43c077b44998c7;hb=HEAD#l933
lxcContainerMountBasicFS()

and:
http://libvirt.org/git/?p=libvirt.git;a=blob;f=src/lxc/lxc_container.c;h=9a9ae5c2aaf0f90ff472f24fda43c077b44998c7;hb=HEAD#l850
lxcBasicMounts

Quoted 8 lines
Quoted 1 line

What are the mount flags in a working libvirt-lxc?

See:
test1:~ # cat /proc/self/mountinfo
149 147 0:56 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw 150 149 0:56 /sys /proc/sys ro,nodev,relatime - proc proc rw

If you need more info, please let me know. :-)

Oh interesting I had not realized libvirt-lxc had grown an unprivileged mode using user namespaces.

This does appear to be a classic remount bug, where you are not preserving the permissions. It appears the fact that the code failed to enforce locked permissions on the fresh mount of proc was hiding this bug until now.

I expect what you actually want is the code below:

src/lxc/lxc_container.c +1 -1
index 9a9ae5c2aaf0..f008a7484bfe 100644
@@ -850,7 +850,7 @@ typedef struct {
 
 static const virLXCBasicMountInfo lxcBasicMounts[] = {
     { "proc", "/proc", "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, false, false, false },
-    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, false, false, false },
+    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },
     { "/.oldroot/proc/sys/net/ipv4", "/proc/sys/net/ipv4", NULL, MS_BIND, false, false, true },
     { "/.oldroot/proc/sys/net/ipv6", "/proc/sys/net/ipv6", NULL, MS_BIND, false, false, true },
     { "sysfs", "/sys", "sysfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },

Or possibly just:

src/lxc/lxc_container.c +1 -1
index 9a9ae5c2aaf0..a60ccbd12bfc 100644
@@ -850,7 +850,7 @@ typedef struct {
 
 static const virLXCBasicMountInfo lxcBasicMounts[] = {
     { "proc", "/proc", "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, false, false, false },
-    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, false, false, false },
+    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, true, false, false },
     { "/.oldroot/proc/sys/net/ipv4", "/proc/sys/net/ipv4", NULL, MS_BIND, false, false, true },
     { "/.oldroot/proc/sys/net/ipv6", "/proc/sys/net/ipv6", NULL, MS_BIND, false, false, true },
     { "sysfs", "/sys", "sysfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },

As the there is little point in making /proc/sys read-only in a user-namespace, as the permission checks are uid based and no-one should have the global uid 0 in your container. Making mounting /proc/sys read-only rather pointless.

Eric

A message that is not in the archive (sent off-list or not yet received): [email protected]

#170 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

Am 28.05.2015 um 23:32 schrieb Eric W. Biederman:

Quoted 31 lines
Quoted 28 lines · Richard Weinberger

Am 28.05.2015 um 21:57 schrieb Eric W. Biederman:

Quoted 6 lines
Quoted 2 lines

FWIW, it breaks also libvirt-lxc:
Error: internal error: guest failed to start: Failed to re-mount /proc/sys on /proc/sys flags=1021: Operation not permitted

Interesting. I had not anticipated a failure there? And it is failing in remount? Oh that is interesting.

Quoted 6 lines

That implies that there is some flag of the original mount of /proc that the remount of /proc/sys is clearing, and that previously

The flags specified are current rdonly,remount,bind so I expect there are some other flags on proc that libvirt-lxc is clearing by accident and we did not fail before because the kernel was not enforcing things.

Please see:
http://libvirt.org/git/?p=libvirt.git;a=blob;f=src/lxc/lxc_container.c;h=9a9ae5c2aaf0f90ff472f24fda43c077b44998c7;hb=HEAD#l933
lxcContainerMountBasicFS()

and:
http://libvirt.org/git/?p=libvirt.git;a=blob;f=src/lxc/lxc_container.c;h=9a9ae5c2aaf0f90ff472f24fda43c077b44998c7;hb=HEAD#l850
lxcBasicMounts

Quoted 1 line

What are the mount flags in a working libvirt-lxc?

See:
test1:~ # cat /proc/self/mountinfo
149 147 0:56 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw 150 149 0:56 /sys /proc/sys ro,nodev,relatime - proc proc rw

Quoted 4 lines
Quoted 1 line

If you need more info, please let me know. :-)

Oh interesting I had not realized libvirt-lxc had grown an unprivileged mode using user namespaces.

Yep. It works quite well. I've migrated all my containers from lxc to libvirt-lxc because libvirt-lxc had a working user-namespace implementation before lxc.

Quoted 28 lines

This does appear to be a classic remount bug, where you are not preserving the permissions. It appears the fact that the code failed to enforce locked permissions on the fresh mount of proc was hiding this bug until now.

I expect what you actually want is the code below:

src/lxc/lxc_container.c +1 -1
index 9a9ae5c2aaf0..f008a7484bfe 100644
@@ -850,7 +850,7 @@ typedef struct {
 
 static const virLXCBasicMountInfo lxcBasicMounts[] = {
     { "proc", "/proc", "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, false, false, false },
-    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, false, false, false },
+    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },
     { "/.oldroot/proc/sys/net/ipv4", "/proc/sys/net/ipv4", NULL, MS_BIND, false, false, true },
     { "/.oldroot/proc/sys/net/ipv6", "/proc/sys/net/ipv6", NULL, MS_BIND, false, false, true },
     { "sysfs", "/sys", "sysfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },

Or possibly just:

src/lxc/lxc_container.c +0 -0
index 9a9ae5c2aaf0..a60ccbd12bfc 100644

src/lxc/lxc_container.c typedef struct { · line 856

Quoted 8 lines
src/lxc/lxc_container.c +1 -1
@@ -850,7 +850,7 @@ typedef struct {
 
 static const virLXCBasicMountInfo lxcBasicMounts[] = {
     { "proc", "/proc", "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, false, false, false },
-    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, false, false, false },
+    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, true, false, false },
     { "/.oldroot/proc/sys/net/ipv4", "/proc/sys/net/ipv4", NULL, MS_BIND, false, false, true },
     { "/.oldroot/proc/sys/net/ipv6", "/proc/sys/net/ipv6", NULL, MS_BIND, false, false, true },
     { "sysfs", "/sys", "sysfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },

I'll test your diff tomorrow with a fresh brain.
I sent a similar patch to libvirt folks some time ago, looks like it got lost. ;-\

Quoted 4 lines

As the there is little point in making /proc/sys read-only in a user-namespace, as the permission checks are uid based and no-one should have the global uid 0 in your container. Making mounting /proc/sys read-only rather pointless.

Yeah, I've been ranting about that for ages... libvirt-lxc contains a lot of cruft to make privileged container kind of secure. Some users still fear using the user-namespace.

Thanks,
//richard

A message that is not in the archive (sent off-list or not yet received): 55678CCA.80807-/[email protected]

#172 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

Quoted 81 lines · Richard Weinberger

Am 28.05.2015 um 23:32 schrieb Eric W. Biederman:

Quoted 31 lines
Quoted 28 lines · Richard Weinberger

Am 28.05.2015 um 21:57 schrieb Eric W. Biederman:

Quoted 6 lines
Quoted 2 lines

FWIW, it breaks also libvirt-lxc:
Error: internal error: guest failed to start: Failed to re-mount /proc/sys on /proc/sys flags=1021: Operation not permitted

Interesting. I had not anticipated a failure there? And it is failing in remount? Oh that is interesting.

Quoted 6 lines

That implies that there is some flag of the original mount of /proc that the remount of /proc/sys is clearing, and that previously

The flags specified are current rdonly,remount,bind so I expect there are some other flags on proc that libvirt-lxc is clearing by accident and we did not fail before because the kernel was not enforcing things.

Please see:
http://libvirt.org/git/?p=libvirt.git;a=blob;f=src/lxc/lxc_container.c;h=9a9ae5c2aaf0f90ff472f24fda43c077b44998c7;hb=HEAD#l933
lxcContainerMountBasicFS()

and:
http://libvirt.org/git/?p=libvirt.git;a=blob;f=src/lxc/lxc_container.c;h=9a9ae5c2aaf0f90ff472f24fda43c077b44998c7;hb=HEAD#l850
lxcBasicMounts

Quoted 1 line

What are the mount flags in a working libvirt-lxc?

See:
test1:~ # cat /proc/self/mountinfo
149 147 0:56 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw 150 149 0:56 /sys /proc/sys ro,nodev,relatime - proc proc rw

Quoted 4 lines
Quoted 1 line

If you need more info, please let me know. :-)

Oh interesting I had not realized libvirt-lxc had grown an unprivileged mode using user namespaces.

Yep. It works quite well. I've migrated all my containers from lxc to libvirt-lxc because libvirt-lxc had a working user-namespace implementation before lxc.

Quoted 28 lines

This does appear to be a classic remount bug, where you are not preserving the permissions. It appears the fact that the code failed to enforce locked permissions on the fresh mount of proc was hiding this bug until now.

I expect what you actually want is the code below:

src/lxc/lxc_container.c +1 -1
index 9a9ae5c2aaf0..f008a7484bfe 100644
@@ -850,7 +850,7 @@ typedef struct {
 
 static const virLXCBasicMountInfo lxcBasicMounts[] = {
     { "proc", "/proc", "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, false, false, false },
-    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, false, false, false },
+    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },
     { "/.oldroot/proc/sys/net/ipv4", "/proc/sys/net/ipv4", NULL, MS_BIND, false, false, true },
     { "/.oldroot/proc/sys/net/ipv6", "/proc/sys/net/ipv6", NULL, MS_BIND, false, false, true },
     { "sysfs", "/sys", "sysfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },

Or possibly just:

src/lxc/lxc_container.c +0 -0
index 9a9ae5c2aaf0..a60ccbd12bfc 100644

src/lxc/lxc_container.c typedef struct { · line 856

Quoted 8 lines
src/lxc/lxc_container.c +1 -1
@@ -850,7 +850,7 @@ typedef struct {
 
 static const virLXCBasicMountInfo lxcBasicMounts[] = {
     { "proc", "/proc", "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, false, false, false },
-    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, false, false, false },
+    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, true, false, false },
     { "/.oldroot/proc/sys/net/ipv4", "/proc/sys/net/ipv4", NULL, MS_BIND, false, false, true },
     { "/.oldroot/proc/sys/net/ipv6", "/proc/sys/net/ipv6", NULL, MS_BIND, false, false, true },
     { "sysfs", "/sys", "sysfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },

I'll test your diff tomorrow with a fresh brain.
I sent a similar patch to libvirt folks some time ago, looks like it got lost. ;-\

Quoted 8 lines
Quoted 4 lines

As the there is little point in making /proc/sys read-only in a user-namespace, as the permission checks are uid based and no-one should have the global uid 0 in your container. Making mounting /proc/sys read-only rather pointless.

Yeah, I've been ranting about that for ages... libvirt-lxc contains a lot of cruft to make privileged container kind of secure. Some users still fear using the user-namespace.

Yes, we've discussed this before and I'd like to simplify this. The thing that has been stopping me tackling it has been figuring out a way to ensure we don't change semantics for existing deployed users. ie when RHEL-7 rebases to newer libvirt, I don't want existing containers to suddenly change their setup, because although the existing setup is sub-optimal, some apps / users might be relying on its behaviour in ways I can't predict.

I do believe I have figured out a way to allow backwards compatibility now though, so we should have able to have another stab at simplifying and removing this cruft for newly deployed containers.

Regards,
Daniel

Signature · 4 lines
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|
#173 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

In reply to a message not in the archive
Quoted 81 lines · Richard Weinberger

Am 28.05.2015 um 23:32 schrieb Eric W. Biederman:

Quoted 31 lines
Quoted 28 lines · Richard Weinberger

Am 28.05.2015 um 21:57 schrieb Eric W. Biederman:

Quoted 6 lines
Quoted 2 lines

FWIW, it breaks also libvirt-lxc:
Error: internal error: guest failed to start: Failed to re-mount /proc/sys on /proc/sys flags=1021: Operation not permitted

Interesting. I had not anticipated a failure there? And it is failing in remount? Oh that is interesting.

Quoted 6 lines

That implies that there is some flag of the original mount of /proc that the remount of /proc/sys is clearing, and that previously

The flags specified are current rdonly,remount,bind so I expect there are some other flags on proc that libvirt-lxc is clearing by accident and we did not fail before because the kernel was not enforcing things.

Please see:
http://libvirt.org/git/?p=libvirt.git;a=blob;f=src/lxc/lxc_container.c;h=9a9ae5c2aaf0f90ff472f24fda43c077b44998c7;hb=HEAD#l933
lxcContainerMountBasicFS()

and:
http://libvirt.org/git/?p=libvirt.git;a=blob;f=src/lxc/lxc_container.c;h=9a9ae5c2aaf0f90ff472f24fda43c077b44998c7;hb=HEAD#l850
lxcBasicMounts

Quoted 1 line

What are the mount flags in a working libvirt-lxc?

See:
test1:~ # cat /proc/self/mountinfo
149 147 0:56 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw 150 149 0:56 /sys /proc/sys ro,nodev,relatime - proc proc rw

Quoted 4 lines
Quoted 1 line

If you need more info, please let me know. :-)

Oh interesting I had not realized libvirt-lxc had grown an unprivileged mode using user namespaces.

Yep. It works quite well. I've migrated all my containers from lxc to libvirt-lxc because libvirt-lxc had a working user-namespace implementation before lxc.

Quoted 28 lines

This does appear to be a classic remount bug, where you are not preserving the permissions. It appears the fact that the code failed to enforce locked permissions on the fresh mount of proc was hiding this bug until now.

I expect what you actually want is the code below:

src/lxc/lxc_container.c +1 -1
index 9a9ae5c2aaf0..f008a7484bfe 100644
@@ -850,7 +850,7 @@ typedef struct {
 
 static const virLXCBasicMountInfo lxcBasicMounts[] = {
     { "proc", "/proc", "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, false, false, false },
-    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, false, false, false },
+    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },
     { "/.oldroot/proc/sys/net/ipv4", "/proc/sys/net/ipv4", NULL, MS_BIND, false, false, true },
     { "/.oldroot/proc/sys/net/ipv6", "/proc/sys/net/ipv6", NULL, MS_BIND, false, false, true },
     { "sysfs", "/sys", "sysfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },

Or possibly just:

src/lxc/lxc_container.c +0 -0
index 9a9ae5c2aaf0..a60ccbd12bfc 100644

src/lxc/lxc_container.c typedef struct { · line 856

Quoted 8 lines
src/lxc/lxc_container.c +1 -1
@@ -850,7 +850,7 @@ typedef struct {
 
 static const virLXCBasicMountInfo lxcBasicMounts[] = {
     { "proc", "/proc", "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, false, false, false },
-    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, false, false, false },
+    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, true, false, false },
     { "/.oldroot/proc/sys/net/ipv4", "/proc/sys/net/ipv4", NULL, MS_BIND, false, false, true },
     { "/.oldroot/proc/sys/net/ipv6", "/proc/sys/net/ipv6", NULL, MS_BIND, false, false, true },
     { "sysfs", "/sys", "sysfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },

I'll test your diff tomorrow with a fresh brain.
I sent a similar patch to libvirt folks some time ago, looks like it got lost. ;-\

Quoted 8 lines
Quoted 4 lines

As the there is little point in making /proc/sys read-only in a user-namespace, as the permission checks are uid based and no-one should have the global uid 0 in your container. Making mounting /proc/sys read-only rather pointless.

Yeah, I've been ranting about that for ages... libvirt-lxc contains a lot of cruft to make privileged container kind of secure. Some users still fear using the user-namespace.

Yes, we've discussed this before and I'd like to simplify this. The thing that has been stopping me tackling it has been figuring out a way to ensure we don't change semantics for existing deployed users. ie when RHEL-7 rebases to newer libvirt, I don't want existing containers to suddenly change their setup, because although the existing setup is sub-optimal, some apps / users might be relying on its behaviour in ways I can't predict.

I do believe I have figured out a way to allow backwards compatibility now though, so we should have able to have another stab at simplifying and removing this cruft for newly deployed containers.

Regards,
Daniel

Signature · 4 lines
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|
#174 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

In reply to a message not in the archive

[CC'ing libvirt-lxc folks]

Am 28.05.2015 um 23:32 schrieb Eric W. Biederman:

Quoted 73 lines
Quoted 22 lines · Richard Weinberger

Am 28.05.2015 um 21:57 schrieb Eric W. Biederman:

Quoted 6 lines
Quoted 2 lines

FWIW, it breaks also libvirt-lxc:
Error: internal error: guest failed to start: Failed to re-mount /proc/sys on /proc/sys flags=1021: Operation not permitted

Interesting. I had not anticipated a failure there? And it is failing in remount? Oh that is interesting.

Quoted 6 lines

That implies that there is some flag of the original mount of /proc that the remount of /proc/sys is clearing, and that previously

The flags specified are current rdonly,remount,bind so I expect there are some other flags on proc that libvirt-lxc is clearing by accident and we did not fail before because the kernel was not enforcing things.

Please see:
http://libvirt.org/git/?p=libvirt.git;a=blob;f=src/lxc/lxc_container.c;h=9a9ae5c2aaf0f90ff472f24fda43c077b44998c7;hb=HEAD#l933
lxcContainerMountBasicFS()

and:
http://libvirt.org/git/?p=libvirt.git;a=blob;f=src/lxc/lxc_container.c;h=9a9ae5c2aaf0f90ff472f24fda43c077b44998c7;hb=HEAD#l850
lxcBasicMounts

Quoted 8 lines
Quoted 1 line

What are the mount flags in a working libvirt-lxc?

See:
test1:~ # cat /proc/self/mountinfo
149 147 0:56 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw 150 149 0:56 /sys /proc/sys ro,nodev,relatime - proc proc rw

If you need more info, please let me know. :-)

Oh interesting I had not realized libvirt-lxc had grown an unprivileged mode using user namespaces.

This does appear to be a classic remount bug, where you are not preserving the permissions. It appears the fact that the code failed to enforce locked permissions on the fresh mount of proc was hiding this bug until now.

I expect what you actually want is the code below:

src/lxc/lxc_container.c +1 -1
index 9a9ae5c2aaf0..f008a7484bfe 100644
@@ -850,7 +850,7 @@ typedef struct {
 
 static const virLXCBasicMountInfo lxcBasicMounts[] = {
     { "proc", "/proc", "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, false, false, false },
-    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, false, false, false },
+    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },
     { "/.oldroot/proc/sys/net/ipv4", "/proc/sys/net/ipv4", NULL, MS_BIND, false, false, true },
     { "/.oldroot/proc/sys/net/ipv6", "/proc/sys/net/ipv6", NULL, MS_BIND, false, false, true },
     { "sysfs", "/sys", "sysfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },

Or possibly just:

src/lxc/lxc_container.c +1 -1
index 9a9ae5c2aaf0..a60ccbd12bfc 100644
@@ -850,7 +850,7 @@ typedef struct {
 
 static const virLXCBasicMountInfo lxcBasicMounts[] = {
     { "proc", "/proc", "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, false, false, false },
-    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, false, false, false },
+    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, true, false, false },
     { "/.oldroot/proc/sys/net/ipv4", "/proc/sys/net/ipv4", NULL, MS_BIND, false, false, true },
     { "/.oldroot/proc/sys/net/ipv6", "/proc/sys/net/ipv6", NULL, MS_BIND, false, false, true },
     { "sysfs", "/sys", "sysfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },
Quoted 4 lines

As the there is little point in making /proc/sys read-only in a user-namespace, as the permission checks are uid based and no-one should have the global uid 0 in your container. Making mounting /proc/sys read-only rather pointless.

Eric, using the patch below I was able to spawn a user-namespace enabled container using libvirt-lxc. :-)

I had to:
1. Disable the read-only mount of /proc/sys which is anyway useless in the user-namespace case.
2. Disable the /proc/sys/net/ipv{4,6} bind mounts, this ugly hack is only needed for the non user-namespace case.
3. Remove MS_RDONLY from the sysfs mount (For the non user-namespace case we'd have to keep this, though).

Daniel, I'd take this as a chance to disable all the MS_RDONLY games if user-namespace are configured. With Eric's fixes they hurt us. And as I wrote many times before if root within the user-namespace is able to do nasty things in /sys and /proc that's a plain kernel bug which needs fixing. There is no point in mounting these read-only. Except for the case then no user-namespace is used.

src/lxc/lxc_container.c +4 -4
index 9a9ae5c..497e05f 100644
@@ -850,10 +850,10 @@ typedef struct {
 
 static const virLXCBasicMountInfo lxcBasicMounts[] = {
     { "proc", "/proc", "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, false, false, false },
-    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, false, false, false },
-    { "/.oldroot/proc/sys/net/ipv4", "/proc/sys/net/ipv4", NULL, MS_BIND, false, false, true },
-    { "/.oldroot/proc/sys/net/ipv6", "/proc/sys/net/ipv6", NULL, MS_BIND, false, false, true },
-    { "sysfs", "/sys", "sysfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },
+    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, true, false, false },
+    { "/.oldroot/proc/sys/net/ipv4", "/proc/sys/net/ipv4", NULL, MS_BIND, true, false, true },
+    { "/.oldroot/proc/sys/net/ipv6", "/proc/sys/net/ipv6", NULL, MS_BIND, true, false, true },
+    { "sysfs", "/sys", "sysfs", MS_NOSUID|MS_NOEXEC|MS_NODEV, false, false, false },
     { "securityfs", "/sys/kernel/security", "securityfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, true, true, false },
 #if WITH_SELINUX
     { SELINUX_MOUNT, SELINUX_MOUNT, "selinuxfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, true, true, false },

Thanks,
//richard

A message that is not in the archive (sent off-list or not yet received): 556831CF.9040600-/[email protected]

#176 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

Quoted 76 lines · Richard Weinberger

[CC'ing libvirt-lxc folks]

Am 28.05.2015 um 23:32 schrieb Eric W. Biederman:

Quoted 73 lines
Quoted 22 lines · Richard Weinberger

Am 28.05.2015 um 21:57 schrieb Eric W. Biederman:

Quoted 6 lines
Quoted 2 lines

FWIW, it breaks also libvirt-lxc:
Error: internal error: guest failed to start: Failed to re-mount /proc/sys on /proc/sys flags=1021: Operation not permitted

Interesting. I had not anticipated a failure there? And it is failing in remount? Oh that is interesting.

Quoted 6 lines

That implies that there is some flag of the original mount of /proc that the remount of /proc/sys is clearing, and that previously

The flags specified are current rdonly,remount,bind so I expect there are some other flags on proc that libvirt-lxc is clearing by accident and we did not fail before because the kernel was not enforcing things.

Please see:
http://libvirt.org/git/?p=libvirt.git;a=blob;f=src/lxc/lxc_container.c;h=9a9ae5c2aaf0f90ff472f24fda43c077b44998c7;hb=HEAD#l933
lxcContainerMountBasicFS()

and:
http://libvirt.org/git/?p=libvirt.git;a=blob;f=src/lxc/lxc_container.c;h=9a9ae5c2aaf0f90ff472f24fda43c077b44998c7;hb=HEAD#l850
lxcBasicMounts

Quoted 8 lines
Quoted 1 line

What are the mount flags in a working libvirt-lxc?

See:
test1:~ # cat /proc/self/mountinfo
149 147 0:56 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw 150 149 0:56 /sys /proc/sys ro,nodev,relatime - proc proc rw

If you need more info, please let me know. :-)

Oh interesting I had not realized libvirt-lxc had grown an unprivileged mode using user namespaces.

This does appear to be a classic remount bug, where you are not preserving the permissions. It appears the fact that the code failed to enforce locked permissions on the fresh mount of proc was hiding this bug until now.

I expect what you actually want is the code below:

src/lxc/lxc_container.c +1 -1
index 9a9ae5c2aaf0..f008a7484bfe 100644
@@ -850,7 +850,7 @@ typedef struct {
 
 static const virLXCBasicMountInfo lxcBasicMounts[] = {
     { "proc", "/proc", "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, false, false, false },
-    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, false, false, false },
+    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },
     { "/.oldroot/proc/sys/net/ipv4", "/proc/sys/net/ipv4", NULL, MS_BIND, false, false, true },
     { "/.oldroot/proc/sys/net/ipv6", "/proc/sys/net/ipv6", NULL, MS_BIND, false, false, true },
     { "sysfs", "/sys", "sysfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },

Or possibly just:

src/lxc/lxc_container.c +1 -1
index 9a9ae5c2aaf0..a60ccbd12bfc 100644
@@ -850,7 +850,7 @@ typedef struct {
 
 static const virLXCBasicMountInfo lxcBasicMounts[] = {
     { "proc", "/proc", "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, false, false, false },
-    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, false, false, false },
+    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, true, false, false },
     { "/.oldroot/proc/sys/net/ipv4", "/proc/sys/net/ipv4", NULL, MS_BIND, false, false, true },
     { "/.oldroot/proc/sys/net/ipv6", "/proc/sys/net/ipv6", NULL, MS_BIND, false, false, true },
     { "sysfs", "/sys", "sysfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },
Quoted 7 lines
Quoted 4 lines

As the there is little point in making /proc/sys read-only in a user-namespace, as the permission checks are uid based and no-one should have the global uid 0 in your container. Making mounting /proc/sys read-only rather pointless.

Eric, using the patch below I was able to spawn a user-namespace enabled container using libvirt-lxc. :-)

I am glad.

I am trying to figure out which set of changes were necessary vs just nice to have, to inform that part of the conversation that is asking is there a way we can avoid breaking userspace for this security fix.

Quoted 3 lines

I had to:
1. Disable the read-only mount of /proc/sys which is anyway useless in the user-namespace case.

It is likely worth addressing the libvirt-lxc MS_REMOUNT code as it does not preserve any mount flags, or even have the capability to try.

    if (bindOverReadonly &&
            mount(mnt_src, mnt->dst, NULL,
                  MS_BIND|MS_REMOUNT|MS_RDONLY, NULL) < 0) {
            virReportSystemError(errno,
                                 _("Failed to re-mount %s on %s flags=%x"),
                                 mnt_src, mnt->dst,
                                 MS_BIND|MS_REMOUNT|MS_RDONLY);
            goto cleanup;
     }

Aka the flags during remount are hard coded (which is buggy). So I believe even without the use of user-namespaces this code does the wrong thing.

Likely statvfs needs to be called to get the existing mount flags and those should be applied during remount or possibly just the mount flags from the virLXCBasicMountInfo entry should be added.

Quoted 1 line

2. Disable the /proc/sys/net/ipv{4,6} bind mounts, this ugly hack is only needed for the non user-namespace case.

*Scratches my head*

Why was this necessary? Those are just plain bind mounts which do not need any remount-magic so they should have just worked and preserved the existing mount flags.

I agree they are unnecessary in this context but I don't expect they would have cause problems or were "wrong".

Quoted 1 line

3. Remove MS_RDONLY from the sysfs mount (For the non user-namespace case we'd have to keep this, though).

Ok. I can see this as being necessary as well, and missed in the first pass because the code did not get this far.

The code flow for sysfs appears to trigger the bindOverReadOnly code as MS_RDONLY is set.

Then the remount clears the other mount flags on sysfs. Which previously we would have not enforced as sysfs with a network namespace is a fresh mount (and that is the bug my patchset fixes).

This does very much look like a bug in libvirt-lxc clearing flags it did not intend to.

Quoted 27 lines

Daniel, I'd take this as a chance to disable all the MS_RDONLY games if user-namespace are configured. With Eric's fixes they hurt us. And as I wrote many times before if root within the user-namespace is able to do nasty things in /sys and /proc that's a plain kernel bug which needs fixing. There is no point in mounting these read-only. Except for the case then no user-namespace is used.

src/lxc/lxc_container.c +4 -4
index 9a9ae5c..497e05f 100644
@@ -850,10 +850,10 @@ typedef struct {
 
 static const virLXCBasicMountInfo lxcBasicMounts[] = {
     { "proc", "/proc", "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, false, false, false },
-    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, false, false, false },
-    { "/.oldroot/proc/sys/net/ipv4", "/proc/sys/net/ipv4", NULL, MS_BIND, false, false, true },
-    { "/.oldroot/proc/sys/net/ipv6", "/proc/sys/net/ipv6", NULL, MS_BIND, false, false, true },
-    { "sysfs", "/sys", "sysfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },
+    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, true, false, false },
+    { "/.oldroot/proc/sys/net/ipv4", "/proc/sys/net/ipv4", NULL, MS_BIND, true, false, true },
+    { "/.oldroot/proc/sys/net/ipv6", "/proc/sys/net/ipv6", NULL, MS_BIND, true, false, true },
+    { "sysfs", "/sys", "sysfs", MS_NOSUID|MS_NOEXEC|MS_NODEV, false, false, false },
     { "securityfs", "/sys/kernel/security", "securityfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, true, true, false },
 #if WITH_SELINUX
     { SELINUX_MOUNT, SELINUX_MOUNT, "selinuxfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, true, true, false },

Thanks,
//richard

#177 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

In reply to a message not in the archive
Quoted 76 lines · Richard Weinberger

[CC'ing libvirt-lxc folks]

Am 28.05.2015 um 23:32 schrieb Eric W. Biederman:

Quoted 73 lines
Quoted 22 lines · Richard Weinberger

Am 28.05.2015 um 21:57 schrieb Eric W. Biederman:

Quoted 6 lines
Quoted 2 lines

FWIW, it breaks also libvirt-lxc:
Error: internal error: guest failed to start: Failed to re-mount /proc/sys on /proc/sys flags=1021: Operation not permitted

Interesting. I had not anticipated a failure there? And it is failing in remount? Oh that is interesting.

Quoted 6 lines

That implies that there is some flag of the original mount of /proc that the remount of /proc/sys is clearing, and that previously

The flags specified are current rdonly,remount,bind so I expect there are some other flags on proc that libvirt-lxc is clearing by accident and we did not fail before because the kernel was not enforcing things.

Please see:
http://libvirt.org/git/?p=libvirt.git;a=blob;f=src/lxc/lxc_container.c;h=9a9ae5c2aaf0f90ff472f24fda43c077b44998c7;hb=HEAD#l933
lxcContainerMountBasicFS()

and:
http://libvirt.org/git/?p=libvirt.git;a=blob;f=src/lxc/lxc_container.c;h=9a9ae5c2aaf0f90ff472f24fda43c077b44998c7;hb=HEAD#l850
lxcBasicMounts

Quoted 8 lines
Quoted 1 line

What are the mount flags in a working libvirt-lxc?

See:
test1:~ # cat /proc/self/mountinfo
149 147 0:56 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw 150 149 0:56 /sys /proc/sys ro,nodev,relatime - proc proc rw

If you need more info, please let me know. :-)

Oh interesting I had not realized libvirt-lxc had grown an unprivileged mode using user namespaces.

This does appear to be a classic remount bug, where you are not preserving the permissions. It appears the fact that the code failed to enforce locked permissions on the fresh mount of proc was hiding this bug until now.

I expect what you actually want is the code below:

src/lxc/lxc_container.c +1 -1
index 9a9ae5c2aaf0..f008a7484bfe 100644
@@ -850,7 +850,7 @@ typedef struct {
 
 static const virLXCBasicMountInfo lxcBasicMounts[] = {
     { "proc", "/proc", "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, false, false, false },
-    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, false, false, false },
+    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },
     { "/.oldroot/proc/sys/net/ipv4", "/proc/sys/net/ipv4", NULL, MS_BIND, false, false, true },
     { "/.oldroot/proc/sys/net/ipv6", "/proc/sys/net/ipv6", NULL, MS_BIND, false, false, true },
     { "sysfs", "/sys", "sysfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },

Or possibly just:

src/lxc/lxc_container.c +1 -1
index 9a9ae5c2aaf0..a60ccbd12bfc 100644
@@ -850,7 +850,7 @@ typedef struct {
 
 static const virLXCBasicMountInfo lxcBasicMounts[] = {
     { "proc", "/proc", "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, false, false, false },
-    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, false, false, false },
+    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, true, false, false },
     { "/.oldroot/proc/sys/net/ipv4", "/proc/sys/net/ipv4", NULL, MS_BIND, false, false, true },
     { "/.oldroot/proc/sys/net/ipv6", "/proc/sys/net/ipv6", NULL, MS_BIND, false, false, true },
     { "sysfs", "/sys", "sysfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },
Quoted 7 lines
Quoted 4 lines

As the there is little point in making /proc/sys read-only in a user-namespace, as the permission checks are uid based and no-one should have the global uid 0 in your container. Making mounting /proc/sys read-only rather pointless.

Eric, using the patch below I was able to spawn a user-namespace enabled container using libvirt-lxc. :-)

I am glad.

I am trying to figure out which set of changes were necessary vs just nice to have, to inform that part of the conversation that is asking is there a way we can avoid breaking userspace for this security fix.

Quoted 3 lines

I had to:
1. Disable the read-only mount of /proc/sys which is anyway useless in the user-namespace case.

It is likely worth addressing the libvirt-lxc MS_REMOUNT code as it does not preserve any mount flags, or even have the capability to try.

    if (bindOverReadonly &&
            mount(mnt_src, mnt->dst, NULL,
                  MS_BIND|MS_REMOUNT|MS_RDONLY, NULL) < 0) {
            virReportSystemError(errno,
                                 _("Failed to re-mount %s on %s flags=%x"),
                                 mnt_src, mnt->dst,
                                 MS_BIND|MS_REMOUNT|MS_RDONLY);
            goto cleanup;
     }

Aka the flags during remount are hard coded (which is buggy). So I believe even without the use of user-namespaces this code does the wrong thing.

Likely statvfs needs to be called to get the existing mount flags and those should be applied during remount or possibly just the mount flags from the virLXCBasicMountInfo entry should be added.

Quoted 1 line

2. Disable the /proc/sys/net/ipv{4,6} bind mounts, this ugly hack is only needed for the non user-namespace case.

*Scratches my head*

Why was this necessary? Those are just plain bind mounts which do not need any remount-magic so they should have just worked and preserved the existing mount flags.

I agree they are unnecessary in this context but I don't expect they would have cause problems or were "wrong".

Quoted 1 line

3. Remove MS_RDONLY from the sysfs mount (For the non user-namespace case we'd have to keep this, though).

Ok. I can see this as being necessary as well, and missed in the first pass because the code did not get this far.

The code flow for sysfs appears to trigger the bindOverReadOnly code as MS_RDONLY is set.

Then the remount clears the other mount flags on sysfs. Which previously we would have not enforced as sysfs with a network namespace is a fresh mount (and that is the bug my patchset fixes).

This does very much look like a bug in libvirt-lxc clearing flags it did not intend to.

Quoted 27 lines

Daniel, I'd take this as a chance to disable all the MS_RDONLY games if user-namespace are configured. With Eric's fixes they hurt us. And as I wrote many times before if root within the user-namespace is able to do nasty things in /sys and /proc that's a plain kernel bug which needs fixing. There is no point in mounting these read-only. Except for the case then no user-namespace is used.

src/lxc/lxc_container.c +4 -4
index 9a9ae5c..497e05f 100644
@@ -850,10 +850,10 @@ typedef struct {
 
 static const virLXCBasicMountInfo lxcBasicMounts[] = {
     { "proc", "/proc", "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, false, false, false },
-    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, false, false, false },
-    { "/.oldroot/proc/sys/net/ipv4", "/proc/sys/net/ipv4", NULL, MS_BIND, false, false, true },
-    { "/.oldroot/proc/sys/net/ipv6", "/proc/sys/net/ipv6", NULL, MS_BIND, false, false, true },
-    { "sysfs", "/sys", "sysfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },
+    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, true, false, false },
+    { "/.oldroot/proc/sys/net/ipv4", "/proc/sys/net/ipv4", NULL, MS_BIND, true, false, true },
+    { "/.oldroot/proc/sys/net/ipv6", "/proc/sys/net/ipv6", NULL, MS_BIND, true, false, true },
+    { "sysfs", "/sys", "sysfs", MS_NOSUID|MS_NOEXEC|MS_NODEV, false, false, false },
     { "securityfs", "/sys/kernel/security", "securityfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, true, true, false },
 #if WITH_SELINUX
     { SELINUX_MOUNT, SELINUX_MOUNT, "selinuxfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, true, true, false },

Thanks,
//richard

#178 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

In reply to a message not in the archive
Quoted 89 lines · Richard Weinberger

[CC'ing libvirt-lxc folks]

Am 28.05.2015 um 23:32 schrieb Eric W. Biederman:

Quoted 73 lines
Quoted 22 lines · Richard Weinberger

Am 28.05.2015 um 21:57 schrieb Eric W. Biederman:

Quoted 6 lines
Quoted 2 lines

FWIW, it breaks also libvirt-lxc:
Error: internal error: guest failed to start: Failed to re-mount /proc/sys on /proc/sys flags=1021: Operation not permitted

Interesting. I had not anticipated a failure there? And it is failing in remount? Oh that is interesting.

Quoted 6 lines

That implies that there is some flag of the original mount of /proc that the remount of /proc/sys is clearing, and that previously

The flags specified are current rdonly,remount,bind so I expect there are some other flags on proc that libvirt-lxc is clearing by accident and we did not fail before because the kernel was not enforcing things.

Please see:
http://libvirt.org/git/?p=libvirt.git;a=blob;f=src/lxc/lxc_container.c;h=9a9ae5c2aaf0f90ff472f24fda43c077b44998c7;hb=HEAD#l933
lxcContainerMountBasicFS()

and:
http://libvirt.org/git/?p=libvirt.git;a=blob;f=src/lxc/lxc_container.c;h=9a9ae5c2aaf0f90ff472f24fda43c077b44998c7;hb=HEAD#l850
lxcBasicMounts

Quoted 8 lines
Quoted 1 line

What are the mount flags in a working libvirt-lxc?

See:
test1:~ # cat /proc/self/mountinfo
149 147 0:56 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw 150 149 0:56 /sys /proc/sys ro,nodev,relatime - proc proc rw

If you need more info, please let me know. :-)

Oh interesting I had not realized libvirt-lxc had grown an unprivileged mode using user namespaces.

This does appear to be a classic remount bug, where you are not preserving the permissions. It appears the fact that the code failed to enforce locked permissions on the fresh mount of proc was hiding this bug until now.

I expect what you actually want is the code below:

src/lxc/lxc_container.c +1 -1
index 9a9ae5c2aaf0..f008a7484bfe 100644
@@ -850,7 +850,7 @@ typedef struct {
 
 static const virLXCBasicMountInfo lxcBasicMounts[] = {
     { "proc", "/proc", "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, false, false, false },
-    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, false, false, false },
+    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },
     { "/.oldroot/proc/sys/net/ipv4", "/proc/sys/net/ipv4", NULL, MS_BIND, false, false, true },
     { "/.oldroot/proc/sys/net/ipv6", "/proc/sys/net/ipv6", NULL, MS_BIND, false, false, true },
     { "sysfs", "/sys", "sysfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },

Or possibly just:

src/lxc/lxc_container.c +1 -1
index 9a9ae5c2aaf0..a60ccbd12bfc 100644
@@ -850,7 +850,7 @@ typedef struct {
 
 static const virLXCBasicMountInfo lxcBasicMounts[] = {
     { "proc", "/proc", "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, false, false, false },
-    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, false, false, false },
+    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, true, false, false },
     { "/.oldroot/proc/sys/net/ipv4", "/proc/sys/net/ipv4", NULL, MS_BIND, false, false, true },
     { "/.oldroot/proc/sys/net/ipv6", "/proc/sys/net/ipv6", NULL, MS_BIND, false, false, true },
     { "sysfs", "/sys", "sysfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },
Quoted 4 lines

As the there is little point in making /proc/sys read-only in a user-namespace, as the permission checks are uid based and no-one should have the global uid 0 in your container. Making mounting /proc/sys read-only rather pointless.

Eric, using the patch below I was able to spawn a user-namespace enabled container using libvirt-lxc. :-)

I had to:
1. Disable the read-only mount of /proc/sys which is anyway useless in the user-namespace case.
2. Disable the /proc/sys/net/ipv{4,6} bind mounts, this ugly hack is only needed for the non user-namespace case.
3. Remove MS_RDONLY from the sysfs mount (For the non user-namespace case we'd have to keep this, though).

Quoted 5 lines

Daniel, I'd take this as a chance to disable all the MS_RDONLY games if user-namespace are configured. With Eric's fixes they hurt us. And as I wrote many times before if root within the user-namespace is able to do nasty things in /sys and /proc that's a plain kernel bug which needs fixing. There is no point in mounting these read-only. Except for the case then no user-namespace is used.

For clarity the patch below appears to be the minimal change needed to fix this security issue.

AKA add mnt_mflags in when remounting something read-only.

/proc/sys needed to be updated so it had the proper flags to be added back in.

I hope this helps.

src/lxc/lxc_container.c +2 -2
index 9a9ae5c2aaf0..11e9514e0761 100644
@@ -850,7 +850,7 @@ typedef struct {
 
 static const virLXCBasicMountInfo lxcBasicMounts[] = {
     { "proc", "/proc", "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, false, false, false },
-    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, false, false, false },
+    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },
     { "/.oldroot/proc/sys/net/ipv4", "/proc/sys/net/ipv4", NULL, MS_BIND, false, false, true },
     { "/.oldroot/proc/sys/net/ipv6", "/proc/sys/net/ipv6", NULL, MS_BIND, false, false, true },
     { "sysfs", "/sys", "sysfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },
@@ -1030,7 +1030,7 @@ static int lxcContainerMountBasicFS(bool userns_enabled,
 
         if (bindOverReadonly &&
             mount(mnt_src, mnt->dst, NULL,
-                  MS_BIND|MS_REMOUNT|MS_RDONLY, NULL) < 0) {
+                  MS_BIND|MS_REMOUNT|mnt_mflags|MS_RDONLY, NULL) < 0) {
             virReportSystemError(errno,
                                  _("Failed to re-mount %s on %s flags=%x"),
                                  mnt_src, mnt->dst,

Eric

#179 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

In reply to Richard Weinberger
Quoted 89 lines · Richard Weinberger

[CC'ing libvirt-lxc folks]

Am 28.05.2015 um 23:32 schrieb Eric W. Biederman:

Quoted 73 lines
Quoted 22 lines · Richard Weinberger

Am 28.05.2015 um 21:57 schrieb Eric W. Biederman:

Quoted 6 lines
Quoted 2 lines

FWIW, it breaks also libvirt-lxc:
Error: internal error: guest failed to start: Failed to re-mount /proc/sys on /proc/sys flags=1021: Operation not permitted

Interesting. I had not anticipated a failure there? And it is failing in remount? Oh that is interesting.

Quoted 6 lines

That implies that there is some flag of the original mount of /proc that the remount of /proc/sys is clearing, and that previously

The flags specified are current rdonly,remount,bind so I expect there are some other flags on proc that libvirt-lxc is clearing by accident and we did not fail before because the kernel was not enforcing things.

Please see:
http://libvirt.org/git/?p=libvirt.git;a=blob;f=src/lxc/lxc_container.c;h=9a9ae5c2aaf0f90ff472f24fda43c077b44998c7;hb=HEAD#l933
lxcContainerMountBasicFS()

and:
http://libvirt.org/git/?p=libvirt.git;a=blob;f=src/lxc/lxc_container.c;h=9a9ae5c2aaf0f90ff472f24fda43c077b44998c7;hb=HEAD#l850
lxcBasicMounts

Quoted 8 lines
Quoted 1 line

What are the mount flags in a working libvirt-lxc?

See:
test1:~ # cat /proc/self/mountinfo
149 147 0:56 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw 150 149 0:56 /sys /proc/sys ro,nodev,relatime - proc proc rw

If you need more info, please let me know. :-)

Oh interesting I had not realized libvirt-lxc had grown an unprivileged mode using user namespaces.

This does appear to be a classic remount bug, where you are not preserving the permissions. It appears the fact that the code failed to enforce locked permissions on the fresh mount of proc was hiding this bug until now.

I expect what you actually want is the code below:

src/lxc/lxc_container.c +1 -1
index 9a9ae5c2aaf0..f008a7484bfe 100644
@@ -850,7 +850,7 @@ typedef struct {
 
 static const virLXCBasicMountInfo lxcBasicMounts[] = {
     { "proc", "/proc", "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, false, false, false },
-    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, false, false, false },
+    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },
     { "/.oldroot/proc/sys/net/ipv4", "/proc/sys/net/ipv4", NULL, MS_BIND, false, false, true },
     { "/.oldroot/proc/sys/net/ipv6", "/proc/sys/net/ipv6", NULL, MS_BIND, false, false, true },
     { "sysfs", "/sys", "sysfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },

Or possibly just:

src/lxc/lxc_container.c +1 -1
index 9a9ae5c2aaf0..a60ccbd12bfc 100644
@@ -850,7 +850,7 @@ typedef struct {
 
 static const virLXCBasicMountInfo lxcBasicMounts[] = {
     { "proc", "/proc", "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, false, false, false },
-    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, false, false, false },
+    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, true, false, false },
     { "/.oldroot/proc/sys/net/ipv4", "/proc/sys/net/ipv4", NULL, MS_BIND, false, false, true },
     { "/.oldroot/proc/sys/net/ipv6", "/proc/sys/net/ipv6", NULL, MS_BIND, false, false, true },
     { "sysfs", "/sys", "sysfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },
Quoted 4 lines

As the there is little point in making /proc/sys read-only in a user-namespace, as the permission checks are uid based and no-one should have the global uid 0 in your container. Making mounting /proc/sys read-only rather pointless.

Eric, using the patch below I was able to spawn a user-namespace enabled container using libvirt-lxc. :-)

I had to:
1. Disable the read-only mount of /proc/sys which is anyway useless in the user-namespace case.
2. Disable the /proc/sys/net/ipv{4,6} bind mounts, this ugly hack is only needed for the non user-namespace case.
3. Remove MS_RDONLY from the sysfs mount (For the non user-namespace case we'd have to keep this, though).

Quoted 5 lines

Daniel, I'd take this as a chance to disable all the MS_RDONLY games if user-namespace are configured. With Eric's fixes they hurt us. And as I wrote many times before if root within the user-namespace is able to do nasty things in /sys and /proc that's a plain kernel bug which needs fixing. There is no point in mounting these read-only. Except for the case then no user-namespace is used.

For clarity the patch below appears to be the minimal change needed to fix this security issue.

AKA add mnt_mflags in when remounting something read-only.

/proc/sys needed to be updated so it had the proper flags to be added back in.

I hope this helps.

src/lxc/lxc_container.c +2 -2
index 9a9ae5c2aaf0..11e9514e0761 100644
@@ -850,7 +850,7 @@ typedef struct {
 
 static const virLXCBasicMountInfo lxcBasicMounts[] = {
     { "proc", "/proc", "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, false, false, false },
-    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, false, false, false },
+    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },
     { "/.oldroot/proc/sys/net/ipv4", "/proc/sys/net/ipv4", NULL, MS_BIND, false, false, true },
     { "/.oldroot/proc/sys/net/ipv6", "/proc/sys/net/ipv6", NULL, MS_BIND, false, false, true },
     { "sysfs", "/sys", "sysfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },
@@ -1030,7 +1030,7 @@ static int lxcContainerMountBasicFS(bool userns_enabled,
 
         if (bindOverReadonly &&
             mount(mnt_src, mnt->dst, NULL,
-                  MS_BIND|MS_REMOUNT|MS_RDONLY, NULL) < 0) {
+                  MS_BIND|MS_REMOUNT|mnt_mflags|MS_RDONLY, NULL) < 0) {
             virReportSystemError(errno,
                                  _("Failed to re-mount %s on %s flags=%x"),
                                  mnt_src, mnt->dst,

Eric

A message that is not in the archive (sent off-list or not yet received): [email protected]

#181 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

Quoted 121 lines · Eric W. Biederman
Quoted 89 lines · Richard Weinberger

[CC'ing libvirt-lxc folks]

Am 28.05.2015 um 23:32 schrieb Eric W. Biederman:

Quoted 73 lines
Quoted 22 lines · Richard Weinberger

Am 28.05.2015 um 21:57 schrieb Eric W. Biederman:

Quoted 6 lines
Quoted 2 lines

FWIW, it breaks also libvirt-lxc:
Error: internal error: guest failed to start: Failed to re-mount /proc/sys on /proc/sys flags=1021: Operation not permitted

Interesting. I had not anticipated a failure there? And it is failing in remount? Oh that is interesting.

Quoted 6 lines

That implies that there is some flag of the original mount of /proc that the remount of /proc/sys is clearing, and that previously

The flags specified are current rdonly,remount,bind so I expect there are some other flags on proc that libvirt-lxc is clearing by accident and we did not fail before because the kernel was not enforcing things.

Please see:
http://libvirt.org/git/?p=libvirt.git;a=blob;f=src/lxc/lxc_container.c;h=9a9ae5c2aaf0f90ff472f24fda43c077b44998c7;hb=HEAD#l933
lxcContainerMountBasicFS()

and:
http://libvirt.org/git/?p=libvirt.git;a=blob;f=src/lxc/lxc_container.c;h=9a9ae5c2aaf0f90ff472f24fda43c077b44998c7;hb=HEAD#l850
lxcBasicMounts

Quoted 8 lines
Quoted 1 line

What are the mount flags in a working libvirt-lxc?

See:
test1:~ # cat /proc/self/mountinfo
149 147 0:56 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw 150 149 0:56 /sys /proc/sys ro,nodev,relatime - proc proc rw

If you need more info, please let me know. :-)

Oh interesting I had not realized libvirt-lxc had grown an unprivileged mode using user namespaces.

This does appear to be a classic remount bug, where you are not preserving the permissions. It appears the fact that the code failed to enforce locked permissions on the fresh mount of proc was hiding this bug until now.

I expect what you actually want is the code below:

src/lxc/lxc_container.c +1 -1
index 9a9ae5c2aaf0..f008a7484bfe 100644
@@ -850,7 +850,7 @@ typedef struct {
 
 static const virLXCBasicMountInfo lxcBasicMounts[] = {
     { "proc", "/proc", "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, false, false, false },
-    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, false, false, false },
+    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },
     { "/.oldroot/proc/sys/net/ipv4", "/proc/sys/net/ipv4", NULL, MS_BIND, false, false, true },
     { "/.oldroot/proc/sys/net/ipv6", "/proc/sys/net/ipv6", NULL, MS_BIND, false, false, true },
     { "sysfs", "/sys", "sysfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },

Or possibly just:

src/lxc/lxc_container.c +1 -1
index 9a9ae5c2aaf0..a60ccbd12bfc 100644
@@ -850,7 +850,7 @@ typedef struct {
 
 static const virLXCBasicMountInfo lxcBasicMounts[] = {
     { "proc", "/proc", "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, false, false, false },
-    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, false, false, false },
+    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, true, false, false },
     { "/.oldroot/proc/sys/net/ipv4", "/proc/sys/net/ipv4", NULL, MS_BIND, false, false, true },
     { "/.oldroot/proc/sys/net/ipv6", "/proc/sys/net/ipv6", NULL, MS_BIND, false, false, true },
     { "sysfs", "/sys", "sysfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },
Quoted 4 lines

As the there is little point in making /proc/sys read-only in a user-namespace, as the permission checks are uid based and no-one should have the global uid 0 in your container. Making mounting /proc/sys read-only rather pointless.

Eric, using the patch below I was able to spawn a user-namespace enabled container using libvirt-lxc. :-)

I had to:
1. Disable the read-only mount of /proc/sys which is anyway useless in the user-namespace case.
2. Disable the /proc/sys/net/ipv{4,6} bind mounts, this ugly hack is only needed for the non user-namespace case.
3. Remove MS_RDONLY from the sysfs mount (For the non user-namespace case we'd have to keep this, though).

Quoted 5 lines

Daniel, I'd take this as a chance to disable all the MS_RDONLY games if user-namespace are configured. With Eric's fixes they hurt us. And as I wrote many times before if root within the user-namespace is able to do nasty things in /sys and /proc that's a plain kernel bug which needs fixing. There is no point in mounting these read-only. Except for the case then no user-namespace is used.

For clarity the patch below appears to be the minimal change needed to fix this security issue.

AKA add mnt_mflags in when remounting something read-only.

/proc/sys needed to be updated so it had the proper flags to be added back in.

I hope this helps.

src/lxc/lxc_container.c +1 -1
index 9a9ae5c2aaf0..11e9514e0761 100644
@@ -850,7 +850,7 @@ typedef struct {
 
 static const virLXCBasicMountInfo lxcBasicMounts[] = {
     { "proc", "/proc", "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, false, false, false },
-    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, false, false, false },
+    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },
     { "/.oldroot/proc/sys/net/ipv4", "/proc/sys/net/ipv4", NULL, MS_BIND, false, false, true },
     { "/.oldroot/proc/sys/net/ipv6", "/proc/sys/net/ipv6", NULL, MS_BIND, false, false, true },
     { "sysfs", "/sys", "sysfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },

src/lxc/lxc_container.c static int lxcContainerMountBasicFS(bool userns_enabled, · line 1036

Quoted 8 lines
src/lxc/lxc_container.c +1 -1
@@ -1030,7 +1030,7 @@ static int lxcContainerMountBasicFS(bool userns_enabled,
 
         if (bindOverReadonly &&
             mount(mnt_src, mnt->dst, NULL,
-                  MS_BIND|MS_REMOUNT|MS_RDONLY, NULL) < 0) {
+                  MS_BIND|MS_REMOUNT|mnt_mflags|MS_RDONLY, NULL) < 0) {
             virReportSystemError(errno,
                                  _("Failed to re-mount %s on %s flags=%x"),
                                  mnt_src, mnt->dst,

Thanks Richard / Eric for the suggested patches. I'll apply Eric's simplified patch to libvirt now, and backport it to our stable libvirt branches.

Regards,
Daniel

Signature · 4 lines
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|

A message that is not in the archive (sent off-list or not yet received): [email protected]

#183 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

Am 16.06.2015 um 14:31 schrieb Daniel P. Berrange:

Quoted 3 lines

Thanks Richard / Eric for the suggested patches. I'll apply Eric's simplified patch to libvirt now, and backport it to our stable libvirt branches.

Thank you Daniel!

#184 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

In reply to a message not in the archive

Am 16.06.2015 um 14:31 schrieb Daniel P. Berrange:

Quoted 3 lines

Thanks Richard / Eric for the suggested patches. I'll apply Eric's simplified patch to libvirt now, and backport it to our stable libvirt branches.

Thank you Daniel!

#185 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

In reply to a message not in the archive
Quoted 121 lines · Eric W. Biederman
Quoted 89 lines · Richard Weinberger

[CC'ing libvirt-lxc folks]

Am 28.05.2015 um 23:32 schrieb Eric W. Biederman:

Quoted 73 lines
Quoted 22 lines · Richard Weinberger

Am 28.05.2015 um 21:57 schrieb Eric W. Biederman:

Quoted 6 lines
Quoted 2 lines

FWIW, it breaks also libvirt-lxc:
Error: internal error: guest failed to start: Failed to re-mount /proc/sys on /proc/sys flags=1021: Operation not permitted

Interesting. I had not anticipated a failure there? And it is failing in remount? Oh that is interesting.

Quoted 6 lines

That implies that there is some flag of the original mount of /proc that the remount of /proc/sys is clearing, and that previously

The flags specified are current rdonly,remount,bind so I expect there are some other flags on proc that libvirt-lxc is clearing by accident and we did not fail before because the kernel was not enforcing things.

Please see:
http://libvirt.org/git/?p=libvirt.git;a=blob;f=src/lxc/lxc_container.c;h=9a9ae5c2aaf0f90ff472f24fda43c077b44998c7;hb=HEAD#l933
lxcContainerMountBasicFS()

and:
http://libvirt.org/git/?p=libvirt.git;a=blob;f=src/lxc/lxc_container.c;h=9a9ae5c2aaf0f90ff472f24fda43c077b44998c7;hb=HEAD#l850
lxcBasicMounts

Quoted 8 lines
Quoted 1 line

What are the mount flags in a working libvirt-lxc?

See:
test1:~ # cat /proc/self/mountinfo
149 147 0:56 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw 150 149 0:56 /sys /proc/sys ro,nodev,relatime - proc proc rw

If you need more info, please let me know. :-)

Oh interesting I had not realized libvirt-lxc had grown an unprivileged mode using user namespaces.

This does appear to be a classic remount bug, where you are not preserving the permissions. It appears the fact that the code failed to enforce locked permissions on the fresh mount of proc was hiding this bug until now.

I expect what you actually want is the code below:

src/lxc/lxc_container.c +1 -1
index 9a9ae5c2aaf0..f008a7484bfe 100644
@@ -850,7 +850,7 @@ typedef struct {
 
 static const virLXCBasicMountInfo lxcBasicMounts[] = {
     { "proc", "/proc", "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, false, false, false },
-    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, false, false, false },
+    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },
     { "/.oldroot/proc/sys/net/ipv4", "/proc/sys/net/ipv4", NULL, MS_BIND, false, false, true },
     { "/.oldroot/proc/sys/net/ipv6", "/proc/sys/net/ipv6", NULL, MS_BIND, false, false, true },
     { "sysfs", "/sys", "sysfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },

Or possibly just:

src/lxc/lxc_container.c +1 -1
index 9a9ae5c2aaf0..a60ccbd12bfc 100644
@@ -850,7 +850,7 @@ typedef struct {
 
 static const virLXCBasicMountInfo lxcBasicMounts[] = {
     { "proc", "/proc", "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, false, false, false },
-    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, false, false, false },
+    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, true, false, false },
     { "/.oldroot/proc/sys/net/ipv4", "/proc/sys/net/ipv4", NULL, MS_BIND, false, false, true },
     { "/.oldroot/proc/sys/net/ipv6", "/proc/sys/net/ipv6", NULL, MS_BIND, false, false, true },
     { "sysfs", "/sys", "sysfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },
Quoted 4 lines

As the there is little point in making /proc/sys read-only in a user-namespace, as the permission checks are uid based and no-one should have the global uid 0 in your container. Making mounting /proc/sys read-only rather pointless.

Eric, using the patch below I was able to spawn a user-namespace enabled container using libvirt-lxc. :-)

I had to:
1. Disable the read-only mount of /proc/sys which is anyway useless in the user-namespace case.
2. Disable the /proc/sys/net/ipv{4,6} bind mounts, this ugly hack is only needed for the non user-namespace case.
3. Remove MS_RDONLY from the sysfs mount (For the non user-namespace case we'd have to keep this, though).

Quoted 5 lines

Daniel, I'd take this as a chance to disable all the MS_RDONLY games if user-namespace are configured. With Eric's fixes they hurt us. And as I wrote many times before if root within the user-namespace is able to do nasty things in /sys and /proc that's a plain kernel bug which needs fixing. There is no point in mounting these read-only. Except for the case then no user-namespace is used.

For clarity the patch below appears to be the minimal change needed to fix this security issue.

AKA add mnt_mflags in when remounting something read-only.

/proc/sys needed to be updated so it had the proper flags to be added back in.

I hope this helps.

src/lxc/lxc_container.c +1 -1
index 9a9ae5c2aaf0..11e9514e0761 100644
@@ -850,7 +850,7 @@ typedef struct {
 
 static const virLXCBasicMountInfo lxcBasicMounts[] = {
     { "proc", "/proc", "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, false, false, false },
-    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, false, false, false },
+    { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },
     { "/.oldroot/proc/sys/net/ipv4", "/proc/sys/net/ipv4", NULL, MS_BIND, false, false, true },
     { "/.oldroot/proc/sys/net/ipv6", "/proc/sys/net/ipv6", NULL, MS_BIND, false, false, true },
     { "sysfs", "/sys", "sysfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },

src/lxc/lxc_container.c static int lxcContainerMountBasicFS(bool userns_enabled, · line 1036

Quoted 8 lines
src/lxc/lxc_container.c +1 -1
@@ -1030,7 +1030,7 @@ static int lxcContainerMountBasicFS(bool userns_enabled,
 
         if (bindOverReadonly &&
             mount(mnt_src, mnt->dst, NULL,
-                  MS_BIND|MS_REMOUNT|MS_RDONLY, NULL) < 0) {
+                  MS_BIND|MS_REMOUNT|mnt_mflags|MS_RDONLY, NULL) < 0) {
             virReportSystemError(errno,
                                  _("Failed to re-mount %s on %s flags=%x"),
                                  mnt_src, mnt->dst,

Thanks Richard / Eric for the suggested patches. I'll apply Eric's simplified patch to libvirt now, and backport it to our stable libvirt branches.

Regards,
Daniel

Signature · 4 lines
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|

A message that is not in the archive (sent off-list or not yet received): [email protected]

#187 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

Am 28.05.2015 um 21:57 schrieb Eric W. Biederman:

Quoted 6 lines
Quoted 2 lines

FWIW, it breaks also libvirt-lxc:
Error: internal error: guest failed to start: Failed to re-mount /proc/sys on /proc/sys flags=1021: Operation not permitted

Interesting. I had not anticipated a failure there? And it is failing in remount? Oh that is interesting.

Quoted 6 lines

That implies that there is some flag of the original mount of /proc that the remount of /proc/sys is clearing, and that previously

The flags specified are current rdonly,remount,bind so I expect there are some other flags on proc that libvirt-lxc is clearing by accident and we did not fail before because the kernel was not enforcing things.

Please see:
http://libvirt.org/git/?p=libvirt.git;a=blob;f=src/lxc/lxc_container.c;h=9a9ae5c2aaf0f90ff472f24fda43c077b44998c7;hb=HEAD#l933
lxcContainerMountBasicFS()

and:
http://libvirt.org/git/?p=libvirt.git;a=blob;f=src/lxc/lxc_container.c;h=9a9ae5c2aaf0f90ff472f24fda43c077b44998c7;hb=HEAD#l850
lxcBasicMounts

Quoted 1 line

What are the mount flags in a working libvirt-lxc?

See:
test1:~ # cat /proc/self/mountinfo
147 100 0:30 /srv/container/test1/rootfs / rw,relatime - btrfs /dev/sda2 rw,space_cache
149 147 0:56 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw
150 149 0:56 /sys /proc/sys ro,nodev,relatime - proc proc rw
151 150 0:3 /sys/net/ipv4 /proc/sys/net/ipv4 rw,nosuid,nodev,noexec,relatime - proc proc rw
152 150 0:3 /sys/net/ipv6 /proc/sys/net/ipv6 rw,nosuid,nodev,noexec,relatime - proc proc rw
153 147 0:57 / /sys ro,nodev,relatime - sysfs sysfs rw
154 149 0:53 /meminfo /proc/meminfo rw,nosuid,nodev,relatime - fuse libvirt rw,user_id=0,group_id=0,allow_other
155 153 0:58 / /sys/fs/cgroup rw,nosuid,nodev,noexec,relatime - tmpfs tmpfs rw,size=64k,mode=755,uid=10000,gid=10000
156 155 0:22 /machine.slice/machine-lxc\134x2dtest1.scope /sys/fs/cgroup/cpu,cpuacct rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,cpu,cpuacct 157 155 0:21 /machine.slice/machine-lxc\134x2dtest1.scope /sys/fs/cgroup/cpuset rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,cpuset 158 155 0:23 /machine.slice/machine-lxc\134x2dtest1.scope /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,memory 159 155 0:24 /machine.slice/machine-lxc\134x2dtest1.scope /sys/fs/cgroup/devices rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,devices 160 155 0:25 /machine.slice/machine-lxc\134x2dtest1.scope /sys/fs/cgroup/freezer rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,freezer 161 155 0:27 /machine.slice/machine-lxc\134x2dtest1.scope /sys/fs/cgroup/blkio rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,blkio 162 155 0:26 /machine.slice/machine-lxc\134x2dtest1.scope /sys/fs/cgroup/net_cls,net_prio rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,net_cls,net_prio 163 155 0:28 /machine.slice/machine-lxc\134x2dtest1.scope /sys/fs/cgroup/perf_event rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,perf_event 164 155 0:19 /machine.slice/machine-lxc\134x2dtest1.scope /sys/fs/cgroup/systemd rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd
165 147 0:52 / /dev rw,nosuid,relatime - tmpfs devfs rw,size=64k,mode=755
166 165 0:51 / /dev/pts rw,nosuid,relatime - devpts devpts rw,gid=10005,mode=620,ptmxmode=666
167 165 0:51 /ptmx /dev/ptmx rw,nosuid,relatime - devpts devpts rw,gid=10005,mode=620,ptmxmode=666
101 165 0:55 / /dev/shm rw,nosuid,nodev - tmpfs tmpfs rw,uid=10000,gid=10000
102 147 0:59 / /run rw,nosuid,nodev - tmpfs tmpfs rw,mode=755,uid=10000,gid=10000
103 165 0:54 / /dev/mqueue rw,nodev,relatime - mqueue mqueue rw
104 147 0:59 / /var/run rw,nosuid,nodev - tmpfs tmpfs rw,mode=755,uid=10000,gid=10000
105 147 0:59 /lock /var/lock rw,nosuid,nodev - tmpfs tmpfs rw,mode=755,uid=10000,gid=10000

If you need more info, please let me know. :-)

Thanks,
//richard

#188 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

In reply to Serge Hallyn

Am 28.05.2015 um 16:08 schrieb Serge Hallyn:

Quoted 7 lines · Andy Lutomirski
Quoted 6 lines
Quoted 1 line · Eric W. Biederman

I had hoped to get some Tested-By's on that patch series.

Sorry, I've been totally swamped.

Quoted 8 lines
Quoted 3 lines

I suspect that Sandstorm is okay, but I haven't had a chance to test it for real. Sandstorm makes only limited use of proc and sysfs in containers, but I'll see if I can test it for real this weekend.

Testing this with unprivileged containers, I get

lxc-start: conf.c: lxc_mount_auto_mounts: 808 Operation not permitted - error mounting sysfs on /usr/lib/x86_64-linux-gnu/lxc/sys/devices/virtual/net flags 0

FWIW, it breaks also libvirt-lxc:
Error: internal error: guest failed to start: Failed to re-mount /proc/sys on /proc/sys flags=1021: Operation not permitted

Thanks,
//richard

#189 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

In reply to a message not in the archive
Quoted 1 line · Eric W. Biederman

I had hoped to get some Tested-By's on that patch series.

Sorry, I've been totally swamped.

I suspect that Sandstorm is okay, but I haven't had a chance to test it for real. Sandstorm makes only limited use of proc and sysfs in containers, but I'll see if I can test it for real this weekend.

Quoted 8 lines

Oh well. The fundamentals seem sound, and my biggest concern the implicit nodev does not apply so I will put this patchset in linux-next and aim at merging it in the next merge window. Hopefully that will leave enough time catch problems.

Eric

Signature · 2 lines
Andy Lutomirski
AMA Capital Management, LLC
#190 lore raw

Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)

In reply to a message not in the archive

I had hoped to get some Tested-By's on that patch series.

Oh well. The fundamentals seem sound, and my biggest concern the implicit nodev does not apply so I will put this patchset in linux-next and aim at merging it in the next merge window. Hopefully that will leave enough time catch problems.

Eric

#191 lore raw

PATCH 2/10 mnt: Modify fs_fully_visible to deal with mount attributes

In reply to Eric W. Biederman

Ignore an existing mount if it's locked attributes are less permissive than the new mounts attributes.

On success ensure the new mount locks all of the same attributes as the old mount.

---
 fs/namespace.c | 32 +++++++++++++++++++++++++++++---
 1 file changed, 29 insertions(+), 3 deletions(-)
fs/namespace.c +29 -3
index 8e7edaf60fe1..fccee9924e8c 100644
@@ -2332,7 +2332,7 @@ unlock:
 	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
@@ -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;
 		}
 	}
@@ -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;
 
@@ -3191,6 +3192,25 @@ 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_NOSUID) &&
+		    !(new_flags & MNT_NOSUID))
+			continue;
+		if ((mnt->mnt.mnt_flags & MNT_LOCK_NOEXEC) &&
+		    !(new_flags & MNT_NOEXEC))
+			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.
 		 */
@@ -3201,6 +3221,12 @@ 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_NOSUID   | \
+							MNT_LOCK_NOEXEC   | \
+							MNT_LOCK_ATIME);
 		visible = true;
 		goto found;
 	next:	;
Signature · 1 line
2.2.1