Commit 17644ff3 authored by Dmitry Safonov's avatar Dmitry Safonov Committed by Andrei Vagin

zdtm/vdso: Add test for restoring task without vdso blob

Check that task without vvar & vdso blobs is restored without them.
Reviewed-by: 's avatarCyrill Gorcunov <gorcunov@openvz.org>
Signed-off-by: 's avatarDmitry Safonov <dsafonov@virtuozzo.com>
Signed-off-by: 's avatarAndrei Vagin <avagin@virtuozzo.com>
parent 8f386360
......@@ -54,6 +54,7 @@ TST_NOFILE := \
pthread02 \
vdso00 \
vdso01 \
vdso02 \
utsname \
pstree \
sockets01 \
......
#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@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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment