From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([140.186.70.92]:58697) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1R9Gxr-0003jA-VL for qemu-devel@nongnu.org; Thu, 29 Sep 2011 09:47:57 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1R9Gxl-0004FL-4n for qemu-devel@nongnu.org; Thu, 29 Sep 2011 09:47:51 -0400 Received: from gw.ac.upc.edu ([147.83.30.3]:51003) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1R9Gxk-0004Eo-IL for qemu-devel@nongnu.org; Thu, 29 Sep 2011 09:47:45 -0400 From: =?utf-8?b?TGx1w61z?= Vilanova Date: Thu, 29 Sep 2011 15:47:43 +0200 Message-ID: <20110929134743.19559.98297.stgit@ginnungagap.bsc.es> In-Reply-To: <20110929134727.19559.54734.stgit@ginnungagap.bsc.es> References: <20110929134727.19559.54734.stgit@ginnungagap.bsc.es> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Subject: [Qemu-devel] [PATCH 3/5] backdoor: [*-user] Add QEMU-side proxy to "libbackdoor.a" List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: Zhi Yong Wu 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=C3=ADs Vilanova --- 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=20 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 =20 +backdoor-nested-$(CONFIG_USER_ONLY) +=3D user.o + backdoor-obj-y +=3D $(addprefix backdoor/qemu/, $(backdoor-nested-y)) =20 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=C3=ADs Vilanova + * + * This work is licensed under the terms of the GNU GPL, version 2 or la= ter. + * See the COPYING file in the top-level directory. + */ + +#include "backdoor/qemu/user.h" + +#include + +#include "qemu-common.h" +#include "backdoor/qemu/qemu-backdoor.h" + + +static char *data_path =3D NULL; +static char *control_path =3D NULL; +static int data_fd =3D -1; +static int control_fd =3D -1; + +static void *data =3D NULL; +static void *qemu_control_0 =3D NULL; +static void *qemu_control_1 =3D 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 si= ze, + char ** path, int *fd, void **addr) +{ + *path =3D g_malloc(strlen(base) + strlen(suffix) + 1); + sprintf(*path, "%s%s", base, suffix); + + *fd =3D open(*path, O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR); + if (*fd =3D=3D -1) { + fprintf(stderr, "error: open(%s): %s\n", *path, strerror(errno))= ; + abort(); + } + + off_t lres =3D lseek(*fd, size - 1, SEEK_SET); + if (lres =3D=3D (off_t)-1) { + fprintf(stderr, "error: lseek(%s): %s\n", *path, strerror(errno)= ); + abort(); + } + + char tmp; + ssize_t wres =3D write(*fd, &tmp, 1); + if (wres =3D=3D -1) { + fprintf(stderr, "error: write(%s): %s\n", *path, strerror(errno)= ); + abort(); + } + + if (addr) { + *addr =3D mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, *= fd, 0); + if (*addr =3D=3D MAP_FAILED) { + fprintf(stderr, "error: mmap(%s): %s\n", *path, strerror(err= no)); + abort(); + } + } +} + +void backdoor_init(const char *base, uint64_t data_size) +{ + if (base =3D=3D NULL) { + return; + } + + init_channel(base, "-data", data_size, &data_path, &data_fd, &data); + void *control; + init_channel(base, "-control", getpagesize() * 2, &control_path, &co= ntrol_fd, &control); + + /* store channel size in first 64bits; command goes into 2nd slot */ + *(uint64_t*)control =3D data_size; + + if (fstat(control_fd, &control_fd_stat) =3D=3D -1) { + fprintf(stderr, "error: fstat(backdoor_control): %s\n", strerror= (errno)); + abort(); + } + + struct sigaction segv; + memset(&segv, 0, sizeof(segv)); + segv.sa_sigaction =3D segv_handler; + segv.sa_flags =3D SA_SIGINFO | SA_RESTART; + sigemptyset(&segv.sa_mask); + + if (sigaction(SIGSEGV, &segv, &segv_next) !=3D 0) { + fprintf(stderr, "error: sigaction(SIGSEGV): %s\n", strerror(errn= o)); + abort(); + } + + qemu_backdoor_init(data_size); +} + + +static void fini_channel(int *fd, char **path) +{ + if (*fd !=3D -1) { + if (close(*fd) =3D=3D -1) { + fprintf(stderr, "error: close: %s\n", strerror(errno)); + abort(); + } + if (unlink(*path) =3D=3D -1) { + fprintf(stderr, "error: unlink(%s): %s\n", *path, strerror(e= rrno)); + abort(); + } + *fd =3D -1; + } + if (*path !=3D NULL) { + g_free(path); + *path =3D NULL; + } +} + +void backdoor_fini(void) +{ + static bool atexit_in =3D false; + if (atexit_in) { + return; + } + atexit_in =3D true; + + if (sigaction(SIGSEGV, &segv_next, NULL) !=3D 0) { + fprintf(stderr, "error: sigaction(SIGSEGV): %s\n", strerror(errn= o)); + 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) !=3D 0) { + return; + } + + if (s.st_dev !=3D control_fd_stat.st_dev || + s.st_ino !=3D control_fd_stat.st_ino) { + return; + } + + qemu_control_0 =3D qemu_addr; + qemu_control_1 =3D qemu_control_0 + getpagesize(); + if (mprotect(qemu_control_0, getpagesize(), PROT_READ) =3D=3D -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) =3D=3D -1)= { + fprintf(stderr, "error: mprotect(from): %s\n", + strerror(errno)); + abort(); + } + if (mprotect(to, getpagesize(), PROT_READ) =3D=3D -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 <=3D siginfo->si_addr && + siginfo->si_addr < qemu_control_1) { + + assert(((target_ulong)siginfo->si_addr % getpagesize()) =3D=3D s= izeof(uint64_t)); + swap_control(qemu_control_0, qemu_control_1); + + } else if (qemu_control_1 <=3D siginfo->si_addr && + siginfo->si_addr < qemu_control_1 + getpagesize()) { + + assert(((target_ulong)siginfo->si_addr % getpagesize()) =3D=3D s= izeof(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 !=3D NULL) { + segv_next.sa_sigaction(signum, siginfo, sigctxt); + } else if (segv_next.sa_handler !=3D 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=C3=ADs Vilanova + * + * This work is licensed under the terms of the GNU GPL, version 2 or la= ter. + * See the COPYING file in the top-level directory. + */ + +#include +#include + + +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 =20 #define DEBUG_LOGFILE "/tmp/qemu.log" =20 @@ -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/Op= enBSD (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 chan= nel (default: 1)\n" +#endif "\n" "Debug options:\n" "-d options activate log (default logfile=3D%s)\n" @@ -744,6 +752,10 @@ int main(int argc, char **argv) char **target_environ, **wrk; envlist_t *envlist =3D NULL; bsd_type =3D target_openbsd; +#if defined(CONFIG_BACKDOOR) + char *backdoor_base =3D NULL; + uint64_t backdoor_size =3D getpagesize(); +#endif =20 if (argc <=3D 1) usage(); @@ -851,6 +863,16 @@ int main(int argc, char **argv) singlestep =3D 1; } else if (!strcmp(r, "strace")) { do_strace =3D 1; +#if defined(CONFIG_BACKDOOR) + } else if (!strcmp(r, "backdoor")) { + if (atexit(backdoor_fini) !=3D 0) { + fprintf(stderr, "error: atexit: %s\n", strerror(errno)); + abort(); + } + backdoor_base =3D argv[optind++]; + } else if (!strcmp(r, "backdoor-pages")) { + backdoor_size =3D 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 =20 #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" =20 +#if defined(CONFIG_BACKDOOR) +#include "backdoor/qemu/user.h" +#endif + //#define DEBUG_MMAP =20 #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/Ma= kefile if test -n "$backdoor"; then mkdir -p $target_dir/libbackdoor symlink $backdoor/Makefile $target_dir/libbackdoor/Makefile + mkdir -p $target_dir/backdoor/qemu fi =20 =20 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 =20 #include "qemu.h" +#if defined(CONFIG_BACKDOOR) +#include "backdoor/qemu/user.h" +#endif =20 #define DEBUG_LOGFILE "/tmp/qemu.log" =20 @@ -713,6 +716,11 @@ static void usage(void) "-h print this help\n" "-L path set the %s library path (default=3D'%s')\n" "-s size set the stack size in bytes (default=3D%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 chan= nel (default: 1)\n" +#endif "\n" "debug options:\n" "-d options activate log (logfile=3D'%s')\n" @@ -747,6 +755,10 @@ int main(int argc, char **argv) short use_gdbstub =3D 0; const char *r; const char *cpu_model; +#if defined(CONFIG_BACKDOOR) + char *backdoor_base =3D NULL; + uint64_t backdoor_size =3D getpagesize(); +#endif =20 if (argc <=3D 1) usage(); @@ -804,6 +816,16 @@ int main(int argc, char **argv) } } else if (!strcmp(r, "singlestep")) { singlestep =3D 1; +#if defined(CONFIG_BACKDOOR) + } else if (!strcmp(r, "backdoor")) { + if (atexit(backdoor_fini) !=3D 0) { + fprintf(stderr, "error: atexit: %s\n", strerror(errno)); + abort(); + } + backdoor_base =3D argv[optind++]; + } else if (!strcmp(r, "backdoor-pages")) { + backdoor_size =3D atoi(argv[optind++]) * getpagesize(); +#endif } else { usage(); @@ -870,6 +892,9 @@ int main(int argc, char **argv) =20 syscall_init(); signal_init(); +#if defined(CONFIG_BACKDOOR) + backdoor_init(backdoor_base, backdoor_size); +#endif global_env =3D env; =20 /* 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 @@ =20 #include "qemu.h" =20 +#if defined(CONFIG_BACKDOOR) +#include "backdoor/qemu/user.h" +#endif + //#define DEBUG_MMAP =20 /* NOTE: all the constants are the HOST ones */ @@ -308,6 +312,9 @@ long target_mmap(unsigned long start, unsigned long l= en, 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 =20 #define DEBUG_LOGFILE "/tmp/qemu.log" =20 @@ -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 =3D NULL; +uint64_t backdoor_size; +#endif =20 static void usage(void); =20 @@ -3080,6 +3087,18 @@ static void handle_arg_strace(const char *arg) do_strace =3D 1; } =20 +#if defined(CONFIG_BACKDOOR) +static void handle_arg_backdoor(const char *arg) +{ + backdoor_base =3D arg; +} + +static void handle_arg_backdoor_pages(const char *arg) +{ + backdoor_size =3D 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[] =3D { {"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 (defau= lt: 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 <=3D 1) usage(); =20 + backdoor_size =3D getpagesize(); + qemu_cache_utils_init(envp); =20 if ((envlist =3D envlist_create()) =3D=3D 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 =20 #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" =20 +#if defined(CONFIG_BACKDOOR) +#include "backdoor/qemu/user.h" +#endif + //#define DEBUG_MMAP =20 #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