[CRIU] [PATCH 04/11] zdtm/vdso: Add test for restoring task without vdso blob
Dmitry Safonov
dsafonov at virtuozzo.com
Thu Jun 15 19:36:08 MSK 2017
Check that task without vvar & vdso blobs is restored without them.
Signed-off-by: Dmitry Safonov <dsafonov at virtuozzo.com>
---
test/zdtm/static/Makefile | 1 +
test/zdtm/static/vdso02.c | 231 ++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 232 insertions(+)
create mode 100644 test/zdtm/static/vdso02.c
diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile
index 0ea6c3d87dbf..2c26f50c062d 100644
--- a/test/zdtm/static/Makefile
+++ b/test/zdtm/static/Makefile
@@ -54,6 +54,7 @@ TST_NOFILE := \
pthread02 \
vdso00 \
vdso01 \
+ vdso02 \
utsname \
pstree \
sockets01 \
diff --git a/test/zdtm/static/vdso02.c b/test/zdtm/static/vdso02.c
new file mode 100644
index 000000000000..f0047bc2cc61
--- /dev/null
+++ b/test/zdtm/static/vdso02.c
@@ -0,0 +1,231 @@
+#include <signal.h>
+#include <stdlib.h>
+#include <sys/syscall.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "zdtmtst.h"
+
+const char *test_doc = "Restoring task with unmapped vDSO blob. Poor man's test for C/R on vdso64_enabled=0 booted kernel.\n";
+const char *test_author = "Dmitry Safonov <dsafonov at virtuozzo.com>";
+
+#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
+#define VDSO_BAD_ADDR (-1ul)
+#define VVAR_BAD_ADDR (-1ul)
+#define BUF_SZ 1024
+
+struct vm_area {
+ unsigned long start;
+ unsigned long end;
+};
+
+static int parse_vm_area(char *buf, struct vm_area *vma)
+{
+ if (sscanf(buf, "%lx-%lx", &vma->start, &vma->end) == 2)
+ return 0;
+
+ pr_perror("Can't find VMA bounds");
+ return -1;
+}
+
+static int find_blobs(pid_t pid, struct vm_area *vdso, struct vm_area *vvar)
+{
+ char buf[BUF_SZ];
+ int ret = -1;
+ FILE *maps;
+
+ vdso->start = VDSO_BAD_ADDR;
+ vdso->end = VDSO_BAD_ADDR;
+ vvar->start = VVAR_BAD_ADDR;
+ vvar->end = VVAR_BAD_ADDR;
+
+ if (snprintf(buf, BUF_SZ, "/proc/%d/maps", pid) < 0) {
+ pr_perror("snprintf() failure for path");
+ return -1;
+ }
+
+ maps = fopen(buf, "r");
+ if (!maps) {
+ pr_perror("Can't open maps for %d", pid);
+ return -1;
+ }
+
+ while (fgets(buf, sizeof(buf), maps)) {
+ if (strstr(buf, "[vdso]") && parse_vm_area(buf, vdso))
+ goto err;
+
+ if (strstr(buf, "[vvar]") && parse_vm_area(buf, vvar))
+ goto err;
+ }
+
+ if (vdso->start != VDSO_BAD_ADDR)
+ test_msg("[vdso] %lx-%lx\n", vdso->start, vdso->end);
+ if (vvar->start != VVAR_BAD_ADDR)
+ test_msg("[vvar] %lx-%lx\n", vvar->start, vvar->end);
+ ret = 0;
+err:
+ fclose(maps);
+ return ret;
+}
+
+#ifdef __i386__
+/*
+ * On i386 syscalls for speed are optimized trough vdso,
+ * call raw int80 as vdso is unmapped.
+ */
+#define __NR32_munmap 91
+#define __NR32_kill 37
+#define __NR32_exit 1
+struct syscall_args32 {
+ uint32_t nr, arg0, arg1;
+};
+
+static inline void do_full_int80(struct syscall_args32 *args)
+{
+ asm volatile (
+ "int $0x80\n\t"
+ : "+a" (args->nr),
+ "+b" (args->arg0), "+c" (args->arg1));
+}
+
+int sys_munmap(void *addr, size_t len)
+{
+ struct syscall_args32 s = {0};
+
+ s.nr = __NR32_munmap;
+ s.arg0 = (uint32_t)(uintptr_t)addr;
+ s.arg1 = (uint32_t)len;
+
+ do_full_int80(&s);
+
+ return (int)s.nr;
+}
+
+int sys_kill(pid_t pid, int sig)
+{
+ struct syscall_args32 s = {0};
+
+ s.nr = __NR32_kill;
+ s.arg0 = (uint32_t)pid;
+ s.arg1 = (uint32_t)sig;
+
+ do_full_int80(&s);
+
+ return (int)s.nr;
+}
+
+void sys_exit(int status)
+{
+ struct syscall_args32 s = {0};
+
+ s.nr = __NR32_exit;
+ s.arg0 = (uint32_t)status;
+
+ do_full_int80(&s);
+}
+
+#else /* !__i386__ */
+
+int sys_munmap(void *addr, size_t len)
+{
+ return syscall(SYS_munmap, addr, len);
+}
+
+int sys_kill(pid_t pid, int sig)
+{
+ return syscall(SYS_kill, pid, sig);
+}
+
+void sys_exit(int status)
+{
+ syscall(SYS_exit, status);
+}
+
+#endif
+
+static int unmap_blobs(void)
+{
+ struct vm_area vdso, vvar;
+ int ret;
+
+ if (find_blobs(getpid(), &vdso, &vvar))
+ return -1;
+
+ if (vdso.start != VDSO_BAD_ADDR) {
+ ret = sys_munmap((void*)vdso.start, vdso.end - vdso.start);
+ if (ret)
+ return ret;
+ }
+ if (vvar.start != VVAR_BAD_ADDR) {
+ ret = sys_munmap((void*)vvar.start, vvar.end - vvar.start);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ struct vm_area vdso, vvar;
+ pid_t child;
+ int status, ret = -1;
+
+ test_init(argc, argv);
+
+ child = fork();
+ if (child < 0) {
+ pr_perror("fork() failed");
+ exit(1);
+ }
+
+ if (child == 0) {
+ child = getpid();
+ if (unmap_blobs() < 0)
+ syscall(SYS_exit, 1);
+ sys_kill(child, SIGSTOP);
+ sys_exit(2);
+ }
+
+ waitpid(child, &status, WUNTRACED);
+ if (WIFEXITED(status)) {
+ int ret = WEXITSTATUS(status);
+
+ pr_err("Child unexpectedly exited with %d\n", ret);
+ goto out_kill;
+ } else if (WIFSIGNALED(status)) {
+ int sig = WTERMSIG(status);
+
+ pr_err("Child unexpectedly signaled with %d: %s\n",
+ sig, strsignal(sig));
+ goto out_kill;
+ } else if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGSTOP) {
+ pr_err("Child is unstoppable or was stopped by other means\n");
+ goto out_kill;
+ }
+
+ if (find_blobs(child, &vdso, &vvar))
+ goto out_kill;
+ if (vdso.start != VDSO_BAD_ADDR || vvar.start != VVAR_BAD_ADDR) {
+ pr_err("Found vvar or vdso blob(s) in child, which should have unmapped them\n");
+ goto out_kill;
+ }
+
+ test_daemon();
+ test_waitsig();
+
+ if (find_blobs(child, &vdso, &vvar))
+ goto out_kill;
+ if (vdso.start != VDSO_BAD_ADDR || vvar.start != VVAR_BAD_ADDR) {
+ pr_err("Child without vdso got it after C/R\n");
+ fail();
+ goto out_kill;
+ }
+
+ pass();
+
+ ret = 0;
+out_kill:
+ kill(child, SIGKILL);
+ return ret;
+}
--
2.12.2
More information about the CRIU
mailing list