All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/4] fuse: Add support for mounts from pid/user namespaces
@ 2014-09-12 14:41 Seth Forshee
  2014-09-12 14:41   ` Seth Forshee
                   ` (4 more replies)
  0 siblings, 5 replies; 12+ messages in thread
From: Seth Forshee @ 2014-09-12 14:41 UTC (permalink / raw)
  To: Miklos Szeredi, Alexander Viro, Eric W. Biederman
  Cc: Serge Hallyn, fuse-devel, linux-kernel, linux-fsdevel, Seth Forshee

Third round of patches for making it possible to mount with fuse from
within user namespaces. The only change since v2 is the addition of a
patch to ensure real root is capable towards inodes whose uid/gid is
invalid.

Thanks,
Seth


Seth Forshee (4):
  vfs: Check for invalid i_uid in may_follow_link()
  vfs,userns: Ensure real root is always capable towards inodes
  fuse: Translate pids passed to userspace into pid namespaces
  fuse: Add support for mounts from user namespaces

 fs/fuse/dev.c       | 13 +++++++------
 fs/fuse/dir.c       | 46 +++++++++++++++++++++++++++++++++-------------
 fs/fuse/fuse_i.h    |  8 ++++++++
 fs/fuse/inode.c     | 31 +++++++++++++++++++++++--------
 fs/inode.c          |  3 +++
 fs/namei.c          |  2 +-
 kernel/capability.c |  6 +++++-
 7 files changed, 80 insertions(+), 29 deletions(-)


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v3 1/4] vfs: Check for invalid i_uid in may_follow_link()
@ 2014-09-12 14:41   ` Seth Forshee
  0 siblings, 0 replies; 12+ messages in thread
From: Seth Forshee @ 2014-09-12 14:41 UTC (permalink / raw)
  To: Miklos Szeredi, Alexander Viro, Eric W. Biederman
  Cc: Serge Hallyn, fuse-devel, linux-kernel, linux-fsdevel, Seth Forshee

Filesystem uids which don't map into a user namespace may result
in inode->i_uid being INVALID_UID. A symlink and its parent
could have different owners in the filesystem can both get
mapped to INVALID_UID, which may result in following a symlink
when this would not have otherwise been permitted. Prevent this
by adding a check that the uid is valid before the comparison.

Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
Acked-by: Serge E. Hallyn <serge.hallyn@ubuntu.com>
---
 fs/namei.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/namei.c b/fs/namei.c
index a996bb48dfab..193da09e903e 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -741,7 +741,7 @@ static inline int may_follow_link(struct path *link, struct nameidata *nd)
 		return 0;
 
 	/* Allowed if parent directory and link owner match. */
-	if (uid_eq(parent->i_uid, inode->i_uid))
+	if (uid_valid(inode->i_uid) && uid_eq(parent->i_uid, inode->i_uid))
 		return 0;
 
 	audit_log_link_denied("follow_link", link);
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 1/4] vfs: Check for invalid i_uid in may_follow_link()
@ 2014-09-12 14:41   ` Seth Forshee
  0 siblings, 0 replies; 12+ messages in thread
From: Seth Forshee @ 2014-09-12 14:41 UTC (permalink / raw)
  To: Miklos Szeredi, Alexander Viro, Eric W. Biederman
  Cc: fuse-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Serge Hallyn,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Seth Forshee

Filesystem uids which don't map into a user namespace may result
in inode->i_uid being INVALID_UID. A symlink and its parent
could have different owners in the filesystem can both get
mapped to INVALID_UID, which may result in following a symlink
when this would not have otherwise been permitted. Prevent this
by adding a check that the uid is valid before the comparison.

Signed-off-by: Seth Forshee <seth.forshee-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
Acked-by: Serge E. Hallyn <serge.hallyn-GeWIH/nMZzLQT0dZR+AlfA@public.gmane.org>
---
 fs/namei.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/namei.c b/fs/namei.c
index a996bb48dfab..193da09e903e 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -741,7 +741,7 @@ static inline int may_follow_link(struct path *link, struct nameidata *nd)
 		return 0;
 
 	/* Allowed if parent directory and link owner match. */
-	if (uid_eq(parent->i_uid, inode->i_uid))
+	if (uid_valid(inode->i_uid) && uid_eq(parent->i_uid, inode->i_uid))
 		return 0;
 
 	audit_log_link_denied("follow_link", link);
-- 
1.9.1


------------------------------------------------------------------------------
Want excitement?
Manually upgrade your production database.
When you want reliability, choose Perforce
Perforce version control. Predictably reliable.
http://pubads.g.doubleclick.net/gampad/clk?id=157508191&iu=/4140/ostg.clktrk

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 2/4] vfs,userns: Ensure real root is always capable towards inodes
@ 2014-09-12 14:41   ` Seth Forshee
  0 siblings, 0 replies; 12+ messages in thread
From: Seth Forshee @ 2014-09-12 14:41 UTC (permalink / raw)
  To: Miklos Szeredi, Alexander Viro, Eric W. Biederman
  Cc: Serge Hallyn, fuse-devel, linux-kernel, linux-fsdevel, Seth Forshee

Currently root is restricted from performing some modifications
to inodes whose owner is INVALID_UID or group is INVALID_GID
because this id doesn't map into any user namespace. Add a
special case to the relevant checks to make sure root is always
capable of performing these operations.

Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
---
 fs/inode.c          | 3 +++
 kernel/capability.c | 6 +++++-
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/fs/inode.c b/fs/inode.c
index 26753ba7b6d6..1029320ff029 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -1840,6 +1840,9 @@ bool inode_owner_or_capable(const struct inode *inode)
 {
 	struct user_namespace *ns;
 
+	if (capable(CAP_SYS_ADMIN))
+		return true;
+
 	if (uid_eq(current_fsuid(), inode->i_uid))
 		return true;
 
diff --git a/kernel/capability.c b/kernel/capability.c
index 989f5bfc57dc..a472eaa52b6a 100644
--- a/kernel/capability.c
+++ b/kernel/capability.c
@@ -438,8 +438,12 @@ EXPORT_SYMBOL(capable);
  */
 bool capable_wrt_inode_uidgid(const struct inode *inode, int cap)
 {
-	struct user_namespace *ns = current_user_ns();
+	struct user_namespace *ns;
 
+	if (capable(CAP_SYS_ADMIN))
+		return true;
+
+	ns = current_user_ns();
 	return ns_capable(ns, cap) && kuid_has_mapping(ns, inode->i_uid) &&
 		kgid_has_mapping(ns, inode->i_gid);
 }
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 2/4] vfs, userns: Ensure real root is always capable towards inodes
@ 2014-09-12 14:41   ` Seth Forshee
  0 siblings, 0 replies; 12+ messages in thread
