[CRIU] [PATCH 2/2] unix: switch into the root mount namespace before cleaning stale sockets

Andrei Vagin avagin at openvz.org
Thu Oct 20 12:07:00 PDT 2016


From: Andrei Vagin <avagin at virtuozzo.com>

Signed-off-by: Andrei Vagin <avagin at virtuozzo.com>
---
 criu/sk-unix.c | 63 +++++++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 45 insertions(+), 18 deletions(-)

diff --git a/criu/sk-unix.c b/criu/sk-unix.c
index 39cc6c0..f0ee9fa 100644
--- a/criu/sk-unix.c
+++ b/criu/sk-unix.c
@@ -831,8 +831,13 @@ static int shutdown_unix_sk(int sk, struct unix_sk_info *ui)
 	return 0;
 }
 
-static void revert_unix_sk_cwd(int *prev_cwd_fd)
+static void revert_unix_sk_cwd(int *prev_cwd_fd, int *root_fd)
 {
+	if (*root_fd >= 0) {
+		if (fchdir(*root_fd) || chroot("."))
+			pr_perror("Can't revert root directory");
+		close_safe(root_fd);
+	}
 	if (prev_cwd_fd && *prev_cwd_fd >= 0) {
 		if (fchdir(*prev_cwd_fd))
 			pr_perror("Can't revert working dir");
@@ -843,14 +848,36 @@ static void revert_unix_sk_cwd(int *prev_cwd_fd)
 	}
 }
 
-static int prep_unix_sk_cwd(struct unix_sk_info *ui, int *prev_cwd_fd)
+static int prep_unix_sk_cwd(struct unix_sk_info *ui, int *prev_cwd_fd, int *prev_root_fd)
 {
-	if (ui->name_dir) {
-		*prev_cwd_fd = open(".", O_RDONLY);
-		if (*prev_cwd_fd < 0) {
-			pr_err("Can't open current dir\n");
+	static struct ns_id *root = NULL;
+
+	*prev_cwd_fd = open(".", O_RDONLY);
+	if (*prev_cwd_fd < 0) {
+		pr_err("Can't open current dir\n");
+		return -1;
+	}
+
+	if (prev_root_fd && (root_ns_mask & CLONE_NEWNS)) {
+		if (root == NULL)
+			root = lookup_ns_by_id(root_item->ids->mnt_ns_id, &mnt_ns_desc);
+		*prev_root_fd = open("/", O_RDONLY);
+		if (*prev_root_fd < 0) {
+			pr_err("Can't open current root\n");
+			return -1;
+		}
+
+		if (fchdir(root->mnt.root_fd)) {
+			pr_perror("Unable to change current working dir");
 			return -1;
 		}
+		if (chroot(".")) {
+			pr_perror("Unable to change root directory");
+			return -1;
+		}
+	}
+
+	if (ui->name_dir) {
 		if (chdir(ui->name_dir)) {
 			pr_perror("Can't change working dir %s",
 				  ui->name_dir);
@@ -859,8 +886,8 @@ static int prep_unix_sk_cwd(struct unix_sk_info *ui, int *prev_cwd_fd)
 			return -1;
 		}
 		pr_debug("Change working dir to %s\n", ui->name_dir);
-	} else
-		*prev_cwd_fd = -1;
+	}
+
 	return 0;
 }
 
@@ -869,7 +896,7 @@ static int post_open_unix_sk(struct file_desc *d, int fd)
 	struct unix_sk_info *ui;
 	struct unix_sk_info *peer;
 	struct sockaddr_un addr;
-	int cwd_fd = -1;
+	int cwd_fd = -1, root_fd = -1;
 
 	ui = container_of(d, struct unix_sk_info, d);
 	if (ui->flags & (USK_PAIR_MASTER | USK_PAIR_SLAVE))
@@ -896,18 +923,18 @@ static int post_open_unix_sk(struct file_desc *d, int fd)
 
 	pr_info("\tConnect %#x to %#x\n", ui->ue->ino, peer->ue->ino);
 
-	if (prep_unix_sk_cwd(peer, &cwd_fd))
+	if (prep_unix_sk_cwd(peer, &cwd_fd, NULL))
 		return -1;
 
 	if (connect(fd, (struct sockaddr *)&addr,
 				sizeof(addr.sun_family) +
 				peer->ue->name.len) < 0) {
-		revert_unix_sk_cwd(&cwd_fd);
+		revert_unix_sk_cwd(&cwd_fd, &root_fd);
 		pr_perror("Can't connect %#x socket", ui->ue->ino);
 		return -1;
 	}
 
-	revert_unix_sk_cwd(&cwd_fd);
+	revert_unix_sk_cwd(&cwd_fd, &root_fd);
 
 	if (peer->queuer == ui->ue->ino && restore_sk_queue(fd, peer->ue->id))
 		return -1;
@@ -927,7 +954,7 @@ static int post_open_unix_sk(struct file_desc *d, int fd)
 static int bind_unix_sk(int sk, struct unix_sk_info *ui)
 {
 	struct sockaddr_un addr;
-	int cwd_fd = -1;
+	int cwd_fd = -1, root_fd = -1;
 	int ret = -1;
 
 	if ((ui->ue->type == SOCK_STREAM) && (ui->ue->state == TCP_ESTABLISHED)) {
@@ -946,7 +973,7 @@ static int bind_unix_sk(int sk, struct unix_sk_info *ui)
 	addr.sun_family = AF_UNIX;
 	memcpy(&addr.sun_path, ui->name, ui->ue->name.len);
 
-	if (prep_unix_sk_cwd(ui, &cwd_fd))
+	if (prep_unix_sk_cwd(ui, &cwd_fd, NULL))
 		return -1;
 
 	if (ui->ue->name.len) {
@@ -1030,7 +1057,7 @@ static int bind_unix_sk(int sk, struct unix_sk_info *ui)
 
 	ret = 0;
 done:
-	revert_unix_sk_cwd(&cwd_fd);
+	revert_unix_sk_cwd(&cwd_fd, &root_fd);
 	return ret;
 }
 
@@ -1306,12 +1333,12 @@ static struct file_desc_ops unix_desc_ops = {
  */
 static void unlink_stale(struct unix_sk_info *ui)
 {
-	int ret, cwd_fd;
+	int ret, cwd_fd = -1, root_fd = -1;
 
 	if (ui->name[0] == '\0' || (ui->ue->uflags & USK_EXTERN))
 		return;
 
-	if (prep_unix_sk_cwd(ui, &cwd_fd))
+	if (prep_unix_sk_cwd(ui, &cwd_fd, &root_fd))
 		return;
 
 	ret = unlinkat(AT_FDCWD, ui->name, 0) ? -1 : 0;
@@ -1321,7 +1348,7 @@ static void unlink_stale(struct unix_sk_info *ui)
 			ui->name ? (ui->name[0] ? ui->name : &ui->name[1]) : "-",
 			ui->name_dir ? ui->name_dir : "-");
 	}
-	revert_unix_sk_cwd(&cwd_fd);
+	revert_unix_sk_cwd(&cwd_fd, &root_fd);
 }
 
 static int resolve_unix_peers(void *unused);
-- 
2.7.4



More information about the CRIU mailing list