[v2,34/36] ns: Convert task cred's xids to target user ns

Submitted by Kirill Tkhai on Feb. 3, 2017, 4:16 p.m.

Details

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

Commit Message

Kirill Tkhai Feb. 3, 2017, 4:16 p.m.
xids are saved according to NS_ROOT, while in pie
we may set them in their target user_ns. So, let's
convert them. Look at the commentary in the code,
while we save them in NS_ROOT.

Also, small cleanup: use creds instead of args->creds
for caps.

Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com>
---
 criu/cr-restore.c   |   48 +++++++++++++++++++++++++++++++++++++++++-------
 criu/pie/restorer.c |   41 +++++++++++++++++++++++++----------------
 2 files changed, 66 insertions(+), 23 deletions(-)

Patch hide | download patch | download mbox

diff --git a/criu/cr-restore.c b/criu/cr-restore.c
index 96e554338..c03b88b41 100644
--- a/criu/cr-restore.c
+++ b/criu/cr-restore.c
@@ -2714,6 +2714,9 @@  rst_prep_creds_args(CredsEntry *ce, unsigned long *prev_pos)
 {
 	unsigned long this_pos;
 	struct thread_creds_args *args;
+	struct ns_id *ns = NULL;
+	CredsEntry *creds;
+	int i;
 
 	if (!verify_cap_size(ce)) {
 		pr_err("Caps size mismatch %d %d %d %d\n",
@@ -2722,6 +2725,16 @@  rst_prep_creds_args(CredsEntry *ce, unsigned long *prev_pos)
 		return ERR_PTR(-EINVAL);
 	}
 
+	if (current->ids->has_user_ns_id) {
+		ns = lookup_ns_by_id(current->ids->user_ns_id, &user_ns_desc);
+		if (!ns) {
+			pr_err("Can't find user_ns\n");
+			return ERR_PTR(-ENOENT);
+		}
+		if (ns->type == NS_ROOT)
+			ns = NULL;
+	}
+
 	this_pos = rst_mem_align_cpos(RM_PRIVATE);
 
 	args = rst_mem_alloc(sizeof(*args), RM_PRIVATE);
@@ -2729,7 +2742,8 @@  rst_prep_creds_args(CredsEntry *ce, unsigned long *prev_pos)
 		return ERR_PTR(-ENOMEM);
 
 	args->cap_last_cap = kdat.last_cap;
-	memcpy(&args->creds, ce, sizeof(args->creds));
+	creds = &args->creds;
+	memcpy(creds, ce, sizeof(*creds));
 
 	if (ce->lsm_profile || opts.lsm_supplied) {
 		char *rendered = NULL, *profile;
@@ -2770,12 +2784,12 @@  rst_prep_creds_args(CredsEntry *ce, unsigned long *prev_pos)
 	/*
 	 * Zap fields which we can't use.
 	 */
-	args->creds.cap_inh = NULL;
-	args->creds.cap_eff = NULL;
-	args->creds.cap_prm = NULL;
-	args->creds.cap_bnd = NULL;
-	args->creds.groups = NULL;
-	args->creds.lsm_profile = NULL;
+	creds->cap_inh = NULL;
+	creds->cap_eff = NULL;
+	creds->cap_prm = NULL;
+	creds->cap_bnd = NULL;
+	creds->groups = NULL;
+	creds->lsm_profile = NULL;
 
 	memcpy(args->cap_inh, ce->cap_inh, sizeof(args->cap_inh));
 	memcpy(args->cap_eff, ce->cap_eff, sizeof(args->cap_eff));
@@ -2796,6 +2810,26 @@  rst_prep_creds_args(CredsEntry *ce, unsigned long *prev_pos)
 		args->groups = NULL;
 		args->mem_groups_pos = 0;
 	}
+	if (ns) {
+		/*
+		 * Note, that some of xids may not have mapping
+		 * in target user namespace. This is the reason
+		 * why we dump xids from NS_ROOT. Ideally, it's
+		 * need to restore a xid in the lowest user_ns,
+		 * where it's mapped, but it's not implemented
+		 * for now.
+		 */
+		creds->uid = target_userns_uid(ns, creds->uid);
+		creds->gid = target_userns_gid(ns, creds->gid);
+		creds->euid = target_userns_uid(ns, creds->euid);
+		creds->egid = target_userns_gid(ns, creds->egid);
+		creds->suid = target_userns_uid(ns, creds->suid);
+		creds->sgid = target_userns_gid(ns, creds->sgid);
+		creds->fsuid = target_userns_uid(ns, creds->fsuid);
+		creds->fsgid = target_userns_gid(ns, creds->fsgid);
+		for (i = 0; i < ce->n_groups; i++)
+			args->groups[i] = target_userns_uid(ns, args->groups[i]);
+	}
 
 	args->mem_pos_next = 0;
 
diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c
index 978050e50..ae2f70f9f 100644
--- a/criu/pie/restorer.c
+++ b/criu/pie/restorer.c
@@ -46,6 +46,7 @@ 
 
 #include "shmem.h"
 #include "restorer.h"
+#include "namespaces.h"
 
 #ifndef PR_SET_PDEATHSIG
 #define PR_SET_PDEATHSIG 1
@@ -191,28 +192,36 @@  static int restore_creds(struct thread_creds_args *args, int procfd)
 	 * to override the setresXid settings.
 	 */
 
-	ret = sys_setresuid(ce->uid, ce->euid, ce->suid);
-	if (ret) {
-		pr_err("Unable to set real, effective and saved user ID: %d\n", ret);
-		return -1;
+	if (ce->uid != NS_INVALID_XID || ce->euid != NS_INVALID_XID || ce->suid != NS_INVALID_XID) {
+		ret = sys_setresuid(ce->uid, ce->euid, ce->suid);
+		if (ret) {
+			pr_err("Unable to set real, effective and saved user ID: %d\n", ret);
+			return -1;
+		}
 	}
 
-	sys_setfsuid(ce->fsuid);
-	if (sys_setfsuid(-1) != ce->fsuid) {
-		pr_err("Unable to set fsuid\n");
-		return -1;
+	if (ce->fsuid != NS_INVALID_XID) {
+		sys_setfsuid(ce->fsuid);
+		if (sys_setfsuid(-1) != ce->fsuid) {
+			pr_err("Unable to set fsuid\n");
+			return -1;
+		}
 	}
 
-	ret = sys_setresgid(ce->gid, ce->egid, ce->sgid);
-	if (ret) {
-		pr_err("Unable to set real, effective and saved group ID: %d\n", ret);
-		return -1;
+	if (ce->gid != NS_INVALID_XID || ce->egid != NS_INVALID_XID || ce->sgid != NS_INVALID_XID) {
+		ret = sys_setresgid(ce->gid, ce->egid, ce->sgid);
+		if (ret) {
+			pr_err("Unable to set real, effective and saved group ID: %d\n", ret);
+			return -1;
+		}
 	}
 
-	sys_setfsgid(ce->fsgid);
-	if (sys_setfsgid(-1) != ce->fsgid) {
-		pr_err("Unable to set fsgid\n");
-		return -1;
+	if (ce->fsgid != NS_INVALID_XID) {
+		sys_setfsgid(ce->fsgid);
+		if (sys_setfsgid(-1) != ce->fsgid) {
+			pr_err("Unable to set fsgid\n");
+			return -1;
+		}
 	}
 
 	/*