From: Seth Forshee @ 2014-09-12 14:41 UTC (permalink / raw)
  To: Miklos Szeredi, Alexander Viro, Eric W. Biederman
  Cc: fuse-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Serge Hallyn,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Seth Forshee

Currently root is restricted from performing some modifications
to inodes whose owner is INVALID_UID or group is INVALID_GID
because this id doesn't map into any user namespace. Add a
special case to the relevant checks to make sure root is always
capable of performing these operations.

Signed-off-by: Seth Forshee <seth.forshee-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
---
 fs/inode.c          | 3 +++
 kernel/capability.c | 6 +++++-
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/fs/inode.c b/fs/inode.c
index 26753ba7b6d6..1029320ff029 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -1840,6 +1840,9 @@ bool inode_owner_or_capable(const struct inode *inode)
 {
 	struct user_namespace *ns;
 
+	if (capable(CAP_SYS_ADMIN))
+		return true;
+
 	if (uid_eq(current_fsuid(), inode->i_uid))
 		return true;
 
diff --git a/kernel/capability.c b/kernel/capability.c
index 989f5bfc57dc..a472eaa52b6a 100644
--- a/kernel/capability.c
+++ b/kernel/capability.c
@@ -438,8 +438,12 @@ EXPORT_SYMBOL(capable);
  */
 bool capable_wrt_inode_uidgid(const struct inode *inode, int cap)
 {
-	struct user_namespace *ns = current_user_ns();
+	struct user_namespace *ns;
 
+	if (capable(CAP_SYS_ADMIN))
+		return true;
+
+	ns = current_user_ns();
 	return ns_capable(ns, cap) && kuid_has_mapping(ns, inode->i_uid) &&
 		kgid_has_mapping(ns, inode->i_gid);
 }
-- 
1.9.1


------------------------------------------------------------------------------
Want excitement?
Manually upgrade your production database.
When you want reliability, choose Perforce
Perforce version control. Predictably reliable.
http://pubads.g.doubleclick.net/gampad/clk?id=157508191&iu=/4140/ostg.clktrk

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 3/4] fuse: Translate pids passed to userspace into pid namespaces
@ 2014-09-12 14:41   ` Seth Forshee
  0 siblings, 0 replies; 12+ messages in thread
From: Seth Forshee @ 2014-09-12 14:41 UTC (permalink / raw)
  To: Miklos Szeredi, Alexander Viro, Eric W. Biederman
  Cc: Serge Hallyn, fuse-devel, linux-kernel, linux-fsdevel, Seth Forshee

If the process reading on the fuse fd is executing in a pid
namespace then giving it the global pid of the process making
a request doesn't make sense. Instead, capture the pid namespace
when the filesystem is first mounted and translate pids into this
namespace before passing them to userspace.

Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
Acked-by: Serge E. Hallyn <serge.hallyn@ubuntu.com>
---
 fs/fuse/dev.c    | 9 +++++----
 fs/fuse/fuse_i.h | 4 ++++
 fs/fuse/inode.c  | 3 +++
 3 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index ca887314aba9..839caebd34f1 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -20,6 +20,7 @@
 #include <linux/swap.h>
 #include <linux/splice.h>
 #include <linux/aio.h>
+#include <linux/sched.h>
 
 MODULE_ALIAS_MISCDEV(FUSE_MINOR);
 MODULE_ALIAS("devname:fuse");
@@ -124,11 +125,11 @@ static void __fuse_put_request(struct fuse_req *req)
 	atomic_dec(&req->count);
 }
 
-static void fuse_req_init_context(struct fuse_req *req)
+static void fuse_req_init_context(struct fuse_conn *fc, struct fuse_req *req)
 {
 	req->in.h.uid = from_kuid_munged(&init_user_ns, current_fsuid());
 	req->in.h.gid = from_kgid_munged(&init_user_ns, current_fsgid());
-	req->in.h.pid = current->pid;
+	req->in.h.pid = pid_nr_ns(task_pid(current), fc->pid_ns);
 }
 
 static bool fuse_block_alloc(struct fuse_conn *fc, bool for_background)
@@ -168,7 +169,7 @@ static struct fuse_req *__fuse_get_req(struct fuse_conn *fc, unsigned npages,
 		goto out;
 	}
 
-	fuse_req_init_context(req);
+	fuse_req_init_context(fc, req);
 	req->waiting = 1;
 	req->background = for_background;
 	return req;
@@ -257,7 +258,7 @@ struct fuse_req *fuse_get_req_nofail_nopages(struct fuse_conn *fc,
 	if (!req)
 		req = get_reserved_req(fc, file);
 
-	fuse_req_init_context(req);
+	fuse_req_init_context(fc, req);
 	req->waiting = 1;
 	req->background = 0;
 	return req;
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index e8e47a6ab518..a3ded071e2c6 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -22,6 +22,7 @@
 #include <linux/rbtree.h>
 #include <linux/poll.h>
 #include <linux/workqueue.h>
+#include <linux/pid_namespace.h>
 
 /** Max number of pages that can be used in a single read request */
 #define FUSE_MAX_PAGES_PER_REQ 32
@@ -386,6 +387,9 @@ struct fuse_conn {
 	/** The group id for this mount */
 	kgid_t group_id;
 
+	/** The pid namespace for this mount */
+	struct pid_namespace *pid_ns;
+
 	/** The fuse mount flags for this mount */
 	unsigned flags;
 
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 03246cd9d47a..c6d8473b1a80 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -20,6 +20,7 @@
 #include <linux/random.h>
 #include <linux/sched.h>
 #include <linux/exportfs.h>
+#include <linux/pid_namespace.h>
 
 MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>");
 MODULE_DESCRIPTION("Filesystem in Userspace");
@@ -616,6 +617,7 @@ void fuse_conn_init(struct fuse_conn *fc)
 	fc->initialized = 0;
 	fc->attr_version = 1;
 	get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key));
+	fc->pid_ns = get_pid_ns(task_active_pid_ns(current));
 }
 EXPORT_SYMBOL_GPL(fuse_conn_init);
 
@@ -953,6 +955,7 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req)
 
 static void fuse_free_conn(struct fuse_conn *fc)
 {
+	put_pid_ns(fc->pid_ns);
 	kfree_rcu(fc, rcu);
 }
 
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 3/4] fuse: Translate pids passed to userspace into pid namespaces
@ 2014-09-12 14:41   ` Seth Forshee
  0 siblings, 0 replies; 12+ messages in thread
