Skip to content

Panda supports 64-bit LAVA #1574

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion panda/debian/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
panda.deb
*.deb
*.whl
2 changes: 1 addition & 1 deletion panda/plugins/dwarf2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Summary
-------

The `dwarf2` plugin is to be a replacement of `pri_dwarf` plugin. The workflow is to run
`dwarfdump -dil ${TARGET_PROG} | PYTHONPATH="panda/scripts/" python -c "import sys;import dwarfdump;dwarfdump.parse_dwarfdump(sys.stdin.read(), '${TARGET_PROG}')"`.
`dwarfdump -dil ${TARGET_PROG} | python -c "import sys;from pandare.extras import dwarfdump;dwarfdump.parse_dwarfdump(sys.stdin.read(), '${TARGET_PROG}')"`.
This is going to generate 4 json DWARF symbol files including: Line Info, Global Variables, Function Info, and Type Info. Place these json files under debug path for this plugin to read.

Arguments
Expand Down
658 changes: 337 additions & 321 deletions panda/plugins/dwarf2/dwarf2.cpp

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion panda/plugins/dwarf2/dwarf2_types.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

typedef void (*dwarfTypeCB)(target_ulong buf, LocType loc_t, target_ulong buf_len, const char *astnodename);
typedef void (*dwarfTypeCB)(CPUState *env, target_ulong buf, LocType loc_t, target_ulong buf_len, const char *astnodename);

