[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 3/5] backdoor: [*-user] Add QEMU-side proxy to "libb
From: |
Lluís Vilanova |
Subject: |
[Qemu-devel] [PATCH 3/5] backdoor: [*-user] Add QEMU-side proxy to "libbackdoor.a" |
Date: |
Thu, 29 Sep 2011 15:47:43 +0200 |
User-agent: |
StGit/0.15 |
QEMU detects when the guest uses 'mmap' on the control channel file, and then
uses 'mprotect' to detect accesses to it, which are redirected to the
user-provided "libbackdoor.a".
Signed-off-by: Lluís Vilanova <address@hidden>
---
Makefile.objs | 2 +
backdoor/qemu/user.c | 194 ++++++++++++++++++++++++++++++++++++++++++++++++++
backdoor/qemu/user.h | 17 ++++
bsd-user/main.c | 25 ++++++
bsd-user/mmap.c | 7 ++
configure | 1
darwin-user/main.c | 25 ++++++
darwin-user/mmap.c | 7 ++
linux-user/main.c | 30 ++++++++
linux-user/mmap.c | 7 ++
10 files changed, 315 insertions(+), 0 deletions(-)
create mode 100644 backdoor/qemu/user.c
create mode 100644 backdoor/qemu/user.h
diff --git a/Makefile.objs b/Makefile.objs
index 2493e59..d39074d 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -397,6 +397,8 @@ $(trace-obj-y): $(GENERATED_HEADERS)
######################################################################
# backdoor
+backdoor-nested-$(CONFIG_USER_ONLY) += user.o
+
backdoor-obj-y += $(addprefix backdoor/qemu/, $(backdoor-nested-y))
ifdef CONFIG_BACKDOOR
diff --git a/backdoor/qemu/user.c b/backdoor/qemu/user.c
new file mode 100644
index 0000000..a236ca5
--- /dev/null
+++ b/backdoor/qemu/user.c
@@ -0,0 +1,194 @@
+/*
+ * QEMU-side management of backdoor channels in user-level emulation.
+ *
+ * Copyright (C) 2011 Lluís Vilanova <address@hidden>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "backdoor/qemu/user.h"
+
+#include <sys/mman.h>
+
+#include "qemu-common.h"
+#include "backdoor/qemu/qemu-backdoor.h"
+
+
+static char *data_path = NULL;
+static char *control_path = NULL;
+static int data_fd = -1;
+static int control_fd = -1;
+
+static void *data = NULL;
+static void *qemu_control_0 = NULL;
+static void *qemu_control_1 = NULL;
+
+static struct stat control_fd_stat;
+
+struct sigaction segv_next;
+static void segv_handler(int signum, siginfo_t *siginfo, void *sigctxt);
+
+
+static void init_channel(const char *base, const char *suffix, size_t size,
+ char ** path, int *fd, void **addr)
+{
+ *path = g_malloc(strlen(base) + strlen(suffix) + 1);
+ sprintf(*path, "%s%s", base, suffix);
+
+ *fd = open(*path, O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR);
+ if (*fd == -1) {
+ fprintf(stderr, "error: open(%s): %s\n", *path, strerror(errno));
+ abort();
+ }
+
+ off_t lres = lseek(*fd, size - 1, SEEK_SET);
+ if (lres == (off_t)-1) {
+ fprintf(stderr, "error: lseek(%s): %s\n", *path, strerror(errno));
+ abort();
+ }
+
+ char tmp;
+ ssize_t wres = write(*fd, &tmp, 1);
+ if (wres == -1) {
+ fprintf(stderr, "error: write(%s): %s\n", *path, strerror(errno));
+ abort();
+ }
+
+ if (addr) {
+ *addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, *fd, 0);
+ if (*addr == MAP_FAILED) {
+ fprintf(stderr, "error: mmap(%s): %s\n", *path, strerror(errno));
+ abort();
+ }
+ }
+}
+
+void backdoor_init(const char *base, uint64_t data_size)
+{
+ if (base == NULL) {
+ return;
+ }
+
+ init_channel(base, "-data", data_size, &data_path, &data_fd, &data);
+ void *control;
+ init_channel(base, "-control", getpagesize() * 2, &control_path,
&control_fd, &control);
+
+ /* store channel size in first 64bits; command goes into 2nd slot */
+ *(uint64_t*)control = data_size;
+
+ if (fstat(control_fd, &control_fd_stat) == -1) {
+ fprintf(stderr, "error: fstat(backdoor_control): %s\n",
strerror(errno));
+ abort();
+ }
+
+ struct sigaction segv;
+ memset(&segv, 0, sizeof(segv));
+ segv.sa_sigaction = segv_handler;
+ segv.sa_flags = SA_SIGINFO | SA_RESTART;
+ sigemptyset(&segv.sa_mask);
+
+ if (sigaction(SIGSEGV, &segv, &segv_next) != 0) {
+ fprintf(stderr, "error: sigaction(SIGSEGV): %s\n", strerror(errno));
+ abort();
+ }
+
+ qemu_backdoor_init(data_size);
+}
+
+
+static void fini_channel(int *fd, char **path)
+{
+ if (*fd != -1) {
+ if (close(*fd) == -1) {
+ fprintf(stderr, "error: close: %s\n", strerror(errno));
+ abort();
+ }
+ if (unlink(*path) == -1) {
+ fprintf(stderr, "error: unlink(%s): %s\n", *path, strerror(errno));
+ abort();
+ }
+ *fd = -1;
+ }
+ if (*path != NULL) {
+ g_free(path);
+ *path = NULL;
+ }
+}
+
+void backdoor_fini(void)
+{
+ static bool atexit_in = false;
+ if (atexit_in) {
+ return;
+ }
+ atexit_in = true;
+
+ if (sigaction(SIGSEGV, &segv_next, NULL) != 0) {
+ fprintf(stderr, "error: sigaction(SIGSEGV): %s\n", strerror(errno));
+ abort();
+ }
+ fini_channel(&data_fd, &data_path);
+ fini_channel(&control_fd, &control_path);
+}
+
+
+void backdoor_guest_mmap(int fd, void *qemu_addr)
+{
+ struct stat s;
+ if (fstat(fd, &s) != 0) {
+ return;
+ }
+
+ if (s.st_dev != control_fd_stat.st_dev ||
+ s.st_ino != control_fd_stat.st_ino) {
+ return;
+ }
+
+ qemu_control_0 = qemu_addr;
+ qemu_control_1 = qemu_control_0 + getpagesize();
+ if (mprotect(qemu_control_0, getpagesize(), PROT_READ) == -1) {
+ fprintf(stderr, "error: mprotect(backdoor_control): %s\n",
+ strerror(errno));
+ abort();
+ }
+}
+
+static void swap_control(void *from, void *to)
+{
+ if (mprotect(from, getpagesize(), PROT_READ | PROT_WRITE) == -1) {
+ fprintf(stderr, "error: mprotect(from): %s\n",
+ strerror(errno));
+ abort();
+ }
+ if (mprotect(to, getpagesize(), PROT_READ) == -1) {
+ fprintf(stderr, "error: mprotect(to): %s\n",
+ strerror(errno));
+ abort();
+ }
+}
+
+static void segv_handler(int signum, siginfo_t *siginfo, void *sigctxt)
+{
+ if (qemu_control_0 <= siginfo->si_addr &&
+ siginfo->si_addr < qemu_control_1) {
+
+ assert(((target_ulong)siginfo->si_addr % getpagesize()) ==
sizeof(uint64_t));
+ swap_control(qemu_control_0, qemu_control_1);
+
+ } else if (qemu_control_1 <= siginfo->si_addr &&
+ siginfo->si_addr < qemu_control_1 + getpagesize()) {
+
+ assert(((target_ulong)siginfo->si_addr % getpagesize()) ==
sizeof(uint64_t));
+ qemu_backdoor(((uint64_t*)qemu_control_0)[1], data);
+ swap_control(qemu_control_1, qemu_control_0);
+
+ } else {
+ /* proxy to next handler */
+ if (segv_next.sa_sigaction != NULL) {
+ segv_next.sa_sigaction(signum, siginfo, sigctxt);
+ } else if (segv_next.sa_handler != NULL) {
+ segv_next.sa_handler(signum);
+ }
+ }
+}
diff --git a/backdoor/qemu/user.h b/backdoor/qemu/user.h
new file mode 100644
index 0000000..1ecc8cd
--- /dev/null
+++ b/backdoor/qemu/user.h
@@ -0,0 +1,17 @@
+/*
+ * QEMU-side management of backdoor channels in user-level emulation.
+ *
+ * Copyright (C) 2011 Lluís Vilanova <address@hidden>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <stdint.h>
+#include <sys/types.h>
+
+
+void backdoor_init(const char *base, uint64_t data_size);
+/** Check if this mmap is for the control channel and act accordingly. */
+void backdoor_guest_mmap(int fd, void *qemu_addr);
+void backdoor_fini(void);
diff --git a/bsd-user/main.c b/bsd-user/main.c
index cc7d4a3..046ed87 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -33,6 +33,9 @@
#include "tcg.h"
#include "qemu-timer.h"
#include "envlist.h"
+#if defined(CONFIG_BACKDOOR)
+#include "backdoor/qemu/user.h"
+#endif
#define DEBUG_LOGFILE "/tmp/qemu.log"
@@ -688,6 +691,11 @@ static void usage(void)
"-B address set guest_base address to address\n"
#endif
"-bsd type select emulated BSD type FreeBSD/NetBSD/OpenBSD
(default)\n"
+#if defined(CONFIG_BACKDOOR)
+ "-backdoor path base path to backdoor channel\n"
+ "-backdoor-pages value\n"
+ " number of pages for the backdoor data channel
(default: 1)\n"
+#endif
"\n"
"Debug options:\n"
"-d options activate log (default logfile=%s)\n"
@@ -744,6 +752,10 @@ int main(int argc, char **argv)
char **target_environ, **wrk;
envlist_t *envlist = NULL;
bsd_type = target_openbsd;
+#if defined(CONFIG_BACKDOOR)
+ char *backdoor_base = NULL;
+ uint64_t backdoor_size = getpagesize();
+#endif
if (argc <= 1)
usage();
@@ -851,6 +863,16 @@ int main(int argc, char **argv)
singlestep = 1;
} else if (!strcmp(r, "strace")) {
do_strace = 1;
+#if defined(CONFIG_BACKDOOR)
+ } else if (!strcmp(r, "backdoor")) {
+ if (atexit(backdoor_fini) != 0) {
+ fprintf(stderr, "error: atexit: %s\n", strerror(errno));
+ abort();
+ }
+ backdoor_base = argv[optind++];
+ } else if (!strcmp(r, "backdoor-pages")) {
+ backdoor_size = atoi(argv[optind++]) * getpagesize();
+#endif
} else
{
usage();
@@ -988,6 +1010,9 @@ int main(int argc, char **argv)
target_set_brk(info->brk);
syscall_init();
signal_init();
+#if defined(CONFIG_BACKDOOR)
+ backdoor_init(backdoor_base, backdoor_size);
+#endif
#if defined(CONFIG_USE_GUEST_BASE)
/* Now that we've loaded the binary, GUEST_BASE is fixed. Delay
diff --git a/bsd-user/mmap.c b/bsd-user/mmap.c
index 5d6cffc..afa57df 100644
--- a/bsd-user/mmap.c
+++ b/bsd-user/mmap.c
@@ -28,6 +28,10 @@
#include "qemu-common.h"
#include "bsd-mman.h"
+#if defined(CONFIG_BACKDOOR)
+#include "backdoor/qemu/user.h"
+#endif
+
//#define DEBUG_MMAP
#if defined(CONFIG_USE_NPTL)
@@ -473,6 +477,9 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int
prot,
}
}
the_end1:
+#if defined(CONFIG_BACKDOOR)
+ backdoor_guest_mmap(fd, (void *)g2h(start));
+#endif
page_set_flags(start, start + len, prot | PAGE_VALID);
the_end:
#ifdef DEBUG_MMAP
diff --git a/configure b/configure
index e2be271..74a6f5a 100755
--- a/configure
+++ b/configure
@@ -3216,6 +3216,7 @@ symlink $source_path/Makefile.target $target_dir/Makefile
if test -n "$backdoor"; then
mkdir -p $target_dir/libbackdoor
symlink $backdoor/Makefile $target_dir/libbackdoor/Makefile
+ mkdir -p $target_dir/backdoor/qemu
fi
diff --git a/darwin-user/main.c b/darwin-user/main.c
index 1a881a0..2b28e46 100644
--- a/darwin-user/main.c
+++ b/darwin-user/main.c
@@ -28,6 +28,9 @@
#include <sys/mman.h>
#include "qemu.h"
+#if defined(CONFIG_BACKDOOR)
+#include "backdoor/qemu/user.h"
+#endif
#define DEBUG_LOGFILE "/tmp/qemu.log"
@@ -713,6 +716,11 @@ static void usage(void)
"-h print this help\n"
"-L path set the %s library path (default='%s')\n"
"-s size set the stack size in bytes (default=%ld)\n"
+#if defined(CONFIG_BACKDOOR)
+ "-backdoor path base path to backdoor channel\n"
+ "-backdoor-pages value\n"
+ " number of pages for the backdoor data channel
(default: 1)\n"
+#endif
"\n"
"debug options:\n"
"-d options activate log (logfile='%s')\n"
@@ -747,6 +755,10 @@ int main(int argc, char **argv)
short use_gdbstub = 0;
const char *r;
const char *cpu_model;
+#if defined(CONFIG_BACKDOOR)
+ char *backdoor_base = NULL;
+ uint64_t backdoor_size = getpagesize();
+#endif
if (argc <= 1)
usage();
@@ -804,6 +816,16 @@ int main(int argc, char **argv)
}
} else if (!strcmp(r, "singlestep")) {
singlestep = 1;
+#if defined(CONFIG_BACKDOOR)
+ } else if (!strcmp(r, "backdoor")) {
+ if (atexit(backdoor_fini) != 0) {
+ fprintf(stderr, "error: atexit: %s\n", strerror(errno));
+ abort();
+ }
+ backdoor_base = argv[optind++];
+ } else if (!strcmp(r, "backdoor-pages")) {
+ backdoor_size = atoi(argv[optind++]) * getpagesize();
+#endif
} else
{
usage();
@@ -870,6 +892,9 @@ int main(int argc, char **argv)
syscall_init();
signal_init();
+#if defined(CONFIG_BACKDOOR)
+ backdoor_init(backdoor_base, backdoor_size);
+#endif
global_env = env;
/* build Task State */
diff --git a/darwin-user/mmap.c b/darwin-user/mmap.c
index d840b28..047c5bf 100644
--- a/darwin-user/mmap.c
+++ b/darwin-user/mmap.c
@@ -26,6 +26,10 @@
#include "qemu.h"
+#if defined(CONFIG_BACKDOOR)
+#include "backdoor/qemu/user.h"
+#endif
+
//#define DEBUG_MMAP
/* NOTE: all the constants are the HOST ones */
@@ -308,6 +312,9 @@ long target_mmap(unsigned long start, unsigned long len,
int prot,
return ret;
}
the_end1:
+#if defined(CONFIG_BACKDOOR)
+ backdoor_guest_mmap(fd, (void *)g2h(start));
+#endif
page_set_flags(start, start + len, prot | PAGE_VALID);
the_end:
#ifdef DEBUG_MMAP
diff --git a/linux-user/main.c b/linux-user/main.c
index 186358b..4d5ef97 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -33,6 +33,9 @@
#include "tcg.h"
#include "qemu-timer.h"
#include "envlist.h"
+#if defined(CONFIG_BACKDOOR)
+#include "backdoor/qemu/user.h"
+#endif
#define DEBUG_LOGFILE "/tmp/qemu.log"
@@ -50,6 +53,10 @@ unsigned long guest_base;
int have_guest_base;
unsigned long reserved_va;
#endif
+#if defined(CONFIG_BACKDOOR)
+const char *backdoor_base = NULL;
+uint64_t backdoor_size;
+#endif
static void usage(void);
@@ -3080,6 +3087,18 @@ static void handle_arg_strace(const char *arg)
do_strace = 1;
}
+#if defined(CONFIG_BACKDOOR)
+static void handle_arg_backdoor(const char *arg)
+{
+ backdoor_base = arg;
+}
+
+static void handle_arg_backdoor_pages(const char *arg)
+{
+ backdoor_size = atoi(arg) * getpagesize();
+}
+#endif
+
static void handle_arg_version(const char *arg)
{
printf("qemu-" TARGET_ARCH " version " QEMU_VERSION QEMU_PKGVERSION
@@ -3120,6 +3139,12 @@ struct qemu_argument arg_table[] = {
{"R", "QEMU_RESERVED_VA", true, handle_arg_reserved_va,
"size", "reserve 'size' bytes for guest virtual address space"},
#endif
+#if defined(CONFIG_BACKDOOR)
+ {"backdoor", "QEMU_BACKDOOR", true, handle_arg_backdoor,
+ "path", "base path to backdoor channel\n"},
+ {"backdoor-pages", "QEMU_BACKDOOR_PAGES", true, handle_arg_backdoor_pages,
+ "num", "number of pages for the backdoor data channel (default:
1)\n"},
+#endif
{"d", "QEMU_LOG", true, handle_arg_log,
"options", "activate log"},
{"p", "QEMU_PAGESIZE", true, handle_arg_pagesize,
@@ -3279,6 +3304,8 @@ int main(int argc, char **argv, char **envp)
if (argc <= 1)
usage();
+ backdoor_size = getpagesize();
+
qemu_cache_utils_init(envp);
if ((envlist = envlist_create()) == NULL) {
@@ -3511,6 +3538,9 @@ int main(int argc, char **argv, char **envp)
target_set_brk(info->brk);
syscall_init();
signal_init();
+#if defined(CONFIG_BACKDOOR)
+ backdoor_init(backdoor_base, backdoor_size);
+#endif
#if defined(CONFIG_USE_GUEST_BASE)
/* Now that we've loaded the binary, GUEST_BASE is fixed. Delay
diff --git a/linux-user/mmap.c b/linux-user/mmap.c
index 994c02b..2232363 100644
--- a/linux-user/mmap.c
+++ b/linux-user/mmap.c
@@ -31,6 +31,10 @@
#include "qemu.h"
#include "qemu-common.h"
+#if defined(CONFIG_BACKDOOR)
+#include "backdoor/qemu/user.h"
+#endif
+
//#define DEBUG_MMAP
#if defined(CONFIG_USE_NPTL)
@@ -553,6 +557,9 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int
prot,
}
}
the_end1:
+#if defined(CONFIG_BACKDOOR)
+ backdoor_guest_mmap(fd, (void *)g2h(start));
+#endif
page_set_flags(start, start + len, prot | PAGE_VALID);
the_end:
#ifdef DEBUG_MMAP
- [Qemu-devel] [PATCH 2/5] backdoor: Add build infrastructure, (continued)
- [Qemu-devel] [PATCH 2/5] backdoor: Add build infrastructure, Lluís Vilanova, 2011/09/29
- [Qemu-devel] [PATCH 4/5] backdoor: [softmmu] Add QEMU-side proxy to "libbackdoor.a", Lluís Vilanova, 2011/09/29
- Re: [Qemu-devel] [PATCH 4/5] backdoor: [softmmu] Add QEMU-side proxy to "libbackdoor.a", Blue Swirl, 2011/09/29
- Re: [Qemu-devel] [PATCH 4/5] backdoor: [softmmu] Add QEMU-side proxy to "libbackdoor.a", Frans de Boer, 2011/09/29
- Re: [Qemu-devel] [PATCH 4/5] backdoor: [softmmu] Add QEMU-side proxy to "libbackdoor.a", Blue Swirl, 2011/09/30
- Re: [Qemu-devel] [PATCH 4/5] backdoor: [softmmu] Add QEMU-side proxy to "libbackdoor.a", Lluís Vilanova, 2011/09/30
- Re: [Qemu-devel] [PATCH 4/5] backdoor: [softmmu] Add QEMU-side proxy to "libbackdoor.a", Blue Swirl, 2011/09/30
[Qemu-devel] [PATCH 3/5] backdoor: [*-user] Add QEMU-side proxy to "libbackdoor.a",
Lluís Vilanova <=
[Qemu-devel] [PATCH 5/5] backdoor: Add guest-side library, Lluís Vilanova, 2011/09/29
Re: [Qemu-devel] [RFC][PATCH 0/5] backdoor: lightweight guest-to-QEMU backdoor channel, Anthony Liguori, 2011/09/29