From: Seth Forshee @ 2014-09-12 14:41 UTC (permalink / raw)
  To: Miklos Szeredi, Alexander Viro, Eric W. Biederman
  Cc: fuse-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Serge Hallyn,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Seth Forshee

If the process reading on the fuse fd is executing in a pid
namespace then giving it the global pid of the process making
a request doesn't make sense. Instead, capture the pid namespace
when the filesystem is first mounted and translate pids into this
namespace before passing them to userspace.

Signed-off-by: Seth Forshee <seth.forshee-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
Acked-by: Serge E. Hallyn <serge.hallyn-GeWIH/nMZzLQT0dZR+AlfA@public.gmane.org>
---
 fs/fuse/dev.c    | 9 +++++----
 fs/fuse/fuse_i.h | 4 ++++
 fs/fuse/inode.c  | 3 +++
 3 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index ca887314aba9..839caebd34f1 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -20,6 +20,7 @@
 #include <linux/swap.h>
 #include <linux/splice.h>
 #include <linux/aio.h>
+#include <linux/sched.h>
 
 MODULE_ALIAS_MISCDEV(FUSE_MINOR);
 MODULE_ALIAS("devname:fuse");
@@ -124,11 +125,11 @@ static void __fuse_put_request(struct fuse_req *req)
 	atomic_dec(&req->count);
 }
 
-static void fuse_req_init_context(struct fuse_req *req)
+static void fuse_req_init_context(struct fuse_conn *fc, struct fuse_req *req)
 {
 	req->in.h.uid = from_kuid_munged(&init_user_ns, current_fsuid());
 	req->in.h.gid = from_kgid_munged(&init_user_ns, current_fsgid());
-	req->in.h.pid = current->pid;
+	req->in.h.pid = pid_nr_ns(task_pid(current), fc->pid_ns);
 }
 
 static bool fuse_block_alloc(struct fuse_conn *fc, bool for_background)
@@ -168,7 +169,7 @@ static struct fuse_req *__fuse_get_req(struct fuse_conn *fc, unsigned npages,
 		goto out;
 	}
 
-	fuse_req_init_context(req);
+	fuse_req_init_context(fc, req);
 	req->waiting = 1;
 	req->background = for_background;
 	return req;
@@ -257,7 +258,7 @@ struct fuse_req *fuse_get_req_nofail_nopages(struct fuse_conn *fc,
 	if (!req)
 		req = get_reserved_req(fc, file);
 
-	fuse_req_init_context(req);
+	fuse_req_init_context(fc, req);
 	req->waiting = 1;
 	req->background = 0;
 	return req;
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index e8e47a6ab518..a3ded071e2c6 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -22,6 +22,7 @@
 #include <linux/rbtree.h>
 #include <linux/poll.h>
 #include <linux/workqueue.h>
+#include <linux/pid_namespace.h>
 
 /** Max number of pages that can be used in a single read request */
 #define FUSE_MAX_PAGES_PER_REQ 32
@@ -386,6 +387,9 @@ struct fuse_conn {
 	/** The group id for this mount */
 	kgid_t group_id;
 
+	/** The pid namespace for this mount */
+	struct pid_namespace *pid_ns;
+
 	/** The fuse mount flags for this mount */
 	unsigned flags;
 
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 03246cd9d47a..c6d8473b1a80 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -20,6 +20,7 @@
 #include <linux/random.h>
 #include <linux/sched.h>
 #include <linux/exportfs.h>
+#include <linux/pid_namespace.h>
 
 MODULE_AUTHOR("Miklos Szeredi <miklos-sUDqSbJrdHQHWmgEVkV9KA@public.gmane.org>");
 MODULE_DESCRIPTION("Filesystem in Userspace");
@@ -616,6 +617,7 @@ void fuse_conn_init(struct fuse_conn *fc)
 	fc->initialized = 0;
 	fc->attr_version = 1;
 	get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key));
+	fc->pid_ns = get_pid_ns(task_active_pid_ns(current));
 }
 EXPORT_SYMBOL_GPL(fuse_conn_init);
 
@@ -953,6 +955,7 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req)
 
 static void fuse_free_conn(struct fuse_conn *fc)
 {
+	put_pid_ns(fc->pid_ns);
 	kfree_rcu(fc, rcu);
 }
 
-- 
1.9.1


