[6/6] unix: Fix path resolving for unix sockets

Submitted by Cyrill Gorcunov on Aug. 31, 2018, 10:10 a.m.

Details

Message ID 20180831101004.26940-7-gorcunov@gmail.com
State New
Series "unix: Setup sysct and fix path resolving"
Headers show

Commit Message

Cyrill Gorcunov Aug. 31, 2018, 10:10 a.m.
We should use cr_set_root and cr_restore_root helpers when
fetching paths via procfs here. Otherwise we might fetch
a path which is not resolvable on restore.

In particular we hit a problem with mysql process been
running inside container where the socket /var/run/mysqld/mysqld.sock
has been sitting in own submount namespace.

Signed-off-by: Cyrill Gorcunov <gorcunov@virtuozzo.com>
---
 criu/sk-unix.c | 29 ++++++++++++++++++++++++++---
 1 file changed, 26 insertions(+), 3 deletions(-)

Patch hide | download patch | download mbox

diff --git a/criu/sk-unix.c b/criu/sk-unix.c
index 616f683a8d33..bc293f8f013f 100644
--- a/criu/sk-unix.c
+++ b/criu/sk-unix.c
@@ -289,8 +289,9 @@  static int resolve_rel_name(uint32_t id, struct unix_sk_desc *sk, const struct f
 
 	for (i = 0; i < ARRAY_SIZE(dirs); i++) {
 		char dir[PATH_MAX], path[PATH_MAX];
+		int ret, root_fd;
 		struct stat st;
-		int ret;
+		int errno_save;
 
 		snprintf(path, sizeof(path), "/proc/%d/%s", p->pid, dirs[i]);
 		ret = readlink(path, dir, sizeof(dir));
@@ -300,13 +301,23 @@  static int resolve_rel_name(uint32_t id, struct unix_sk_desc *sk, const struct f
 		}
 		dir[ret] = 0;
 
+		if (cr_set_root(mntns_root, &root_fd))
+			goto err;
+
 		if (snprintf(path, sizeof(path), ".%s/%s", dir, sk->name) >= sizeof(path)) {
 			pr_err("The path .%s/%s is too long\n", dir, sk->name);
 			goto err;
 		}
-		if (fstatat(mntns_root, path, &st, 0)) {
-			if (errno == ENOENT)
+
+		ret = fstatat(mntns_root, path, &st, 0);
+		errno_save = errno;
+		if (cr_restore_root(root_fd))
+			goto err;
+
+		if (ret) {
+			if (errno_save == ENOENT)
 				continue;
+			pr_perror("Unable to stat %s", path);
 			goto err;
 		}
 
@@ -570,6 +581,7 @@  static int unix_resolve_name(int lfd, uint32_t id, struct unix_sk_desc *d,
 	struct ns_id *ns;
 	struct stat st;
 	int mntns_root;
+	int root_fd;
 	int ret, mnt_id;
 
 	if (d->namelen == 0 || name[0] == '\0')
@@ -614,11 +626,18 @@  static int unix_resolve_name(int lfd, uint32_t id, struct unix_sk_desc *d,
 		goto postprone;
 	}
 
+	ret = cr_set_root(mntns_root, &root_fd);
+	if (ret)
+		goto out;
+
 	snprintf(rpath, sizeof(rpath), ".%s", name);
 	if (fstatat(mntns_root, rpath, &st, 0)) {
 		if (errno != ENOENT) {
 			pr_warn("Can't stat socket %#x(%s), skipping: %m (err %d)\n",
 				id, rpath, errno);
+			ret = cr_restore_root(root_fd);
+			if (ret)
+				goto out;
 			goto skip;
 		}
 
@@ -634,6 +653,10 @@  static int unix_resolve_name(int lfd, uint32_t id, struct unix_sk_desc *d,
 		deleted = true;
 	}
 
+	ret = cr_restore_root(root_fd);
+	if (ret)
+		goto out;
+
 	d->mode = st.st_mode;
 	d->uid	= st.st_uid;
 	d->gid	= st.st_gid;