[CRIU] [PATCH] sk-unix: Don't affect cwd for relative named sockets

Cyrill Gorcunov gorcunov at openvz.org
Wed Oct 7 02:59:45 PDT 2015


When we restore sockets with relative names we change
current working directory into the one provided by
socket image data. This actually affects current
criu state because the rest of code doesn't know
about such tricks and may rely on working dir
consistency.

So remember the current working dir and restore it
back once socket cwd operations are complete.

Signed-off-by: Cyrill Gorcunov <gorcunov at openvz.org>
---
 sk-unix.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 56 insertions(+), 13 deletions(-)

diff --git a/sk-unix.c b/sk-unix.c
index def14fd473a8..52297ea0bca6 100644
--- a/sk-unix.c
+++ b/sk-unix.c
@@ -825,21 +825,48 @@ static int shutdown_unix_sk(int sk, struct unix_sk_info *ui)
 	return 0;
 }
 
-static int prep_unix_sk_cwd(struct unix_sk_info *ui)
+static int revert_unix_sk_cwd(char **prev_cwd)
+{
+	int ret = 0;
+
+	if (prev_cwd && *prev_cwd) {
+		if (chdir(*prev_cwd)) {
+			pr_perror("Can't revert working dir to %s\n",
+				  *prev_cwd);
+			ret = -errno;
+		}
+		pr_debug("Revert working dir to %s\n", *prev_cwd);
+		xfree(*prev_cwd);
+		*prev_cwd = NULL;
+	}
+
+	return ret;
+}
+
+static int prep_unix_sk_cwd(struct unix_sk_info *ui, char **prev_cwd)
 {
 	if (ui->name_dir) {
+		*prev_cwd = get_current_dir_name();
+		if (!*prev_cwd) {
+			pr_err("Can't allocate current dir\n");
+			return -1;
+		}
 		if (chdir(ui->name_dir)) {
 			pr_perror("Can't change working dir %s\n",
 				  ui->name_dir);
+			revert_unix_sk_cwd(prev_cwd);
 			return -1;
 		}
-		pr_debug("Change working dir to %s\n", ui->name_dir);
-	}
+		pr_debug("Change working dir to %s (was %s)\n",
+			 ui->name_dir, *prev_cwd);
+	} else
+		*prev_cwd = NULL;
 	return 0;
 }
 
 static int post_open_unix_sk(struct file_desc *d, int fd)
 {
+	char *current_cwd = NULL;
 	struct unix_sk_info *ui;
 	struct unix_sk_info *peer;
 	struct sockaddr_un addr;
@@ -869,16 +896,19 @@ 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))
+	if (prep_unix_sk_cwd(peer, &current_cwd))
 		return -1;
 
 	if (connect(fd, (struct sockaddr *)&addr,
 				sizeof(addr.sun_family) +
 				peer->ue->name.len) < 0) {
+		revert_unix_sk_cwd(&current_cwd);
 		pr_perror("Can't connect %#x socket", ui->ue->ino);
 		return -1;
 	}
 
+	revert_unix_sk_cwd(&current_cwd);
+
 	if (peer->queuer == ui->ue->ino && restore_sk_queue(fd, peer->ue->id))
 		return -1;
 
@@ -896,9 +926,11 @@ static int post_open_unix_sk(struct file_desc *d, int fd)
 
 static int bind_unix_sk(int sk, struct unix_sk_info *ui)
 {
+	char *current_cwd = NULL;
 	struct sockaddr_un addr;
+	int ret = -1;
 
-	if ((ui->ue->type == SOCK_STREAM) && (ui->ue->state == TCP_ESTABLISHED))
+	if ((ui->ue->type == SOCK_STREAM) && (ui->ue->state == TCP_ESTABLISHED)) {
 		/*
 		 * FIXME this can be done, but for doing this properly we
 		 * need to bind socket to its name, then rename one to
@@ -906,19 +938,21 @@ static int bind_unix_sk(int sk, struct unix_sk_info *ui)
 		 * restored we should walk those temp names and rename
 		 * some of them back to real ones.
 		 */
+		ret = 0;
 		goto done;
+	}
 
 	memset(&addr, 0, sizeof(addr));
 	addr.sun_family = AF_UNIX;
 	memcpy(&addr.sun_path, ui->name, ui->ue->name.len);
 
-	if (prep_unix_sk_cwd(ui))
+	if (prep_unix_sk_cwd(ui, &current_cwd))
 		return -1;
 
 	if (bind(sk, (struct sockaddr *)&addr,
 				sizeof(addr.sun_family) + ui->ue->name.len)) {
 		pr_perror("Can't bind socket");
-		return -1;
+		goto done;
 	}
 
 	if (ui->ue->name.len && *ui->name && ui->ue->file_perms) {
@@ -927,7 +961,7 @@ static int bind_unix_sk(int sk, struct unix_sk_info *ui)
 
 		if (ui->ue->name.len >= sizeof(fname)) {
 			pr_err("The file name is too long\n");
-			return -1;
+			goto done;
 		}
 
 		memcpy(fname, ui->name, ui->ue->name.len);
@@ -935,19 +969,22 @@ static int bind_unix_sk(int sk, struct unix_sk_info *ui)
 
 		if (fchownat(AT_FDCWD, fname, perms->uid, perms->gid, 0) == -1) {
 			pr_perror("Unable to change file owner and group");
-			return -1;
+			goto done;
 		}
 
 		if (fchmodat(AT_FDCWD, fname, perms->mode, 0) == -1) {
 			pr_perror("Unable to change file mode bits");
-			return -1;
+			goto done;
 		}
 	}
 
 	if (ui->ue->state != TCP_LISTEN)
 		futex_set_and_wake(&ui->prepared, 1);
+
+	ret = 0;
 done:
-	return 0;
+	revert_unix_sk_cwd(&current_cwd);
+	return ret;
 }
 
 static int unixsk_should_open_transport(FdinfoEntry *fe,
@@ -1198,13 +1235,19 @@ static struct file_desc_ops unix_desc_ops = {
  */
 static int unlink_stale(struct unix_sk_info *ui)
 {
+	char *current_cwd = NULL;
+	int ret;
+
 	if (ui->name[0] == '\0' || (ui->ue->uflags & USK_EXTERN))
 		return 0;
 
-	if (prep_unix_sk_cwd(ui))
+	if (prep_unix_sk_cwd(ui, &current_cwd))
 		return -1;
 
-	return unlinkat(AT_FDCWD, ui->name, 0) ? -1 : 0;
+	ret = unlinkat(AT_FDCWD, ui->name, 0) ? -1 : 0;
+	revert_unix_sk_cwd(&current_cwd);
+
+	return ret;
 }
 
 static int collect_one_unixsk(void *o, ProtobufCMessage *base)
-- 
2.4.3



More information about the CRIU mailing list