------------------------------------------------------------------------------
Want excitement?
Manually upgrade your production database.
When you want reliability, choose Perforce
Perforce version control. Predictably reliable.
http://pubads.g.doubleclick.net/gampad/clk?id=157508191&iu=/4140/ostg.clktrk

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 4/4] fuse: Add support for mounts from user namespaces
@ 2014-09-12 14:41   ` Seth Forshee
  0 siblings, 0 replies; 12+ messages in thread
From: Seth Forshee @ 2014-09-12 14:41 UTC (permalink / raw)
  To: Miklos Szeredi, Alexander Viro, Eric W. Biederman
  Cc: Serge Hallyn, fuse-devel, linux-kernel, linux-fsdevel, Seth Forshee

Update fuse to support mounts from within user namespaces. This
is mostly a matter of translating uids and gids into the
namespace of the process reading requests before handing the
requests off to userspace.

Due to security concerns the namespace used should be fixed,
otherwise a user might be able to pass the fuse fd to
init_user_ns and inject suid files owned by a user outside the
namespace in order to gain elevated privileges. For fuse we
stash current_user_ns() when a filesystem is first mounted and
abort the mount if this namespace is different than the one used
to open the fd passed in the mount options.

The allow_others options could also be a problem, as a userns
mount could bypass system policy for this option and thus open
the possiblity of DoS attacks. This is prevented by restricting
the scope of allow_other to apply only to that superblock's
userns and its children, giving the expected behavior within the
userns while preventing DoS attacks on more privileged contexts.

Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
Acked-by: Serge E. Hallyn <serge.hallyn@ubuntu.com>
---
 fs/fuse/dev.c    |  4 ++--
 fs/fuse/dir.c    | 46 +++++++++++++++++++++++++++++++++-------------
 fs/fuse/fuse_i.h |  4 ++++
 fs/fuse/inode.c  | 28 ++++++++++++++++++++--------
 4 files changed, 59 insertions(+), 23 deletions(-)

diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 839caebd34f1..03c8785ed731 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -127,8 +127,8 @@ static void __fuse_put_request(struct fuse_req *req)
 
 static void fuse_req_init_context(struct fuse_conn *fc, struct fuse_req *req)
 {
-	req->in.h.uid = from_kuid_munged(&init_user_ns, current_fsuid());
-	req->in.h.gid = from_kgid_munged(&init_user_ns, current_fsgid());
+	req->in.h.uid = from_kuid_munged(fc->user_ns, current_fsuid());
+	req->in.h.gid = from_kgid_munged(fc->user_ns, current_fsgid());
 	req->in.h.pid = pid_nr_ns(task_pid(current), fc->pid_ns);
 }
 
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index de1d84af9f7c..c0b9968db6a1 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -905,8 +905,8 @@ static void fuse_fillattr(struct inode *inode, struct fuse_attr *attr,
 	stat->ino = attr->ino;
 	stat->mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777);
 	stat->nlink = attr->nlink;
-	stat->uid = make_kuid(&init_user_ns, attr->uid);
-	stat->gid = make_kgid(&init_user_ns, attr->gid);
+	stat->uid = make_kuid(fc->user_ns, attr->uid);
+	stat->gid = make_kgid(fc->user_ns, attr->gid);
 	stat->rdev = inode->i_rdev;
 	stat->atime.tv_sec = attr->atime;
 	stat->atime.tv_nsec = attr->atimensec;
@@ -1085,12 +1085,20 @@ int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid,
  */
 int fuse_allow_current_process(struct fuse_conn *fc)
 {
-	const struct cred *cred;
+	const struct cred *cred = current_cred();
 
-	if (fc->flags & FUSE_ALLOW_OTHER)
-		return 1;
+	if (fc->flags & FUSE_ALLOW_OTHER) {
+		if (kuid_has_mapping(fc->user_ns, cred->euid) &&
+		    kuid_has_mapping(fc->user_ns, cred->suid) &&
+		    kuid_has_mapping(fc->user_ns, cred->uid) &&
+		    kgid_has_mapping(fc->user_ns, cred->egid) &&
+		    kgid_has_mapping(fc->user_ns, cred->sgid) &&
+		    kgid_has_mapping(fc->user_ns, cred->gid))
+			return 1;
+
+		return 0;
+	}
 
-	cred = current_cred();
 	if (uid_eq(cred->euid, fc->user_id) &&
 	    uid_eq(cred->suid, fc->user_id) &&
 	    uid_eq(cred->uid,  fc->user_id) &&
@@ -1556,17 +1564,25 @@ static bool update_mtime(unsigned ivalid, bool trust_local_mtime)
 	return true;
 }
 
-static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg,
-			   bool trust_local_cmtime)
+static int iattr_to_fattr(struct fuse_conn *fc, struct iattr *iattr,
+			   struct fuse_setattr_in *arg, bool trust_local_cmtime)
 {
 	unsigned ivalid = iattr->ia_valid;
 
 	if (ivalid & ATTR_MODE)
 		arg->valid |= FATTR_MODE,   arg->mode = iattr->ia_mode;
-	if (ivalid & ATTR_UID)
-		arg->valid |= FATTR_UID,    arg->uid = from_kuid(&init_user_ns, iattr->ia_uid);
-	if (ivalid & ATTR_GID)
-		arg->valid |= FATTR_GID,    arg->gid = from_kgid(&init_user_ns, iattr->ia_gid);
+	if (ivalid & ATTR_UID) {
+		arg->uid = from_kuid(fc->user_ns, iattr->ia_uid);
+		if (arg->uid == (uid_t)-1)
+			return -EINVAL;
+		arg->valid |= FATTR_UID;
+	}
+	if (ivalid & ATTR_GID) {
+		arg->gid = from_kgid(fc->user_ns, iattr->ia_gid);
+		if (arg->gid == (gid_t)-1)
+			return -EINVAL;
+		arg->valid |= FATTR_GID;
+	}
 	if (ivalid & ATTR_SIZE)
 		arg->valid |= FATTR_SIZE,   arg->size = iattr->ia_size;
 	if (ivalid & ATTR_ATIME) {
@@ -1588,6 +1604,8 @@ static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg,
 		arg->ctime = iattr->ia_ctime.tv_sec;
 		arg->ctimensec = iattr->ia_ctime.tv_nsec;
 	}
+
+	return 0;
 }
 
 /*
@@ -1741,7 +1759,9 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr,
 
 	memset(&inarg, 0, sizeof(inarg));
 	memset(&outarg, 0, sizeof(outarg));
-	iattr_to_fattr(attr, &inarg, trust_local_cmtime);
+	err = iattr_to_fattr(fc, attr, &inarg, trust_local_cmtime);
+	if (err)
+		goto error;
 	if (file) {
 		struct fuse_file *ff = file->private_data;
 		inarg.valid |= FATTR_FH;
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index a3ded071e2c6..2cfd0ca3407a 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -22,6 +22,7 @@
 #include <linux/rbtree.h>
 #include <linux/poll.h>
 #include <linux/workqueue.h>
+#include <linux/user_namespace.h>
 #include <linux/pid_namespace.h>
 
 /** Max number of pages that can be used in a single read request */
@@ -387,6 +388,9 @@ struct fuse_conn {
 	/** The group id for this mount */
 	kgid_t group_id;
 
+	/** The user namespace for this mount */
+	struct user_namespace *user_ns;
+
 	/** The pid namespace for this mount */
 	struct pid_namespace *pid_ns;
 
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index c6d8473b1a80..f3a3ded82f85 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -167,8 +167,8 @@ void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr,
 	inode->i_ino     = fuse_squash_ino(attr->ino);
 	inode->i_mode    = (inode->i_mode & S_IFMT) | (attr->mode & 07777);
 	set_nlink(inode, attr->nlink);
-	inode->i_uid     = make_kuid(&init_user_ns, attr->uid);
-	inode->i_gid     = make_kgid(&init_user_ns, attr->gid);
+	inode->i_uid     = make_kuid(fc->user_ns, attr->uid);
+	inode->i_gid     = make_kgid(fc->user_ns, attr->gid);
 	inode->i_blocks  = attr->blocks;
 	inode->i_atime.tv_sec   = attr->atime;
 	inode->i_atime.tv_nsec  = attr->atimensec;
@@ -496,6 +496,8 @@ static int parse_fuse_opt(char *opt, struct fuse_mount_data *d, int is_bdev)
 	memset(d, 0, sizeof(struct fuse_mount_data));
 	d->max_read = ~0;
 	d->blksize = FUSE_DEFAULT_BLKSIZE;
+	d->user_id = make_kuid(current_user_ns(), 0);
+	d->group_id = make_kgid(current_user_ns(), 0);
 
 	while ((p = strsep(&opt, ",")) != NULL) {
 		int token;
@@ -578,8 +580,10 @@ static int fuse_show_options(struct seq_file *m, struct dentry *root)
 	struct super_block *sb = root->d_sb;
 	struct fuse_conn *fc = get_fuse_conn_super(sb);
 
-	seq_printf(m, ",user_id=%u", from_kuid_munged(&init_user_ns, fc->user_id));
-	seq_printf(m, ",group_id=%u", from_kgid_munged(&init_user_ns, fc->group_id));
+	seq_printf(m, ",user_id=%u",
+		   from_kuid_munged(fc->user_ns, fc->user_id));
+	seq_printf(m, ",group_id=%u",
+		   from_kgid_munged(fc->user_ns, fc->group_id));
 	if (fc->flags & FUSE_DEFAULT_PERMISSIONS)
 		seq_puts(m, ",default_permissions");
 	if (fc->flags & FUSE_ALLOW_OTHER)
@@ -618,6 +622,7 @@ void fuse_conn_init(struct fuse_conn *fc)
 	fc->attr_version = 1;
 	get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key));
 	fc->pid_ns = get_pid_ns(task_active_pid_ns(current));
+	fc->user_ns = get_user_ns(current_user_ns());
 }
 EXPORT_SYMBOL_GPL(fuse_conn_init);
 
@@ -956,6 +961,7 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req)
 static void fuse_free_conn(struct fuse_conn *fc)
 {
 	put_pid_ns(fc->pid_ns);
+	put_user_ns(fc->user_ns);
 	kfree_rcu(fc, rcu);
 }
 
@@ -1042,8 +1048,14 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
 	if (!file)
 		goto err;
 
-	if ((file->f_op != &fuse_dev_operations) ||
-	    (file->f_cred->user_ns != &init_user_ns))
+	/*
+	 * Require mount to happen from the same user namespace which
+	 * opened /dev/fuse, otherwise users might be able to
+	 * elevate privileges by opening in init_user_ns then
+	 * mounting from a different namespace without MNT_NOSUID.
+	 */
+	if (file->f_op != &fuse_dev_operations ||
+	    file->f_cred->user_ns != current_user_ns())
 		goto err_fput;
 
 	fc = kmalloc(sizeof(*fc), GFP_KERNEL);
@@ -1157,7 +1169,7 @@ static void fuse_kill_sb_anon(struct super_block *sb)
 static struct file_system_type fuse_fs_type = {
 	.owner		= THIS_MODULE,
 	.name		= "fuse",
-	.fs_flags	= FS_HAS_SUBTYPE,
+	.fs_flags	= FS_HAS_SUBTYPE | FS_USERNS_MOUNT,
 	.mount		= fuse_mount,
 	.kill_sb	= fuse_kill_sb_anon,
 };
@@ -1189,7 +1201,7 @@ static struct file_system_type fuseblk_fs_type = {
 	.name		= "fuseblk",
 	.mount		= fuse_mount_blk,
 	.kill_sb	= fuse_kill_sb_blk,
-	.fs_flags	= FS_REQUIRES_DEV | FS_HAS_SUBTYPE,
+	.fs_flags	= FS_REQUIRES_DEV | FS_HAS_SUBTYPE | FS_USERNS_MOUNT,
 };
 MODULE_ALIAS_FS("fuseblk");
 
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 4/4] fuse: Add support for mounts from user namespaces
@ 2014-09-12 14:41   ` Seth Forshee
  0 siblings, 0 replies; 12+ messages in thread
