Permalink
Browse files

Modified evecve to detect target elf binaries to run using qemu.

  • Loading branch information...
1 parent 145271e commit 4d70225e5063bc63d4abad154390e37eab84d1f6 @staceyson committed Mar 6, 2013
View
21 work/qemu-1.4.0/bsd-user/elfload.c
@@ -1304,6 +1304,27 @@ static void load_symbols(struct elfhdr *hdr, int fd)
syminfos = s;
}
+/* Check the elf header and see if this a target elf binary. */
+int is_target_elf_binary(int fd)
+{
+ uint8_t buf[128];
+ struct elfhdr elf_ex;
+
+ if (lseek(fd, 0L, SEEK_SET) < 0)
+ return (0);
+ if (read(fd, buf, sizeof(buf)) < 0)
+ return (0);
+
+ elf_ex = *((struct elfhdr *)buf);
+ bswap_ehdr(&elf_ex);
+
+ if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
+ (! elf_check_arch(elf_ex.e_machine)))
+ return (0);
+ else
+ return (1);
+}
+
int load_elf_binary(struct bsd_binprm * bprm, struct target_pt_regs * regs,
struct image_info * info)
{
View
34 work/qemu-1.4.0/bsd-user/main.c
@@ -2,6 +2,7 @@
* qemu user main
*
* Copyright (c) 2003-2008 Fabrice Bellard
+ * Copyright (c) 2012-2013 Stacey Son
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -25,6 +26,7 @@
#include <machine/trap.h>
#include <sys/types.h>
#include <sys/mman.h>
+#include <sys/sysctl.h>
#include "qemu.h"
#include "qemu-common.h"
@@ -58,6 +60,36 @@ enum BSDType bsd_type;
by remapping the process stack directly at the right place */
unsigned long x86_stack_size = 512 * 1024;
+static void save_proc_pathname(void);
+char qemu_proc_pathname[PATH_MAX];
+
+#ifdef __FreeBSD__
+static void
+save_proc_pathname(void)
+{
+ int mib[4];
+ size_t len;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_PATHNAME;
+ mib[3] = -1;
+
+ len = sizeof(qemu_proc_pathname);
+
+ if (sysctl(mib, 4, qemu_proc_pathname, &len, NULL, 0))
+ perror("sysctl");
+}
+
+#else
+
+static void
+save_proc_pathname(void)
+{
+}
+
+#endif /* !__FreeBSD__ */
+
void gemu_log(const char *fmt, ...)
{
va_list ap;
@@ -1496,6 +1528,8 @@ int main(int argc, char **argv)
if (argc <= 1)
usage();
+ save_proc_pathname();
+
module_call_init(MODULE_INIT_QOM);
if ((envlist = envlist_create()) == NULL) {
View
14 work/qemu-1.4.0/bsd-user/qemu.h
@@ -64,15 +64,15 @@ struct image_info {
#define MAX_SIGQUEUE_SIZE 1024
-struct sigqueue {
- struct sigqueue *next;
+struct qemu_sigqueue {
+ struct qemu_sigqueue *next;
target_siginfo_t info;
};
struct emulated_sigtable {
int pending; /* true if signal is pending */
- struct sigqueue *first;
- struct sigqueue info; /* in order to always have memory for the
+ struct qemu_sigqueue *first;
+ struct qemu_sigqueue info; /* in order to always have memory for the
first signal, we put it here */
};
@@ -95,8 +95,8 @@ typedef struct TaskState {
struct bsd_binprm *bprm;
struct emulated_sigtable sigtab[TARGET_NSIG];
- struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */
- struct sigqueue *first_free; /* first free siginfo queue entry */
+ struct qemu_sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */
+ struct qemu_sigqueue *first_free; /* first free siginfo queue entry */
int signal_pending; /* non zero if a signal may be pending */
uint8_t stack[0];
@@ -146,6 +146,7 @@ int load_elf_binary(struct bsd_binprm * bprm, struct target_pt_regs * regs,
struct image_info * info);
int load_flt_binary(struct bsd_binprm * bprm, struct target_pt_regs * regs,
struct image_info * info);
+int is_target_elf_binary(int fd);
void target_set_brk(abi_ulong new_brk);
abi_long do_brk(abi_ulong new_brk);
@@ -222,6 +223,7 @@ void mmap_fork_end(int child);
/* main.c */
extern unsigned long x86_stack_size;
+extern char qemu_proc_pathname[];
/* user access */
View
10 work/qemu-1.4.0/bsd-user/signal.c
@@ -286,11 +286,11 @@ core_dump_signal(int sig)
}
/* Signal queue handling. */
-static inline struct sigqueue *
+static inline struct qemu_sigqueue *
alloc_sigqueue(CPUArchState *env)
{
TaskState *ts = env->opaque;
- struct sigqueue *q = ts->first_free;
+ struct qemu_sigqueue *q = ts->first_free;
if (!q)
return (NULL);
@@ -299,7 +299,7 @@ alloc_sigqueue(CPUArchState *env)
}
static inline void
-free_sigqueue(CPUArchState *env, struct sigqueue *q)
+free_sigqueue(CPUArchState *env, struct qemu_sigqueue *q)
{
TaskState *ts = env->opaque;
@@ -372,7 +372,7 @@ queue_signal(CPUArchState *env, int sig, target_siginfo_t *info)
{
TaskState *ts = env->opaque;
struct emulated_sigtable *k;
- struct sigqueue *q, **pq;
+ struct qemu_sigqueue *q, **pq;
abi_ulong handler;
int queue;
@@ -1049,7 +1049,7 @@ process_pending_signals(CPUArchState *cpu_env)
target_sigset_t target_old_set;
struct emulated_sigtable *k;
struct target_sigaction *sa;
- struct sigqueue *q;
+ struct qemu_sigqueue *q;
TaskState *ts = cpu_env->opaque;
if (!ts->signal_pending)
View
151 work/qemu-1.4.0/bsd-user/syscall.c
@@ -100,6 +100,70 @@
static abi_ulong target_brk;
static abi_ulong target_original_brk;
+static char *get_filename_from_fd(pid_t pid, int fd, char *filename, size_t len);
+
+#ifdef __FreeBSD__
+#include <sys/queue.h>
+#include <sys/user.h>
+#include <libprocstat.h>
+
+
+/*
+ * Get the filename for the given file descriptor.
+ * Note that this may return NULL (fail) if no longer cached in the kernel.
+ */
+static char *
+get_filename_from_fd(pid_t pid, int fd, char *filename, size_t len)
+{
+ unsigned int cnt;
+ struct procstat *procstat = NULL;
+ struct kinfo_proc *kipp = NULL;
+ struct filestat_list *head = NULL;
+ struct filestat *fst;
+ char *ret = NULL;
+
+ procstat = procstat_open_sysctl();
+ if (NULL == procstat)
+ goto out;
+
+ kipp = procstat_getprocs(procstat, KERN_PROC_PID, pid, &cnt);
+ if (NULL == kipp)
+ goto out;
+
+ head = procstat_getfiles(procstat, kipp, 0);
+ if (NULL == head)
+ goto out;
+
+ STAILQ_FOREACH(fst, head, next) {
+ if (fd == fst->fs_fd) {
+ if (fst->fs_path != NULL) {
+ (void)strlcpy(filename, fst->fs_path, len);
+ ret = filename;
+ }
+ break;
+ }
+ }
+
+out:
+ if (head != NULL)
+ procstat_freefiles(procstat, head);
+ if (kipp != NULL)
+ procstat_freeprocs(procstat, kipp);
+ if (procstat != NULL)
+ procstat_close(procstat);
+ return (ret);
+}
+
+#else
+
+static char *
+get_filename_from_fd(pid_t pid, int fd, char *filename, size_t len)
+{
+ return (NULL);
+}
+
+#endif /* ! __FreeBSD__ */
+
static inline abi_long get_errno(abi_long ret)
{
if (ret == -1)
@@ -4196,7 +4260,7 @@ static inline abi_long
freebsd_exec_common(abi_ulong path_or_fd, abi_ulong guest_argp,
abi_ulong guest_envp, int do_fexec)
{
- char **argp, **envp;
+ char **argp, **envp, **qargp, **qarg1;
int argc, envc;
abi_ulong gp;
abi_ulong addr;
@@ -4208,40 +4272,51 @@ freebsd_exec_common(abi_ulong path_or_fd, abi_ulong guest_argp,
argc = 0;
for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
if (get_user_ual(addr, gp))
- goto execve_efault;
+ return (-TARGET_EFAULT);
if (!addr)
break;
argc++;
}
envc = 0;
for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
if (get_user_ual(addr, gp))
- goto execve_efault;
+ return (-TARGET_EFAULT);
if (!addr)
break;
envc++;
}
- argp = alloca((argc + 1) * sizeof(void *));
+ qargp = argp = alloca((argc + 3) * sizeof(void *));
+ /* save the first agrument for the emulator */
+ *argp++ = (char *)getprogname();
+ qarg1 = argp;
envp = alloca((envc + 1) * sizeof(void *));
for (gp = guest_argp, q = argp; gp; gp += sizeof(abi_ulong), q++) {
- if (get_user_ual(addr, gp))
- goto execve_efault;
+ if (get_user_ual(addr, gp)) {
+ ret = -TARGET_EFAULT;
+ goto execve_end;
+ }
if (!addr)
break;
- if (!(*q = lock_user_string(addr)))
- goto execve_efault;
+ if (!(*q = lock_user_string(addr))) {
+ ret = -TARGET_EFAULT;
+ goto execve_end;
+ }
total_size += strlen(*q) + 1;
}
*q = NULL;
for (gp = guest_envp, q = envp; gp; gp += sizeof(abi_ulong), q++) {
- if (get_user_ual(addr, gp))
- goto execve_efault;
+ if (get_user_ual(addr, gp)) {
+ ret = -TARGET_EFAULT;
+ goto execve_end;
+ }
if (!addr)
break;
- if (!(*q = lock_user_string(addr)))
- goto execve_efault;
+ if (!(*q = lock_user_string(addr))) {
+ ret = -TARGET_EFAULT;
+ goto execve_end;
+ }
total_size += strlen(*q) + 1;
}
*q = NULL;
@@ -4256,14 +4331,53 @@ freebsd_exec_common(abi_ulong path_or_fd, abi_ulong guest_argp,
}
if (do_fexec) {
- ret = get_errno(fexecve((int)path_or_fd, argp, envp));
+ if (((int)path_or_fd > 0 &&
+ is_target_elf_binary((int)path_or_fd)) == 1) {
+ char execpath[PATH_MAX];
+
+ /*
+ * The executable is an elf binary for the target
+ * arch. execve() it using the emulator if we can
+ * determine the filename path from the fd.
+ */
+ if (get_filename_from_fd(getpid(), (int)path_or_fd,
+ execpath, sizeof(execpath)) != NULL) {
+ *qarg1 = execpath;
+ ret = get_errno(execve(qemu_proc_pathname,
+ qargp, envp));
+ } else {
+ /* Getting the filename path failed. */
+ ret = -TARGET_EBADF;
+ goto execve_end;
+ }
+ } else {
+ ret = get_errno(fexecve((int)path_or_fd, argp, envp));
+ }
} else {
- if (!(p = lock_user_string(path_or_fd)))
- goto execve_efault;
- ret = get_errno(execve(p, argp, envp));
+ int fd;
+
+ if (!(p = lock_user_string(path_or_fd))) {
+ ret = -TARGET_EFAULT;
+ goto execve_end;
+ }
+
+ /*
+ * Check the header and see if it a target elf binary. If so
+ * then execute using qemu user mode emulator.
+ */
+ fd = open(p, O_RDONLY | O_CLOEXEC);
+ if (fd > 0 && is_target_elf_binary(fd) == 1) {
+ close(fd);
+ /* Execve() as a target binary using emulator. */
+ *qarg1 = (char *)p;
+ ret = get_errno(execve(qemu_proc_pathname, qargp, envp));
+ } else {
+ close(fd);
+ /* Execve() as a host native binary. */
+ ret = get_errno(execve(p, argp, envp));
+ }
unlock_user(p, path_or_fd, 0);
}
- goto execve_end;
execve_end:
for (gp = guest_argp, q = argp; *q; gp += sizeof(abi_ulong), q++) {
@@ -4278,9 +4392,6 @@ freebsd_exec_common(abi_ulong path_or_fd, abi_ulong guest_argp,
unlock_user(*q, addr, 0);
}
return (ret);
-
-execve_efault:
- return (-TARGET_EFAULT);
}
static inline abi_long
View
5 work/qemu-1.4.0/configure
@@ -434,8 +434,9 @@ FreeBSD)
make="${MAKE-gmake}"
audio_drv_list="oss"
audio_possible_drivers="oss sdl esd pa"
- # needed for kinfo_getvmmap(3) in libutil.h
- LIBS="-lutil $LIBS"
+ # -lutil needed for kinfo_getvmmap(3) in libutil.h
+ # -lprocstat needed for procstat_*(3) in main.c
+ LIBS="-lprocstat -lutil $LIBS"
;;
DragonFly)
bsd="yes"

0 comments on commit 4d70225

Please sign in to comment.