[CRIU] [PATCH v2] remap: fix dead pid remap of /proc/<pid>
Tycho Andersen
tycho.andersen at canonical.com
Thu Jan 14 01:42:49 PST 2016
It turns out we can't just test for /proc/<pid>, because the kernel appends
(deleted), since the directory is actually deleted (vs. something like
/proc/1/mountinfo, where the file still exists in the unlinked directory,
so there is no (deleted)). See comment for details.
v2: s/ret/is_dead in /proc/<pid>/xxx test, split tests to correctly test
both cases
Signed-off-by: Tycho Andersen <tycho.andersen at canonical.com>
---
files-reg.c | 34 ++++++++----
test/zdtm/.gitignore | 1 +
test/zdtm/live/static/Makefile | 1 +
test/zdtm/live/static/remap_dead_pid.c | 5 +-
test/zdtm/live/static/remap_dead_pid_root.c | 72 ++++++++++++++++++++++++++
test/zdtm/live/static/remap_dead_pid_root.desc | 1 +
6 files changed, 104 insertions(+), 10 deletions(-)
create mode 100644 test/zdtm/live/static/remap_dead_pid_root.c
create mode 100644 test/zdtm/live/static/remap_dead_pid_root.desc
diff --git a/files-reg.c b/files-reg.c
index 0f89be5..ea66af0 100644
--- a/files-reg.c
+++ b/files-reg.c
@@ -887,16 +887,32 @@ static int check_path_remap(struct fd_link *link, const struct fd_parms *parms,
return -1;
pid = strtol(start + 1, &end, 10);
- /* if we didn't find another /, this path something
- * like ./proc/kmsg, which we shouldn't mess with. */
- if (*end == '/') {
- *end = 0;
- ret = access(rpath, F_OK);
- *end = '/';
-
- if (ret) {
+ /* If strtol didn't convert anything, then we are looking at
+ * something like /proc/kmsg, which we shouldn't mess with.
+ * Anything under /proc/<pid> (including that directory itself)
+ * can be c/r'd with a dead pid remap, so let's allow all such
+ * cases.
+ */
+ if (pid != 0) {
+ bool is_dead = strip_deleted(link);
+
+ /* /proc/<pid> will be "/proc/1 (deleted)" when it is
+ * dead, but a path like /proc/1/mountinfo won't have
+ * the suffix, since it isn't actually deleted (still
+ * exists, but the parent dir is deleted). So, if we
+ * have a path like /proc/1/mountinfo, test if /proc/1
+ * exists instead, since this is what CRIU will need to
+ * open on restore.
+ */
+ if (!is_dead) {
+ *end = 0;
+ is_dead = access(rpath, F_OK);
+ *end = '/';
+ }
+
+ if (is_dead) {
pr_info("Dumping dead process remap of %d\n", pid);
- return dump_dead_process_remap(pid, rpath + 1, plen - 1, ost, lfd, id, nsid);
+ return dump_dead_process_remap(pid, rpath + 1, link->len - 1, ost, lfd, id, nsid);
}
}
diff --git a/test/zdtm/.gitignore b/test/zdtm/.gitignore
index 3cdfa1a..5963609 100644
--- a/test/zdtm/.gitignore
+++ b/test/zdtm/.gitignore
@@ -106,6 +106,7 @@
/live/static/pty03
/live/static/pty04
/live/static/remap_dead_pid
+/live/static/remap_dead_pid_root
/live/static/rlimits00
/live/static/rmdir_open
/live/static/rtc
diff --git a/test/zdtm/live/static/Makefile b/test/zdtm/live/static/Makefile
index 42eea67..689b1e7 100644
--- a/test/zdtm/live/static/Makefile
+++ b/test/zdtm/live/static/Makefile
@@ -132,6 +132,7 @@ TST_NOFILE = \
dumpable01 \
dumpable02 \
remap_dead_pid \
+ remap_dead_pid_root \
aio00 \
fd \
apparmor \
diff --git a/test/zdtm/live/static/remap_dead_pid.c b/test/zdtm/live/static/remap_dead_pid.c
index c16832d..00fe3fd 100644
--- a/test/zdtm/live/static/remap_dead_pid.c
+++ b/test/zdtm/live/static/remap_dead_pid.c
@@ -41,8 +41,11 @@ int main(int argc, char **argv)
pid_t result;
sprintf(path, "/proc/%d/mountinfo", pid);
-
fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ fail("failed to open fd");
+ return -1;
+ }
/* no matter what, we should kill the child */
kill(pid, SIGKILL);
diff --git a/test/zdtm/live/static/remap_dead_pid_root.c b/test/zdtm/live/static/remap_dead_pid_root.c
new file mode 100644
index 0000000..2a31412
--- /dev/null
+++ b/test/zdtm/live/static/remap_dead_pid_root.c
@@ -0,0 +1,72 @@
+#define _GNU_SOURCE
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "zdtmtst.h"
+
+#ifndef CLONE_NEWNS
+#define CLONE_NEWNS 0x00020000
+#endif
+
+const char *test_doc = "Check that dead pid's /proc entries are remapped correctly";
+const char *test_author = "Tycho Andersen <tycho.andersen at canonical.com>";
+
+int main(int argc, char **argv)
+{
+ pid_t pid;
+
+ test_init(argc, argv);
+
+ pid = fork();
+ if (pid < 0) {
+ fail("fork() failed");
+ return -1;
+ }
+
+ if (pid == 0) {
+ test_msg("child is %d\n", pid);
+ /* Child process just sleeps until it is killed. All we need
+ * here is a process to open the mountinfo of. */
+ while(1)
+ sleep(10);
+ } else {
+ int fd, ret;
+ char path[PATH_MAX];
+ pid_t result;
+
+ sprintf(path, "/proc/%d", pid);
+ fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ fail("failed to open fd");
+ return -1;
+ }
+
+ /* no matter what, we should kill the child */
+ kill(pid, SIGKILL);
+ result = waitpid(pid, NULL, 0);
+ if (result < 0) {
+ fail("failed waitpid()");
+ return -1;
+ }
+
+ test_daemon();
+ test_waitsig();
+
+ ret = fcntl(fd, F_GETFD);
+ close(fd);
+
+ if (ret) {
+ fail("bad fd after restore");
+ return -1;
+ }
+ }
+
+ pass();
+ return 0;
+}
diff --git a/test/zdtm/live/static/remap_dead_pid_root.desc b/test/zdtm/live/static/remap_dead_pid_root.desc
new file mode 100644
index 0000000..63df42a
--- /dev/null
+++ b/test/zdtm/live/static/remap_dead_pid_root.desc
@@ -0,0 +1 @@
+{'flavor': 'h'}
--
2.5.0
More information about the CRIU
mailing list