From: Seth Forshee @ 2014-09-12 14:41 UTC (permalink / raw)
  To: Miklos Szeredi, Alexander Viro, Eric W. Biederman
  Cc: fuse-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Serge Hallyn,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Seth Forshee

Update fuse to support mounts from within user namespaces. This
is mostly a matter of translating uids and gids into the
namespace of the process reading requests before handing the
requests off to userspace.

Due to security concerns the namespace used should be fixed,
otherwise a user might be able to pass the fuse fd to
init_user_ns and inject suid files owned by a user outside the
namespace in order to gain elevated privileges. For fuse we
stash current_user_ns() when a filesystem is first mounted and
abort the mount if this namespace is different than the one used
to open the fd passed in the mount options.

The allow_others options could also be a problem, as a userns
mount could bypass system policy for this option and thus open
the possiblity of DoS attacks. This is prevented by restricting
the scope of allow_other to apply only to that superblock's
userns and its children, giving the expected behavior within the
userns while preventing DoS attacks on more privileged contexts.

Signed-off-by: Seth Forshee <seth.forshee-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
Acked-by: Serge E. Hallyn <serge.hallyn-GeWIH/nMZzLQT0dZR+AlfA@public.gmane.org>
---
 fs/fuse/dev.c    |  4 ++--
 fs/fuse/dir.c    | 46 +++++++++++++++++++++++++++++++++-------------
 fs/fuse/fuse_i.h |  4 ++++
 fs/fuse/inode.c  | 28 ++++++++++++++++++++--------
 4 files changed, 59 insertions(+), 23 deletions(-)

diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 839caebd34f1..03c8785ed731 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -127,8 +127,8 @@ static void __fuse_put_request(struct fuse_req *req)
 
 static void fuse_req_init_context(struct fuse_conn *fc, struct fuse_req *req)
 {
-	req->in.h.uid = from_kuid_munged(&init_user_ns, current_fsuid());
-	req->in.h.gid = from_kgid_munged(&init_user_ns, current_fsgid());
+	req->in.h.uid = from_kuid_munged(fc->user_ns, current_fsuid());
+	req->in.h.gid = from_kgid_munged(fc->user_ns, current_fsgid());
 	req->in.h.pid = pid_nr_ns(task_pid(current), fc->pid_ns);
 }
 
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index de1d84af9f7c..c0b9968db6a1 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -905,8 +905,8 @@ static void fuse_fillattr(struct inode *inode, struct fuse_attr *attr,
 	stat->ino = attr->ino;
 	stat->mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777);
 	stat->nlink = attr->nlink;
-	stat->uid = make_kuid(&init_user_ns, attr->uid);
-	stat->gid = make_kgid(&init_user_ns, attr->gid);
+	stat->uid = make_kuid(fc->user_ns, attr->uid);
+	stat->gid = make_kgid(fc->user_ns, attr->gid);
 	stat->rdev = inode->i_rdev;
 	stat->atime.tv_sec = attr->atime;
 	stat->atime.tv_nsec = attr->atimensec;
@@ -1085,12 +1085,20 @@ int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid,
  */
 int fuse_allow_current_process(struct fuse_conn *fc)
 {
-	const struct cred *cred;
+	const struct cred *cred = current_cred();
 
-	if (fc->flags & FUSE_ALLOW_OTHER)
-		return 1;
+	if (fc->flags & FUSE_ALLOW_OTHER) {
+		if (kuid_has_mapping(fc->user_ns, cred->euid) &&
+		    kuid_has_mapping(fc->user_ns, cred->suid) &&
+		    kuid_has_mapping(fc->user_ns, cred->uid) &&
+		    kgid_has_mapping(fc->user_ns, cred->egid) &&
+		    kgid_has_mapping(fc->user_ns, cred->sgid) &&
+		    kgid_has_mapping(fc->user_ns, cred->gid))
+			return 1;
+
+		return 0;
+	}
 
-	cred = current_cred();
 	if (uid_eq(cred->euid, fc->user_id) &&
 	    uid_eq(cred->suid, fc->user_id) &&
 	    uid_eq(cred->uid,  fc->user_id) &&
@@ -1556,17 +1564,25 @@ static bool update_mtime(unsigned ivalid, bool trust_local_mtime)
 	return true;
 }
 
-static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg,
-			   bool trust_local_cmtime)
+static int iattr_to_fattr(struct fuse_conn *fc, struct iattr *iattr,
+			   struct fuse_setattr_in *arg, bool trust_local_cmtime)
 {
 	unsigned ivalid = iattr->ia_valid;
 
 	if (ivalid & ATTR_MODE)
 		arg->valid |= FATTR_MODE,   arg->mode = iattr->ia_mode;
-	if (ivalid & ATTR_UID)
-		arg->valid |= FATTR_UID,    arg->uid = from_kuid(&init_user_ns, iattr->ia_uid);
-	if (ivalid & ATTR_GID)
-		arg->valid |= FATTR_GID,    arg->gid = from_kgid(&init_user_ns, iattr->ia_gid);
+	if (ivalid & ATTR_UID) {
+		arg->uid = from_kuid(fc->user_ns, iattr->ia_uid);
+		if (arg->uid == (uid_t)-1)
+			return -EINVAL;
+		arg->valid |= FATTR_UID;
+	}
+	if (ivalid & ATTR_GID) {
+		arg->gid = from_kgid(fc->user_ns, iattr->ia_gid);
+		if (arg->gid == (gid_t)-1)
+			return -EINVAL;
+		arg->valid |= FATTR_GID;
+	}
 	if (ivalid & ATTR_SIZE)
 		arg->valid |= FATTR_SIZE,   arg->size = iattr->ia_size;
 	if (ivalid & ATTR_ATIME) {
@@ -1588,6 +1604,8 @@ static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg,
 		arg->ctime = iattr->ia_ctime.tv_sec;
 		arg->ctimensec = iattr->ia_ctime.tv_nsec;
 	}
+
+	return 0;
 }
 
 /*
@@ -1741,7 +1759,9 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr,
 
 	memset(&inarg, 0, sizeof(inarg));
 	memset(&outarg, 0, sizeof(outarg));
-	iattr_to_fattr(attr, &inarg, trust_local_cmtime);
+	err = iattr_to_fattr(fc, attr, &inarg, trust_local_cmtime);
+	if (err)
+		goto error;
 	if (file) {
 		struct fuse_file *ff = file->private_data;
 		inarg.valid |= FATTR_FH;
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index a3ded071e2c6..2cfd0ca3407a 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -22,6 +22,7 @@
 #include <linux/rbtree.h>
 #include <linux/poll.h>
 #include <linux/workqueue.h>
+#include <linux/user_namespace.h>
 #include <linux/pid_namespace.h>
 
 /** Max number of pages that can be used in a single read request */
