[v4,09/31] ns: Implement target_userns_{u, g}id() and root_userns_{u, g}id()

Submitted by Kirill Tkhai on Feb. 22, 2017, 11:31 a.m.

Details

Message ID 148776310745.17334.11157297643966401617.stgit@localhost.localdomain
State New
Series "Nested user namespaces support"
Headers show

Commit Message

Kirill Tkhai Feb. 22, 2017, 11:31 a.m.
Add primitives for converting xids from NS_ROOT to custom
NS_OTHER, and vice versa.

v4: Fixed erratum in root_userns_gid()

Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com>
---
 criu/include/namespaces.h |    7 ++++++
 criu/namespaces.c         |   53 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 59 insertions(+), 1 deletion(-)

Patch hide | download patch | download mbox

diff --git a/criu/include/namespaces.h b/criu/include/namespaces.h
index 86a7a15b8..0a8002ea6 100644
--- a/criu/include/namespaces.h
+++ b/criu/include/namespaces.h
@@ -121,6 +121,7 @@  struct ns_id {
 	};
 };
 extern struct ns_id *ns_ids;
+extern struct ns_id *root_user_ns;
 
 #define NS_DESC_ENTRY(_cflag, _str)			\
 	{						\
@@ -164,6 +165,12 @@  extern int stop_usernsd(void);
 extern uid_t userns_uid(uid_t uid);
 extern gid_t userns_gid(gid_t gid);
 
+extern unsigned int target_userns_uid(struct ns_id *ns, unsigned int uid);
+extern unsigned int target_userns_gid(struct ns_id *ns, unsigned int gid);
+
+extern unsigned int root_userns_uid(struct ns_id *ns, unsigned int uid);
+extern unsigned int root_userns_gid(struct ns_id *ns, unsigned int gid);
+
 extern void free_userns_maps(void);
 extern int join_ns_add(const char *type, char *ns_file, char *extra_opts);
 extern int check_namespace_opts(void);
diff --git a/criu/namespaces.c b/criu/namespaces.c
index 9946f4810..6f4bf01d4 100644
--- a/criu/namespaces.c
+++ b/criu/namespaces.c
@@ -753,6 +753,7 @@  static int set_ns_hookups(struct ns_id *ns)
 	return ret;
 }
 
+struct ns_id *root_user_ns = NULL;
 /* Mapping NS_ROOT to NS_CRIU */
 static UsernsEntry *userns_entry;
 
@@ -815,6 +816,54 @@  gid_t userns_gid(gid_t gid)
 	return child_userns_xid(gid, e->gid_map, e->n_gid_map);
 }
 
+/* Convert uid from NS_ROOT down to its representation in NS_OTHER */
+unsigned int target_userns_uid(struct ns_id *ns, unsigned int uid)
+{
+	if (!(root_ns_mask & CLONE_NEWUSER))
+		return uid;
+	if (ns == root_user_ns)
+		return uid;
+	/* User ns max nesting level is only 32 */
+	uid = target_userns_uid(ns->parent, uid);
+	return child_userns_xid(uid, ns->user.e->uid_map, ns->user.e->n_uid_map);
+}
+
+/* Convert gid from NS_ROOT down to its representation in NS_OTHER */
+unsigned int target_userns_gid(struct ns_id *ns, unsigned int gid)
+{
+	if (!(root_ns_mask & CLONE_NEWUSER))
+		return gid;
+	if (ns == root_user_ns)
+		return gid;
+	/* User ns max nesting level is only 32 */
+	gid = target_userns_gid(ns->parent, gid);
+	return child_userns_xid(gid, ns->user.e->gid_map, ns->user.e->n_gid_map);
+}
+
+/* Convert uid from NS_OTHER ns up to its representation in NS_ROOT */
+unsigned int root_userns_uid(struct ns_id *ns, unsigned int uid)
+{
+	if (!(root_ns_mask & CLONE_NEWUSER))
+		return uid;
+	while (ns != root_user_ns) {
+		uid = parent_userns_uid(ns->user.e, uid);
+		ns = ns->parent;
+	}
+	return uid;
+}
+
+/* Convert gid from NS_OTHER ns up to its representation in NS_ROOT */
+unsigned int root_userns_gid(struct ns_id *ns, unsigned int gid)
+{
+	if (!(root_ns_mask & CLONE_NEWUSER))
+		return gid;
+	while (ns != root_user_ns) {
+		gid = parent_userns_gid(ns->user.e, gid);
+		ns = ns->parent;
+	}
+	return gid;
+}
+
 static int parse_id_map(pid_t pid, char *name, UidGidExtent ***pb_exts)
 {
 	UidGidExtent *extents = NULL;
@@ -890,8 +939,10 @@  int collect_user_ns(struct ns_id *ns, void *oarg)
 		return -1;
 	userns_entry__init(e);
 	ns->user.e = e;
-	if (ns->type == NS_ROOT)
+	if (ns->type == NS_ROOT) {
 		userns_entry = e;
+		root_user_ns = ns;
+	}
 	/*
 	 * User namespace is dumped before files to get uid and gid
 	 * mappings, which are used for convirting local id-s to