lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20170921191434.GP5698@ram.oc3035372033.ibm.com>
Date:   Thu, 21 Sep 2017 12:14:34 -0700
From:   Ram Pai <linuxram@...ibm.com>
To:     Dawid Ciezarkiewicz <dawid.ciezarkiewicz@...rik.com>
Cc:     "Eric W. Biederman" <ebiederm@...ssion.com>,
        linux-kernel@...r.kernel.org, linux-fsdevel@...r.kernel.org
Subject: Re: Read-only `slaves` with shared subtrees?

On Wed, Sep 20, 2017 at 08:00:57PM -0700, Dawid Ciezarkiewicz wrote:
> On Wed, Sep 20, 2017 at 5:39 PM, Ram Pai <linuxram@...ibm.com> wrote:
> > Anyway; so something like this should be possible without breaking
> > existing semantics.
> >
> > mount -o bind,remount,ro /mnt
> > mount --make-pass-on-access  /mnt
> >
> > anything that gets mounted under /mnt will inherit the
> > 'ro' attribute from its parent.  And when a mount-event propagates
> > to a read-only-slave-mount, that new mount will automatically
> > inherit the read-only attribute from its slave-parent.
> >
> > Dawid: will that work for you?
> 
> 
> Yes. It is even more universal.


Here is a patch that accomplishes the job. tested to work with
some simple use cases.  check if this works for you. If it does
than we will have to think through all the edge cases and make it
acceptable.


------------------------------------------------------
Signed-off-by: Ram Pai <linuxram@...ibm.com>

diff --git a/fs/namespace.c b/fs/namespace.c
index f8893dc..08f63b6 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -854,6 +854,8 @@ void mnt_set_mountpoint(struct mount *mnt,
 	child_mnt->mnt_mountpoint = dget(mp->m_dentry);
 	child_mnt->mnt_parent = mnt;
 	child_mnt->mnt_mp = mp;
+	if (mnt->mnt.mnt_flags & MNT_STICKY_RW)
+		child_mnt->mnt.mnt_flags |= (mnt->mnt.mnt_flags & (MNT_READONLY | MNT_STICKY_RW));
 	hlist_add_head(&child_mnt->mnt_mp_list, &mp->m_list);
 }
 
@@ -1052,6 +1054,12 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root,
 	    (!(flag & CL_EXPIRE) || list_empty(&old->mnt_expire)))
 		mnt->mnt.mnt_flags |= MNT_LOCKED;
 
+	if (flag & CL_STICKY_RW) {
+		mnt->mnt.mnt_flags |= MNT_STICKY_RW;
+		if (flag & CL_READONLY)
+			mnt->mnt.mnt_flags |= MNT_READONLY;
+	}
+
 	atomic_inc(&sb->s_active);
 	mnt->mnt.mnt_sb = sb;
 	mnt->mnt.mnt_root = dget(root);
@@ -2078,7 +2086,7 @@ static int flags_to_propagation_type(int flags)
 	int type = flags & ~(MS_REC | MS_SILENT);
 
 	/* Fail if any non-propagation flags are set */
-	if (type & ~(MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
+	if (type & ~(MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE | MS_STICKY_RW))
 		return 0;
 	/* Only one propagation flag should be set */
 	if (!is_power_of_2(type))
@@ -2113,7 +2121,10 @@ static int do_change_type(struct path *path, int flag)
 
 	lock_mount_hash();
 	for (m = mnt; m; m = (recurse ? next_mnt(m, mnt) : NULL))
-		change_mnt_propagation(m, type);
+		if (type == MS_STICKY_RW)
+			set_mnt_sticky(m);
+		else
+			change_mnt_propagation(m, type);
 	unlock_mount_hash();
 
  out_unlock:
@@ -2768,7 +2779,7 @@ long do_mount(const char *dev_name, const char __user *dir_name,
 				    data_page);
 	else if (flags & MS_BIND)
 		retval = do_loopback(&path, dev_name, flags & MS_REC);
-	else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
+	else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE | MS_STICKY_RW))
 		retval = do_change_type(&path, flags);
 	else if (flags & MS_MOVE)
 		retval = do_move_mount(&path, dev_name);
diff --git a/fs/pnode.c b/fs/pnode.c
index 53d411a..386105a 100644
--- a/fs/pnode.c
+++ b/fs/pnode.c
@@ -262,6 +262,13 @@ static int propagate_one(struct mount *m)
 	/* Notice when we are propagating across user namespaces */
 	if (m->mnt_ns->user_ns != user_ns)
 		type |= CL_UNPRIVILEGED;
+
+	if (m->mnt.mnt_flags & MNT_STICKY_RW) {
+		type |= CL_STICKY_RW;
+		if (m->mnt.mnt_flags & MNT_READONLY)
+			type |= CL_READONLY;
+	}
+
 	child = copy_tree(last_source, last_source->mnt.mnt_root, type);
 	if (IS_ERR(child))
 		return PTR_ERR(child);
diff --git a/fs/pnode.h b/fs/pnode.h
index dc87e65..0a4f7c2 100644
--- a/fs/pnode.h
+++ b/fs/pnode.h
@@ -29,6 +29,8 @@
 #define CL_SHARED_TO_SLAVE	0x20
 #define CL_UNPRIVILEGED		0x40
 #define CL_COPY_MNT_NS_FILE	0x80
+#define CL_STICKY_RW		0x100
+#define CL_READONLY		0x200
 
 #define CL_COPY_ALL		(CL_COPY_UNBINDABLE | CL_COPY_MNT_NS_FILE)
 
@@ -38,6 +40,11 @@ static inline void set_mnt_shared(struct mount *mnt)
 	mnt->mnt.mnt_flags |= MNT_SHARED;
 }
 
+static inline void set_mnt_sticky(struct mount *mnt)
+{
+	mnt->mnt.mnt_flags |= MNT_STICKY_RW;
+}
+
 void change_mnt_propagation(struct mount *, int);
 int propagate_mnt(struct mount *, struct mountpoint *, struct mount *,
 		struct hlist_head *);
diff --git a/include/linux/mount.h b/include/linux/mount.h
index 1ce85e6..85dc195 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -28,6 +28,7 @@
 #define MNT_NODIRATIME	0x10
 #define MNT_RELATIME	0x20
 #define MNT_READONLY	0x40	/* does the user want this to be r/o? */
+#define MNT_STICKY_RW	0x80	/* children inherit READONLY attr if set */
 
 #define MNT_SHRINKABLE	0x100
 #define MNT_WRITE_HOLD	0x200
diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h
index b7495d0..b06b277 100644
--- a/include/uapi/linux/fs.h
+++ b/include/uapi/linux/fs.h
@@ -112,6 +112,7 @@ struct inodes_stat_t {
 #define MS_REMOUNT	32	/* Alter flags of a mounted FS */
 #define MS_MANDLOCK	64	/* Allow mandatory locks on an FS */
 #define MS_DIRSYNC	128	/* Directory modifications are synchronous */
+#define MS_STICKY_RW	(1<<8)	/* children inherit the RW flag */
 #define MS_NOATIME	1024	/* Do not update access times. */
 #define MS_NODIRATIME	2048	/* Do not update directory access times */
 #define MS_BIND		4096

------------------------------------------------------

Here is a small program that setsup a mount to enable inheritance
of the RW attribute of the mount.

/* pass_on_readonly.c */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mount.h>

#define MS_STICKY_RW (1<<8)

int main(int argc, char *argv[])
{
	unsigned long flags = MS_STICKY_RW;

	if (argc < 2) {
		printf("only argc=%d\n", argc);
		exit (0);
	}
	if (mount(argv[1], argv[1], NULL, flags, NULL) == -1)
		perror("failed ");
	exit (0);
}

-------------------------------------------------------



my testcase is

a) setup a shared mount
	mkdir shared
	mount --bind shared shared
	mount --make-shared shared

b) setup a slave mount
	mkdir slave
	mount --bind shared slave
	mount --make-slave slave

c) make the slave readonly
	mount -o bind,remount,ro slave

d) setup the slave to for passing one its readonly attribute
	gcc pass_on_readonly.c -o pass_on_readonly
	./pass_on_readonly slave


e) create a small mount tree to bind
	mkdir tmpbind
	mount --bind tmpbind tmpbind
	mkdir -p tmpbind/subtmpbind
	mount --bind tmpbind/subtmpbind tmpbind/subtmpbind

f) now mount this tree on the shared mount
	mkdir shared/sub
	mount --rbind tmpbind shared/sub

e) verify if the mounts under slave/sub are all readonly.
	> slave/sub/create_a_file
	slave/sub/create_a_file	: Read-only file system

	> slave/sub/subtmpbind/create_another_file
	slave/sub/subtmpbind/create_another_file : Read-only file system


RP

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