@@ -387,6 +388,9 @@ struct fuse_conn {
 	/** The group id for this mount */
 	kgid_t group_id;
 
+	/** The user namespace for this mount */
+	struct user_namespace *user_ns;
+
 	/** The pid namespace for this mount */
 	struct pid_namespace *pid_ns;
 
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index c6d8473b1a80..f3a3ded82f85 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -167,8 +167,8 @@ void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr,
 	inode->i_ino     = fuse_squash_ino(attr->ino);
 	inode->i_mode    = (inode->i_mode & S_IFMT) | (attr->mode & 07777);
 	set_nlink(inode, attr->nlink);
-	inode->i_uid     = make_kuid(&init_user_ns, attr->uid);
-	inode->i_gid     = make_kgid(&init_user_ns, attr->gid);
+	inode->i_uid     = make_kuid(fc->user_ns, attr->uid);
+	inode->i_gid     = make_kgid(fc->user_ns, attr->gid);
 	inode->i_blocks  = attr->blocks;
 	inode->i_atime.tv_sec   = attr->atime;
 	inode->i_atime.tv_nsec  = attr->atimensec;
@@ -496,6 +496,8 @@ static int parse_fuse_opt(char *opt, struct fuse_mount_data *d, int is_bdev)
 	memset(d, 0, sizeof(struct fuse_mount_data));
 	d->max_read = ~0;
 	d->blksize = FUSE_DEFAULT_BLKSIZE;
+	d->user_id = make_kuid(current_user_ns(), 0);
+	d->group_id = make_kgid(current_user_ns(), 0);
 
 	while ((p = strsep(&opt, ",")) != NULL) {
 		int token;
@@ -578,8 +580,10 @@ static int fuse_show_options(struct seq_file *m, struct dentry *root)
 	struct super_block *sb = root->d_sb;
 	struct fuse_conn *fc = get_fuse_conn_super(sb);
 
-	seq_printf(m, ",user_id=%u", from_kuid_munged(&init_user_ns, fc->user_id));
-	seq_printf(m, ",group_id=%u", from_kgid_munged(&init_user_ns, fc->group_id));
+	seq_printf(m, ",user_id=%u",
+		   from_kuid_munged(fc->user_ns, fc->user_id));
+	seq_printf(m, ",group_id=%u",
+		   from_kgid_munged(fc->user_ns, fc->group_id));
 	if (fc->flags & FUSE_DEFAULT_PERMISSIONS)
 		seq_puts(m, ",default_permissions");
 	if (fc->flags & FUSE_ALLOW_OTHER)
@@ -618,6 +622,7 @@ void fuse_conn_init(struct fuse_conn *fc)
 	fc->attr_version = 1;
 	get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key));
 	fc->pid_ns = get_pid_ns(task_active_pid_ns(current));
+	fc->user_ns = get_user_ns(current_user_ns());
 }
 EXPORT_SYMBOL_GPL(fuse_conn_init);
 
@@ -956,6 +961,7 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req)
 static void fuse_free_conn(struct fuse_conn *fc)
 {
 	put_pid_ns(fc->pid_ns);
+	put_user_ns(fc->user_ns);
 	kfree_rcu(fc, rcu);
 }
 
@@ -1042,8 +1048,14 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
 	if (!file)
 		goto err;
 
-	if ((file->f_op != &fuse_dev_operations) ||
-	    (file->f_cred->user_ns != &init_user_ns))
+	/*
+	 * Require mount to happen from the same user namespace which
+	 * opened /dev/fuse, otherwise users might be able to
+	 * elevate privileges by opening in init_user_ns then
+	 * mounting from a different namespace without MNT_NOSUID.
+	 */
+	if (file->f_op != &fuse_dev_operations ||
+	    file->f_cred->user_ns != current_user_ns())
 		goto err_fput;
 
 	fc = kmalloc(sizeof(*fc), GFP_KERNEL);
@@ -1157,7 +1169,7 @@ static void fuse_kill_sb_anon(struct super_block *sb)
 static struct file_system_type fuse_fs_type = {
 	.owner		= THIS_MODULE,
 	.name		= "fuse",
-	.fs_flags	= FS_HAS_SUBTYPE,
+	.fs_flags	= FS_HAS_SUBTYPE | FS_USERNS_MOUNT,
 	.mount		= fuse_mount,
 	.kill_sb	= fuse_kill_sb_anon,
 };
@@ -1189,7 +1201,7 @@ static struct file_system_type fuseblk_fs_type = {
 	.name		= "fuseblk",
 	.mount		= fuse_mount_blk,
 	.kill_sb	= fuse_kill_sb_blk,
-	.fs_flags	= FS_REQUIRES_DEV | FS_HAS_SUBTYPE,
+	.fs_flags	= FS_REQUIRES_DEV | FS_HAS_SUBTYPE | FS_USERNS_MOUNT,
 };
 MODULE_ALIAS_FS("fuseblk");
 
-- 
1.9.1


------------------------------------------------------------------------------
Want excitement?
Manually upgrade your production database.
When you want reliability, choose Perforce
Perforce version control. Predictably reliable.
http://pubads.g.doubleclick.net/gampad/clk?id=157508191&iu=/4140/ostg.clktrk

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH v3 2/4] vfs,userns: Ensure real root is always capable towards inodes
  2014-09-12 14:41   ` [PATCH v3 2/4] vfs, userns: " Seth Forshee
  (?)
@ 2014-09-12 17:13   ` Serge Hallyn
  -1 siblings, 0 replies; 12+ messages in thread