struct DwarfTypeInfo;
typedef struct {
Expand Down
6 changes: 3 additions & 3 deletions panda/plugins/hypercaller/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ This was designed primarily for Python use cases:
MAGIC = 0x12345678
@panda.hypercall(MAGIC)
def hypercall(cpu):
print("Hello from my hypercall!"
print("Hello from my hypercall!")

```

Expand All @@ -64,7 +64,7 @@ It's much easier to handle this from Python, but here's an example of how you mi
#include <panda/plugin.h>
#include <hypercaller/hypercaller.h>

hypercall_t* register_hypercall;
register_hypercall_t register_hypercall;
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I worked with @jamcleod, so it was decided to add this to the header, from there, I was able to to use hypercaller.h correctly in pri_taint.

The documentation also matches the new code in pri_taint.


void my_hypercall(CPUState *cpu) {
printf("Hello from my hypercall!\n");
Expand All @@ -76,7 +76,7 @@ bool init_plugin(void *self) {
panda_require("hypercaller");
hypercaller = panda_get_plugin_by_name("hypercaller");
}
register_hypercall = (hypercall_t*)dlsym(hypercaller, "register_hypercall");
register_hypercall_t register_hypercall = (register_hypercall_t) dlsym(hypercaller, "register_hypercall");
register_hypercall(0x12345678, my_hypercall);
return true;
}
Expand Down
1 change: 1 addition & 0 deletions panda/plugins/hypercaller/hypercaller.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
// files in this directory that contain subsections like this one.

typedef void (*hypercall_t)(CPUState *cpu);
typedef void (*register_hypercall_t)(uint32_t, hypercall_t);
void register_hypercall(uint32_t magic, hypercall_t);
void unregister_hypercall(uint32_t magic);

Expand Down
192 changes: 122 additions & 70 deletions panda/plugins/loaded/loaded.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ PANDAENDCOMMENT */
#include <cstdio>
#include <map>
#include <memory>
#include <sys/mman.h>

#include "panda/plugin.h"
#include "panda/plugin_plugin.h"
Expand Down Expand Up @@ -52,14 +53,14 @@ PPP_PROT_REG_CB(on_library_load);
// This creates the global for this call back fn (on_library_load)
PPP_CB_BOILERPLATE(on_library_load)

bool debug = true;
bool debug = false;
#define dprintf(...) if (debug) { printf(__VA_ARGS__); fflush(stdout); }

#define MAX_FILENAME 256
std::map <target_ulong, OsiProc> running_procs;

void die(const char* fmt, ...) {
va_list args;

va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
Expand All @@ -80,116 +81,167 @@ uint32_t guest_strncpy(CPUState *cpu, char *buf, size_t maxlen, target_ulong gue
return i;
}

#if defined(TARGET_I386) && !defined(TARGET_X86_64)
// 125 long sys_mprotect ['unsigned long start', ' size_t len', 'unsigned long prot']
void linux_mprotect_return(CPUState* cpu,target_ulong pc,uint32_t start,uint32_t len,uint32_t prot) {
if (debug) {
printf("[loaded] mprotect()\n");
}
}
// 90 long sys_old_mmap ['struct mmap_arg_struct __user *arg']
void linux_old_mmap_return(CPUState *cpu, target_ulong pc, uint32_t arg_ptr) {
if (debug) {
printf("[loaded] old mmap()\n");
}
}

void linux_mmap_pgoff_return(CPUState *cpu,target_ulong pc,uint32_t addr,uint32_t len,uint32_t prot,uint32_t flags,uint32_t fd,uint32_t pgoff) {
CPUArchState *env = (CPUArchState*)cpu->env_ptr;
target_ulong asid = panda_current_asid(cpu);
if (running_procs.count(asid) == 0) {
//printf ("linux_mmap_pgoff_enter for asid=0x%x fd=%d -- dont know about that asid. discarding \n", (unsigned int) asid, (int) fd);
return;
}
if ((int32_t) fd == -1){
//printf ("linux_mmap_pgoff_enter for asid=0x%x fd=%d flags=%x -- not valid fd . . . \n", (unsigned int) asid, (int) fd, flags);
return;
}
OsiProc proc = running_procs[asid];
char *filename = osi_linux_fd_to_filename(cpu, &proc, fd);
// gets us offset into the file. could be useful
//uint64_t pos = osi_linux_fd_to_pos(env, &proc, fd);
// if a filename exists and permission is executable
// TODO: fix this magic constant of 0x04 for PROT_EXEC
if (filename != NULL && ((prot & 0x04) == 0x04)) {
if (debug) {
printf ("[loaded] linux_mmap_pgoff(fd=%d filename=[%s] "
"len=%d prot=%x flags=%x "
"pgoff=%d)=" TARGET_FMT_lx "\n", (int) fd,
filename, len, prot, flags, pgoff, env->regs[R_EAX]);
}
PPP_RUN_CB(on_library_load, cpu, pc, filename, env->regs[R_EAX], len)
} else if ((prot & 0x04) == 0x04) {
printf("[loaded] mapped executable section without a filename!\n");
printf ("[loaded] linux_mmap_pgoff(fd=%d "
"len=%d prot=%x flags=%x "
"pgoff=%d)=" TARGET_FMT_lx "\n", (int) fd,
len, prot, flags, pgoff, env->regs[R_EAX]);
}
}
#endif

// get current process before each bb execs
// which will probably help us actually know the current process
void osi_foo(CPUState *cpu, TranslationBlock *tb) {

if (panda_in_kernel(cpu)) {

std::unique_ptr<OsiProc, decltype(free_osiproc)*> p { get_current_process(cpu), free_osiproc };

//some sanity checks on what we think the current process is
// some sanity checks on what we think the current process is
// we couldn't find the current task
if (!p) return;
if (!p) {
return;
}
// this means we didnt find current task
if (p->taskd == 0) return;
if (p->taskd == 0) {
return;
}
// or the name
if (p->name == 0) return;
if (p->name == 0) {
return;
}
// this is just not ok
if (((int) p->pid) == -1) return;
if (((int) p->pid) == -1) {
return;
}
uint32_t n = strnlen(p->name, 32);
// name is one char?
if (n<2) return;
if (n < 2) {
return;
}
uint32_t np = 0;
for (uint32_t i=0; i<n; i++) {
np += (isprint(p->name[i]) != 0);
}
// name doesnt consist of solely printable characters
// printf ("np=%d n=%d\n", np, n);
if (np != n) return;
if (np != n) {
return;
}
target_ulong asid = panda_current_asid(cpu);
if (running_procs.count(asid) == 0) {
printf ("adding asid=0x%x to running procs. cmd=[%s] task=0x%x\n", (unsigned int) asid, p->name, (unsigned int) p->taskd);
printf("[loaded] adding asid=0x%x to running procs. cmd=[%s] task=0x%x\n", (unsigned int) asid, p->name, (unsigned int) p->taskd);
}
running_procs[asid] = *p;
}

return;
}
bool init_plugin(void *self) {
//panda_arg_list *args = panda_get_args("loaded");

#if defined(TARGET_I386) || defined(TARGET_ARM)
#if defined(TARGET_I386) && !defined(TARGET_X86_64) || defined(TARGET_ARM) && !defined(TARGET_AARCH64)
// technically for 32-bit it is pgoff, not offset! But I want to avoid code duplication!
void linux_mmap_return(CPUState *cpu, target_ulong pc, uint32_t addr, uint32_t len, uint32_t prot, uint32_t flags, uint32_t fd, uint32_t offset)
#elif defined(TARGET_X86_64)
void linux_mmap_return(CPUState *cpu, target_ulong pc, uint64_t addr, uint64_t len, uint64_t prot, uint64_t flags, uint64_t fd, uint64_t offset)
#elif defined(TARGET_AARCH64)
void linux_mmap_return(CPUState* cpu, target_ulong pc, uint64_t addr, uint32_t len, int32_t prot, int32_t flags, int32_t fd, uint64_t offset)
#endif
Comment on lines +131 to +138
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the real change, I updated the function to work both i386, x86_64 and ARM. ARM might be needed for future LAVA work

{
dprintf("[loaded] linux_mmap_return is called!\n");
CPUArchState *env = (CPUArchState*)cpu->env_ptr;
target_ulong asid = panda_current_asid(cpu);
if (running_procs.count(asid) == 0) {
return;
}
if (fd == -1) {
return;
}
dprintf("[loaded] linux_mmap_return is called, with OK fd and non-zero running proc\n");
OsiProc proc = running_procs[asid];
char *filename = osi_linux_fd_to_filename(cpu, &proc, fd);
// gets us offset into the file. could be useful
// uint64_t pos = osi_linux_fd_to_pos(env, &proc, fd);
// if a filename exists and permission is executable
#if defined(TARGET_I386) && !defined(TARGET_X86_64)
dprintf("[loaded] linux_mmap_pgoff(fd=%d filename=[%s] "
"len=%d prot=%x flags=%x "
"pgoffset=%d)=" TARGET_FMT_lx "\n", (int) fd,
filename, len, prot, flags, offset, env->regs[R_EAX]);
#elif defined(TARGET_ARM) && !defined(TARGET_AARCH64)
dprintf("[loaded] linux_mmap_pgoff(fd=%d filename=[%s] "
"len=%u prot=%u flags=%u "
"pgoffset=%d)=" TARGET_FMT_lx "\n", (int) fd,
filename, len, prot, flags, offset, env->regs[0]);
#elif defined(TARGET_X86_64)
dprintf("[loaded] linux_mmap_pgoff(fd=%lu filename=[%s] "
"len=%lu prot=%lu flags=%lu "
"pgoff=%lu)=" TARGET_FMT_lx "\n", (unsigned long) fd,
filename, (unsigned long) len, (unsigned long) prot, (unsigned long) flags, (unsigned long) offset, env->regs[R_EAX]);
#elif defined(TARGET_AARCH64)
printf("[loaded] linux_mmap(fd=%d filename=[%s] "
"len=%u prot=%x flags=%x "
"pgoff=%lu)=" TARGET_FMT_lx "\n", fd,
filename, len, prot, flags, offset, env->xregs[0]);
#endif

if (filename != NULL && ((prot & PROT_EXEC) == PROT_EXEC)) {
// See 'dwarf2.cpp' for the definition of 'on_library_load'
dprintf("[loaded] Calling on_library_load\n");
#if defined(TARGET_I386)
PPP_RUN_CB(on_library_load, cpu, pc, filename, env->regs[R_EAX], len);
#elif defined(TARGET_AARCH64)
PPP_RUN_CB(on_library_load, cpu, pc, filename, env->xregs[0], len);
#elif defined(TARGET_ARM) && !defined(TARGET_AARCH64)
PPP_RUN_CB(on_library_load, cpu, pc, filename, env->regs[0], len);
#endif
}
else if ((prot & PROT_EXEC) == PROT_EXEC) {
printf("[loaded] mapped executable section without a filename!\n");
}
else {
if (filename == NULL) {
dprintf("[loaded] I got a null file name\n");
}
else {
dprintf("[loaded] It seems like filename %s was null, OR PROT_EXEC was not there\n", filename);
}
}
}
#endif

bool init_plugin(void *self) {
panda_require("osi");
assert(init_osi_api());
panda_require("osi_linux");
assert(init_osi_linux_api());
panda_require("syscalls2");
panda_arg_list *args = panda_get_args("loaded");
debug = panda_parse_bool_opt(args, "debug", "enable debug output");

#if defined(TARGET_I386) && !defined(TARGET_X86_64)
{
panda_cb pcb;
pcb.before_block_exec = osi_foo;
panda_register_callback(self, PANDA_CB_BEFORE_BLOCK_EXEC, pcb);
}
PPP_REG_CB("syscalls2", on_sys_mmap_pgoff_return, linux_mmap_return);
printf("[loaded] The plugin is supported on i386\n");
#elif defined(TARGET_ARM) && !defined(TARGET_AARCH64)
{
panda_cb pcb;
pcb.before_block_exec = osi_foo;
panda_register_callback(self, PANDA_CB_BEFORE_BLOCK_EXEC, pcb);
}

PPP_REG_CB("syscalls2", on_sys_mmap_pgoff_return, linux_mmap_pgoff_return);
// don't use these at them moment
//PPP_REG_CB("syscalls2", on_sys_old_mmap_return, linux_old_mmap_return);
//PPP_REG_CB("syscalls2", on_sys_mprotect_return, linux_mprotect_return);
PPP_REG_CB("syscalls2", on_do_mmap2_return, linux_mmap_return);
printf("[loaded] The plugin is supported on ARM 32-bits\n");
#elif defined(TARGET_X86_64) || defined(TARGET_AARCH64)
{
panda_cb pcb;
pcb.before_block_exec = osi_foo;
panda_register_callback(self, PANDA_CB_BEFORE_BLOCK_EXEC, pcb);
}
// Tell Plugin 'syscall2', that if a systemcall 'mmap' occurs, then run the code in 'linux_mmap_return'
// https://www.linuxquestions.org/questions/linux-general-1/difference-between-mmap2-syscall-and-mmap_pgoff-syscall-for-32-bit-linux-4175622986/
PPP_REG_CB("syscalls2", on_sys_mmap_return, linux_mmap_return);
printf("[loaded] The plugin is supported on x86-64 and ARM 64-bits\n");
#else
fprintf(stderr, "The loaded plugin is not currently supported on this platform.\n");
fprintf(stderr, "[loaded] The plugin is not currently supported on this platform.\n");
return false;
#endif
return true;
}

void uninit_plugin(void *self) { }
void uninit_plugin(void *self) {
printf("[loaded] uninit_plugin\n");
}
Loading
Loading