[CRIU] [PATCH v3 8/8] zdtm: check that pid-reuse does not break iterative memory dump
Pavel Tikhomirov
ptikhomirov at virtuozzo.com
Thu Feb 15 13:06:55 MSK 2018
From: ptikhomirov <ptikhomirov at virtuozzo.com>
The idea of the test is:
1) mmap separate page and put variable there, so that other usage does
not dirty these region. Initialize the variable with VALUE_A.
2) fork a child with special pid == CHILD_NS_PID. Only if it is a first
child overwrite the variable with VALUE_B.
3) wait for the end of the next predump or end of restore with
test_waitpre and kill our child.
Note: The memory region is "clean" in parent.
4) goto (2) unles end of cr is reported by test_waitpre
So on first iteration child with pid CHILD_NS_PID was dumped with
VALUE_B, on all other iterations and on final dump other child with the
same pid exists but with VALUE_A. But on all iterations after the first
one we have these memory region "clean". So criu before the fix would
have restored the VALUE_B taking it from first child's image, but should
restore VALUE_A.
Note: Child in its turn waits termination and performs a check that variable
value doesn't change after c/r.
We should run the test with at least one predump to trigger the problem:
[root at snorch criu]# ./test/zdtm.py run --pre 1 -k always -t zdtm/transition/pid_reuse
Checking feature ns_pid
Checking feature ns_get_userns
Checking feature ns_get_parent
=== Run 1/1 ================ zdtm/transition/pid_reuse
===================== Run zdtm/transition/pid_reuse in ns ======================
DEP pid_reuse.d
CC pid_reuse.o
LINK pid_reuse
Start test
Test is SUID
./pid_reuse --pidfile=pid_reuse.pid --outfile=pid_reuse.out
Run criu pre-dump
Send the 10 signal to 52
Run criu dump
Run criu restore
Send the 15 signal to 73
Wait for zdtm/transition/pid_reuse(73) to die for 0.100000
Test output: ================================
14:47:57.717: 11235: ERR: pid_reuse.c:76: Wrong value in a variable after restore
14:47:57.717: 4: FAIL: pid_reuse.c:110: Task 11235 exited with wrong code 1 (errno = 11 (Resource temporarily unavailable))
<<< ================================
https://jira.sw.ru/browse/PSBM-67502
v3: simplify waitpid's status check
Signed-off-by: Pavel Tikhomirov <ptikhomirov at virtuozzo.com>
---
test/zdtm/transition/Makefile | 1 +
test/zdtm/transition/pid_reuse.c | 113 ++++++++++++++++++++++++++++++++++++
test/zdtm/transition/pid_reuse.desc | 1 +
3 files changed, 115 insertions(+)
create mode 100644 test/zdtm/transition/pid_reuse.c
create mode 100644 test/zdtm/transition/pid_reuse.desc
diff --git a/test/zdtm/transition/Makefile b/test/zdtm/transition/Makefile
index f482a8a09..35301ac85 100644
--- a/test/zdtm/transition/Makefile
+++ b/test/zdtm/transition/Makefile
@@ -21,6 +21,7 @@ TST_NOFILE = \
socket-tcp6 \
shmem \
lazy-thp \
+ pid_reuse \
TST_FILE = \
diff --git a/test/zdtm/transition/pid_reuse.c b/test/zdtm/transition/pid_reuse.c
new file mode 100644
index 000000000..9a36c26f9
--- /dev/null
+++ b/test/zdtm/transition/pid_reuse.c
@@ -0,0 +1,113 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+
+#include "zdtmtst.h"
+
+const char *test_doc = "Tests that forking tasks with same pid does not break iterative dump";
+const char *test_author = "Pavel Tikhomirov <ptikhomirov at virtuozzo.com>";
+
+enum {
+ VALUE_A = 1,
+ VALUE_B = 2,
+};
+
+#define CHILD_NS_PID 11235
+
+static int set_ns_next_pid(pid_t pid)
+{
+ char buf[32];
+ int len, fd;
+
+ fd = open("/proc/sys/kernel/ns_last_pid", O_WRONLY);
+ if (fd < 0) {
+ pr_perror("Failed to open ns_last_pid");
+ return -1;
+ }
+
+ len = snprintf(buf, sizeof(buf), "%d", pid - 1);
+ len -= write(fd, buf, len);
+ if (len)
+ pr_perror("Can't set ns_last_pid");
+ close(fd);
+
+ return len ? -1 : 0;
+}
+
+int main(int argc, char **argv)
+{
+ int pid, wpid, status;
+ bool overwrite = true;
+ bool wait = true;
+ int *variable;
+ void *mem;
+
+ test_init(argc, argv);
+
+ mem = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+ if (mem == MAP_FAILED) {
+ pr_perror("Can't mmap memory region");
+ return 1;
+ }
+
+ variable = (int *)mem;
+ *variable = VALUE_A;
+
+ test_daemon();
+
+ while (wait) {
+ if (set_ns_next_pid(CHILD_NS_PID))
+ return 1;
+
+ pid = fork();
+ if (pid == -1) {
+ pr_perror("fork");
+ return 1;
+ } else if (pid == 0) {
+ if (overwrite)
+ *variable = VALUE_B;
+ test_waitsig();
+
+ if (*variable != (overwrite ? VALUE_B : VALUE_A)) {
+ pr_err("Wrong value in a variable after restore\n");
+ exit(1);
+ }
+ exit(0);
+ }
+
+ if (pid != CHILD_NS_PID) {
+ pr_err("Child started with wrong pid %d (expected %d)\n", pid, CHILD_NS_PID);
+ kill(pid, SIGKILL);
+ waitpid(pid, NULL, 0);
+ return 1;
+ }
+
+ /* Wait for next predump/dump finish */
+ if (test_waitpre())
+ wait = false;
+
+ if (kill(pid, SIGTERM)) {
+ pr_perror("kill");
+ return 1;
+ }
+
+ wpid = waitpid(pid, &status, 0);
+ if (wpid <= 0) {
+ pr_perror("waitpid");
+ return 1;
+ }
+
+ if (status) {
+ fail("Task %d died with exit status %x", wpid, status);
+ return 1;
+ }
+
+ overwrite = false;
+ }
+ pass();
+ return 0;
+}
diff --git a/test/zdtm/transition/pid_reuse.desc b/test/zdtm/transition/pid_reuse.desc
new file mode 100644
index 000000000..1d1a44053
--- /dev/null
+++ b/test/zdtm/transition/pid_reuse.desc
@@ -0,0 +1 @@
+{'flavor': 'ns uns', 'flags': 'suid', 'feature': 'ns_pid ns_get_userns ns_get_parent'}
--
2.14.3
More information about the CRIU
mailing list