From: Serge Hallyn @ 2014-09-12 17:13 UTC (permalink / raw)
  To: Seth Forshee
  Cc: Miklos Szeredi, Alexander Viro, Eric W. Biederman, fuse-devel,
	linux-kernel, linux-fsdevel

Quoting Seth Forshee (seth.forshee@canonical.com):
> Currently root is restricted from performing some modifications
> to inodes whose owner is INVALID_UID or group is INVALID_GID
> because this id doesn't map into any user namespace. Add a
> special case to the relevant checks to make sure root is always
> capable of performing these operations.
> 
> Signed-off-by: Seth Forshee <seth.forshee@canonical.com>

(A case which was previously not possible.)

Acked-by: Serge E. Hallyn <serge.hallyn@ubuntu.com>

> ---
>  fs/inode.c          | 3 +++
>  kernel/capability.c | 6 +++++-
>  2 files changed, 8 insertions(+), 1 deletion(-)
> 
> diff --git a/fs/inode.c b/fs/inode.c
> index 26753ba7b6d6..1029320ff029 100644
> --- a/fs/inode.c
> +++ b/fs/inode.c
> @@ -1840,6 +1840,9 @@ bool inode_owner_or_capable(const struct inode *inode)
>  {
>  	struct user_namespace *ns;
>  
> +	if (capable(CAP_SYS_ADMIN))
> +		return true;
> +
>  	if (uid_eq(current_fsuid(), inode->i_uid))
>  		return true;
>  
> diff --git a/kernel/capability.c b/kernel/capability.c
> index 989f5bfc57dc..a472eaa52b6a 100644
> --- a/kernel/capability.c
> +++ b/kernel/capability.c
> @@ -438,8 +438,12 @@ EXPORT_SYMBOL(capable);
>   */
>  bool capable_wrt_inode_uidgid(const struct inode *inode, int cap)
>  {
> -	struct user_namespace *ns = current_user_ns();
> +	struct user_namespace *ns;
>  
> +	if (capable(CAP_SYS_ADMIN))
> +		return true;
> +
> +	ns = current_user_ns();
>  	return ns_capable(ns, cap) && kuid_has_mapping(ns, inode->i_uid) &&
>  		kgid_has_mapping(ns, inode->i_gid);
>  }
> -- 
> 1.9.1
> 

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v3 0/4] fuse: Add support for mounts from pid/user namespaces
  2014-09-12 14:41 [PATCH v3 0/4] fuse: Add support for mounts from pid/user namespaces Seth Forshee
                   ` (3 preceding siblings ...)
  2014-09-12 14:41   ` Seth Forshee
@ 2014-09-23 14:28 ` Seth Forshee
  2014-09-23 17:08   ` Serge E. Hallyn
  4 siblings, 1 reply; 12+ messages in thread
From: Seth Forshee @ 2014-09-23 14:28 UTC (permalink / raw)
  To: Miklos Szeredi, Alexander Viro, Eric W. Biederman
  Cc: Serge Hallyn, fuse-devel, linux-kernel, linux-fsdevel

On Fri, Sep 12, 2014 at 09:41:41AM -0500, Seth Forshee wrote:
> Third round of patches for making it possible to mount with fuse from
> within user namespaces. The only change since v2 is the addition of a
> patch to ensure real root is capable towards inodes whose uid/gid is
> invalid.

It's been nearly two weeks (three from the v2 patches) without any
feedback besides Serge's acks. Any other comments or objections? Anyone
planning to pick these up?

Thanks,
Seth


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v3 0/4] fuse: Add support for mounts from pid/user namespaces
  2014-09-23 14:28 ` [PATCH v3 0/4] fuse: Add support for mounts from pid/user namespaces Seth Forshee
@ 2014-09-23 17:08   ` Serge E. Hallyn
  0 siblings, 0 replies; 12+ messages in thread
From: Serge E. Hallyn @ 2014-09-23 17:08 UTC (permalink / raw)
  To: Miklos Szeredi, Alexander Viro, Eric W. Biederman, Serge Hallyn,
	fuse-devel, linux-kernel, linux-fsdevel

Quoting Seth Forshee (seth.forshee@canonical.com):
> On Fri, Sep 12, 2014 at 09:41:41AM -0500, Seth Forshee wrote:
> > Third round of patches for making it possible to mount with fuse from
> > within user namespaces. The only change since v2 is the addition of a
> > patch to ensure real root is capable towards inodes whose uid/gid is
> > invalid.
> 
> It's been nearly two weeks (three from the v2 patches) without any
> feedback besides Serge's acks. Any other comments or objections? Anyone
> planning to pick these up?
> 
> Thanks,
> Seth

FWIW I was able to mount ext2, ext4, and iso filesystems inside an
unprivileged container with these patches.  Thanks much!

-serge

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2014-09-23 17:34 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-09-12 14:41 [PATCH v3 0/4] fuse: Add support for mounts from pid/user namespaces Seth Forshee
2014-09-12 14:41 ` [PATCH v3 1/4] vfs: Check for invalid i_uid in may_follow_link() Seth Forshee
2014-09-12 14:41   ` Seth Forshee
2014-09-12 14:41 ` [PATCH v3 2/4] vfs,userns: Ensure real root is always capable towards inodes Seth Forshee
2014-09-12 14:41   ` [PATCH v3 2/4] vfs, userns: " Seth Forshee
2014-09-12 17:13   ` [PATCH v3 2/4] vfs,userns: " Serge Hallyn
2014-09-12 14:41 ` [PATCH v3 3/4] fuse: Translate pids passed to userspace into pid namespaces Seth Forshee
2014-09-12 14:41   ` Seth Forshee
2014-09-12 14:41 ` [PATCH v3 4/4] fuse: Add support for mounts from user namespaces Seth Forshee
2014-09-12 14:41   ` Seth Forshee
2014-09-23 14:28 ` [PATCH v3 0/4] fuse: Add support for mounts from pid/user namespaces Seth Forshee
2014-09-23 17:08   ` Serge E. Hallyn

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.