Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Rewrite of the sandbox with another approach, thread based.

Instead of "emulating" syscalls, the untrusted process now runs two threads. One
of them is running the untrusted code still under SECCOMP while the other
one is a trusted routine which will performs syscalls when the helper process
asks him.

This is in fact a generalization of the Chrome browser method.

There are still some TODO:

  - The security rules are still NOP
  - Performances penalty: Each untrusted syscall generates at least 6
    read/write (4 of them are dedicated to write the return values).
  - Memory area of the routine must never be writable for the untrusted
    thread. It was not investigate yet but maybe we should to not call the
    VDSO page anymore to really perform the syscalls because it pushes
    variables on the stack.
  • Loading branch information...
commit 88b008b83c6bce13c0c9174f3a005e7adee6a54e 1 parent b490e03
@nbareil authored committed
View
23 Makefile
@@ -1,21 +1,16 @@
#! /usr/bin/make -f
-CFLAGS=-O2 -Wall -w -Wextra
+CFLAGS=-O2 -Wall -w -Wextra -g
+BINARIES=sandbox.so sandbox
-libgs.so.1.0.1: dlmalloc.o common.o mm.o helper.o jail.o inject.o
- gcc -shared -WI,soname,libgs.so.1 -o libgs.so.1.0.1 dlmalloc.o common.o mm.o helper.o jail.o inject.o -lc -ldl
+.PHONY: all clean
-dlmalloc.o:
- $(CC) $(CFLAGS) -DMSPACES=1 -DUSE_DL_PREFIX=1 -DONLY_MSPACES=1 -c $(@:.o=.c)
+all: $(BINARIES)
-.PHONY: syscalls clean
-
-syscalls: gen_syscall_lists.py syscall.py
- rm -fr autogen
- mkdir autogen
- python gen_syscall_lists.py > autogen/syscall_32.py
+sandbox.so: companion.o common.o helper.o jail.o inject.o
+ gcc -shared -WI,soname,$@.1 -o $@ $^ -lc -ldl -lrt
clean:
- rm -f *.o *pyc
- rm -f libgs.so.1.0.1
- rm -fr autogen
+ rm -f *.so *.o *pyc $(BINARIES)
+
+
View
14 companion.h
@@ -0,0 +1,14 @@
+
+#ifndef __COMPANION_H
+#define __COMPANION_H
+
+#define JUNK_SIZE 4
+#define OFFSET_SYSCALL_DROPBOX 0
+
+unsigned int range_start, range_end, syscall_dropbox;
+char junk_zone[JUNK_SIZE];
+char retarray[256];
+
+extern void companion_routine(void);
+
+#endif
View
86 companion.s
@@ -0,0 +1,86 @@
+ .section .text
+
+ .global range_start
+ .global range_end
+ .global junk_zone
+ .global syscall_dropbox
+ .global retarray
+
+/**
+ * wait_for_trigger() - wait for order
+ *
+ * This routine is blocking on a read() on the control socket, when
+ * 4 bytes are read, this is the signal that the syscall drop box is
+ * ready and can be executed.
+ *
+ * The buffer where bytes are written is the junk zone, theses bytes
+ * are undefined and must be ignored.
+ *
+ */
+wait_for_trigger:
+
+loop_read:
+ movl $3, %ebx
+ movl $junk_zone, %ecx
+ movl $4, %edx ; JUNK_SIZE=4
+ movl $3, %eax
+ int $0x80
+
+ cmpl $0, %eax
+ jle out
+
+ call execute_syscall
+ jmp loop_read
+
+out:
+ int3
+ ret
+
+/**
+ * execute_syscall() - execute syscall written in shared area
+ *
+ * %eax to %edi registers values are extracted from the protected
+ * area 'syscall_dropbox' which is only writable by the trusted
+ * process.
+ *
+ */
+execute_syscall:
+ mov syscall_dropbox, %edi
+ movl 0(%edi), %eax
+ movl 4(%edi), %ebx
+ movl 8(%edi), %ecx
+ movl 12(%edi), %edx
+ movl 16(%edi), %esi
+ movl 20(%edi), %edi
+ int $0x80
+
+ movl %eax, %esi
+ movl $4, %edi
+
+loop_ret:
+ cmp $0, %edi
+ jle real_ret
+
+ mov %esi, %edx
+ andl $0xff, %edx
+ movl $4, %eax
+ movl $3, %ebx
+ lea retarray(%edx), %ecx
+ movl $1, %edx
+ shrl $8, %esi
+ int $0x80
+ decl %edi
+ jmp loop_ret
+
+real_ret:
+ ret
+
+/**
+ * companion_routine() - companion thread
+ *
+ */
+ .global companion_routine
+companion_routine:
+ movl range_start, %eax
+ call wait_for_trigger
+ ret
View
22 doc/DESIGN.org
@@ -453,3 +453,25 @@ void handler(void) {
Behing theses primitives, the whole logic is done in the trusted
process.
+* Hybrid approach
+
+ Either we limit the usage of the trusted thread for specifc case
+ where it is not possible to do the action otherwise, or we always
+ use the trusted thread.
+
+*** Case 1 : Always use of the trusted thread
+
+ Pros:
+ + Performance boost!
+ + A lot more cleaner
+
+ Cons:
+ - The attack surface is increased if we do not do sanitize perfectly
+ the arguments
+
+*** Case 2: Hybrid
+
+ Pros:
+
+
+ Cons:
View
7 helper.c
@@ -3,6 +3,7 @@
#include <errno.h>
#include "helper.h"
+#include "companion.h"
#include "common.h"
#include "mm.h"
@@ -51,7 +52,6 @@ int wait_for_orders(const int fd) {
while (1) {
fxread(fd, &msgtype, sizeof msgtype);
-
switch (msgtype) {
case PEEK_ASCIIZ:
fxread(fd, &addr, sizeof addr);
@@ -78,9 +78,8 @@ int wait_for_orders(const int fd) {
_exit(ret);
break;
- case MEMORY_POOL:
- DEBUGP("big_memory_pool = %#p\n", big_memory_pool);
- write(fd, &big_memory_pool, sizeof big_memory_pool);
+ case MEMORY_POOL:
+ write(fd, &range_start, sizeof range_start);
break;
case RAISE_TRAP:
View
3  helper.h
@@ -9,4 +9,5 @@ enum {
RAISE_TRAP,
};
-static int controlfd = -1;
+#define THREAD_FD 3
+#define CONTROL_FD 4
View
82 hybrid-trusted.c
@@ -0,0 +1,82 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/stat.h> /* For mode constants */
+#include <fcntl.h> /* For O_* constants */
+#include <error.h>
+#include <unistd.h>
+#include <asm/unistd.h>
+
+#define SHMEM_NAME "/seccompnurse"
+#define SHMEM_MODE 0700
+#define SHMEM_SIZE 0x10
+
+#define CONTROL_FD 3
+#define OFFSET_SYSCALL_DROPBOX 0
+#define PING "PING"
+
+#define TEST_FILE "/tmp/seccomp-nurse.test"
+
+struct registers {
+ unsigned int eax, ebx, ecx, edx, esi, edi;
+};
+
+void relay_orders(char *protected_area, char *remote_addr) {
+ struct registers *regs = (struct registers *)protected_area;
+ unsigned int offset = sizeof(*regs);
+ char *buf1 = protected_area+offset;
+
+ memcpy(buf1, TEST_FILE, sizeof TEST_FILE);
+ memset(regs, 0, sizeof regs);
+
+ *(buf1) = '.';
+ while (1) {
+ regs->eax = __NR_write;
+ regs->ebx = STDOUT_FILENO;
+ regs->ecx = remote_addr+offset;
+ regs->edx = 1;
+ write(CONTROL_FD, PING, sizeof PING);
+ sleep(1);
+ }
+}
+
+int main(int argc, char *argv[]) {
+ int fd;
+ unsigned int remoteoffset;
+ void *shmem;
+ char *remote_protected_area;
+ int *flag;
+
+ fd = shm_open(SHMEM_NAME, O_CREAT|O_RDWR, SHMEM_MODE);
+ if (fd < 0) {
+ perror("shm_open()");
+ exit(1);
+ }
+
+ if (ftruncate(fd, SHMEM_SIZE) != 0) {
+ perror("ftruncate()");
+ goto unlink_shmem;
+ }
+
+ shmem = mmap(NULL, SHMEM_SIZE, PROT_WRITE, MAP_SHARED, fd, 0);
+ if (shmem == MAP_FAILED) {
+ perror("mmap()");
+ goto unlink_shmem;
+ }
+
+ read(3, &remote_protected_area, sizeof remote_protected_area);
+ remoteoffset = abs(remote_protected_area - (int)shmem);
+ relay_orders(shmem, remote_protected_area);
+
+unlink_shmem:
+ if (shm_unlink(SHMEM_NAME) != 0) {
+ perror("shm_unlink()");
+ exit(2);
+ }
+
+ unmap_shmem:
+ if (munmap(shmem, SHMEM_SIZE) != 0) {
+ perror("munmap()");
+ exit(4);
+ }
+}
View
36 hybrid-untrusted.c
@@ -0,0 +1,36 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <sys/stat.h> /* For mode constants */
+#include <fcntl.h> /* For O_* constants */
+#include <error.h>
+#include <errno.h>
+#include <sys/prctl.h>
+#include <sched.h>
+
+#include <dlfcn.h>
+#include <link.h>
+
+#include "common.h"
+#include "inject.h"
+#include "jail.h"
+#include "mm.h"
+
+#define SHMEM_NAME "/seccompnurse"
+#define SHMEM_MODE 277
+#define SHMEM_SIZE 0x10
+#define JUNK_SIZE 4
+#define OFFSET_SYSCALL_DROPBOX 0
+
+extern void helper_start(void);
+unsigned int range_start, range_end, syscall_dropbox;
+char junk_zone[JUNK_SIZE];
+
+int trusted_thread(void *shmem) {
+ helper();
+ exit(0);
+}
+
+
View
263 hybrid.py
@@ -0,0 +1,263 @@
+#! /usr/bin/env python
+
+import mmap, os, struct
+import logging
+
+from syscalls import *
+from errno import *
+from trustedthread import TrustedThread
+import security
+
+lvl = logging.DEBUG
+logging.basicConfig(level=lvl,
+ format="%(name)15.15s %(levelname)5s: %(message)s")
+
+mainlog = logging.getLogger("trusted")
+sandboxlog = logging.getLogger("sandbox.action")
+tubelog = logging.getLogger("sandbox.tube")
+
+THREAD_FD = 3
+CONTROL_FD = 4
+SHMEM_SIZE = 0x100
+SHMEM_FILENAME = '/dev/shm/seccompnurse'
+
+class Memory:
+ def __init__(self, eax=0, ebx=0, ecx=0, edx=0, esi=0, edi=0, ebp=0):
+ (self.eax, self.ebx,
+ self.ecx, self.edx,
+ self.esi, self.edi,
+ self.ebp) = (eax, ebx, ecx, edx, esi, edi, ebp)
+
+ @staticmethod
+ def parse(raw):
+ regs = struct.unpack('7I', raw)
+ return Memory(*regs)
+
+ def pack(self):
+ return struct.pack('7I',
+ self.eax, self.ebx,
+ self.ecx, self.edx,
+ self.esi, self.edi,
+ self.ebp)
+
+ def aslist(self):
+ return [self.eax, self.ebx,
+ self.ecx, self.edx,
+ self.esi, self.edi,
+ self.ebp]
+
+ def __repr__(self):
+ return 'eax=%x ebx=%x ecx=%x edx=%x esi=%x edi=%x ebp=%x' % (self.eax, self.ebx,
+ self.ecx, self.edx,
+ self.esi, self.edi,
+ self.ebp)
+
+syscalls_table = {}
+def syscall(nr, argc):
+ def _syscall(func):
+ def __syscall(*args, **kwargs):
+ arguments = list(args[1:__syscall.argc+1])
+ sandboxlog.info('+++ %s(%s)' % (__syscall.name, ','.join(map(str, map(hex, arguments)))))
+ return func(*args, **kwargs)
+ __syscall.nr = nr
+ __syscall.argc = argc
+ __syscall.name = syscallnr2human[nr][2:]
+ syscalls_table[nr] = __syscall
+ return __syscall
+ return _syscall
+
+DO_SYSCALL = 1
+PEEK_ASCIIZ = 2
+PEEK_MEMORY = 3
+POKE_MEMORY = 4
+RETVAL = 5
+NATIVE_EXIT = 6
+PROTECTED_AREA = 7
+RAISE_TRAP = 8
+
+class HybridSandbox:
+ def __init__(self):
+ self.control = os.fdopen(CONTROL_FD, 'w+', 0)
+ shmem = self.shmem_open()
+ self.trustedthread = TrustedThread(THREAD_FD, shmem)
+ self.security = security.SecurityManager()
+
+ def shmem_open(self):
+ self.shmemfd = open(SHMEM_FILENAME, 'w+')
+ self.shmemfd.truncate(SHMEM_SIZE)
+ return mmap.mmap(self.shmemfd.fileno(), 0)
+
+ def syscall_request(self):
+ sandboxlog.debug('syscall request ringing...')
+ msg = self.control.read(7*4)
+ mm = Memory.parse(msg)
+ sandboxlog.debug('>>> %s' % mm)
+ return self.do(mm)
+
+ def do(self, mm):
+ if not mm.eax in syscalls_table:
+ sandboxlog.error('syscall %s [nr=%#x] not implemented' % (syscallnr2human.get(mm.eax, ('???')), mm.eax))
+ return -1
+ func = syscalls_table.get(mm.eax)
+ registers = mm.aslist()[1:func.argc+1]
+ return func(self, *registers)
+
+ @syscall(NR_open, 3)
+ def open(self, filename_ptr, perms, mode):
+ if not self.security.is_valid(filename_ptr):
+ return -1
+ filename = self.peek_asciiz(filename_ptr)
+ if not self.security.open(filename, perms, mode):
+ return -1
+ args = Memory(eax=NR_open,
+ ebx=filename,
+ ecx = perms,
+ edx = mode)
+ ret = self.trustedthread.delegate(args)
+ if ret < 0x80000000:
+ self.security.register_descriptor(ret, filename)
+ return ret
+
+ @syscall(NR_close, 1)
+ def close(self, fd):
+ if not self.security.close(fd):
+ return -1
+ args = Memory(eax=NR_close,
+ ebx=fd)
+ ret = self.trustedthread.delegate(args)
+ if ret == 0:
+ self.security.unregister_descriptor(fd)
+ return ret
+
+ @syscall(NR_access, 2)
+ def access(self, path_ptr, mode):
+ if not self.security.is_valid(path_ptr):
+ return -1
+ path = self.peek_asciiz(path_ptr)
+ self.security.access(path, mode)
+ args = Memory(eax=NR_access,
+ ebx=path,
+ ecx=mode)
+ ret = self.trustedthread.delegate(args)
+ return ret
+
+ @syscall(NR_lseek, 3)
+ def lseek(self, fd, offset, whence):
+ if not self.security.lseek(fd, offset, whence):
+ return -1
+ args = Memory(eax=NR_lseek,
+ ebx=fd,
+ ecx=offset,
+ edx=whence)
+ return self.trustedthread.delegate(args)
+
+ @syscall(NRllseek, 5)
+ def llseek(self, fd, offset_high, offset_low, result, whence):
+ if not self.security.llseek(fd, offset_high, offset_low, result, whence):
+ return -1
+ args = Memory(eax=NR_lseek,
+ ebx=fd,
+ ecx=offset_high,
+ edx=offset_low,
+ esi=result,
+ edi=whence)
+ return self.trustedthread.delegate(args)
+
+ @syscall(NR_stat64, 2)
+ def stat64(self, path_ptr, addr):
+ if not self.security.is_valid(path_ptr):
+ return -1
+ path = self.peek_asciiz(path_ptr)
+ self.security.stat64(path, addr)
+ args = Memory(eax=NR_stat64,
+ ebx=path,
+ ecx=addr)
+ return self.trustedthread.delegate(args)
+
+ @syscall(NR_fstat64, 2)
+ def fstat64(self, fd, ptr):
+ if not self.security.fstat(fd, ptr):
+ return -1
+ args = Memory(eax=NR_fstat64,
+ ebx=fd,
+ ecx=ptr)
+ return self.trustedthread.delegate(args)
+
+ @syscall(NR_mmap2, 6)
+ def mmap2(self, addr, length, prot, flags, fd, pgoffset):
+ return self.mmap(addr, length, prot, flags, fd, pgoffset << 12)
+
+ @syscall(NR_mmap, 6)
+ def mmap(self, addr, length, prot, flags, fd, offset):
+ if not self.security.mmap(addr, length, prot, flags, fd, offset):
+ return -1
+ args = Memory(eax=NR_mmap,
+ ebx=addr,
+ ecx=length,
+ edx=prot,
+ esi=flags,
+ edi=fd,
+ ebp=offset)
+ return self.trustedthread.delegate(args)
+
+ @syscall(NR_brk, 1)
+ def brk(self, addr):
+ if not self.security.brk(addr):
+ return -1
+ args = Memory(eax=NR_brk, ebx=addr)
+ return self.trustedthread.delegate(args)
+
+ @syscall(NR_munmap, 2)
+ def munmap(self, addr, length):
+ if not self.security.munmap(addr, length):
+ return -1
+ args = Memory(eax=NR_munmap,
+ ebx=addr,
+ ecx=length)
+ return self.trustedthread.delegate(args)
+
+ def op_retval(self, ret, errno=0):
+ tubelog.debug('<<< op_retval(%#x, %d)' % (ret,errno))
+ self.control.write(struct.pack('III', RETVAL, ret & 0xffffffff, errno))
+ return ret
+
+ def raisetrap(self):
+ self.control.write(struct.pack('I', RAISE_TRAP))
+
+ def peek_asciiz(self, ptr):
+ tubelog.debug('<<< peek_asciiz(%#x)' % ptr)
+ self.control.write(struct.pack('II', PEEK_ASCIIZ, ptr))
+ buf = self.control.read(4)
+ nbytes = struct.unpack('I', buf)[0]
+ tubelog.debug(' Waiting for %d bytes' % nbytes)
+ buf = self.control.read(nbytes)
+ tubelog.debug('>>> ' + buf)
+ return buf
+
+ def poke_memory(self, addr, buf):
+ length = len(buf)
+ tubelog.debug('<<< poke_memory(%#x, "...") len=%d' % (addr, length))
+ self.control.write(struct.pack('III', POKE_MEMORY, addr, length))
+ written=0
+ while written < length:
+ written += self.control.write(buf[written:])
+
+ def dispatcher(self, rawtype):
+ msgtype = struct.unpack('I', rawtype)[0]
+ if msgtype == DO_SYSCALL:
+ ret = self.syscall_request()
+ self.op_retval(ret)
+ else:
+ tubelog.error('Unknown message type: %#x' % msgtype)
+
+ def run(self):
+ while True:
+ buf = os.read(CONTROL_FD, 4)
+ if not buf:
+ break
+ self.dispatcher(buf)
+
+if __name__ == '__main__':
+ sandbox = HybridSandbox()
+ sandbox.run()
+
View
88 inject.c
@@ -1,36 +1,87 @@
#include <stdio.h>
+#include <stdlib.h>
#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
#include <dlfcn.h>
#include <link.h>
-#include <stdlib.h>
+#define _GNU_SOURCE
+#include <sched.h>
+#include <sys/prctl.h>
#include "common.h"
#include "inject.h"
#include "jail.h"
+#include "companion.h"
#include "mm.h"
-int wrap_main(int argc, char **argv, char **environ)
-{
- pid_t pid;
- char *dir = strdup("/tmp/libnail-XXXXXX");
-
-
- dir=mkdtemp(dir);
- if (!dir)
- PERROR("mkdtemp() failed");
+static void hijack_vdso_gate(void) {
+ asm("mov %%gs:0x10, %%ebx\n"
+ "mov %%ebx, %0\n"
- pid = fork();
- if (pid > 0) {
- start_trusted_process(dir, pid);
+ "mov %1, %%ebx\n"
+ "mov %%ebx, %%gs:0x10\n"
- } else if (pid == 0) {
- jail_exec(dir, argc, argv, environ);
+ : "=m" (real_handler)
+ : "r" (handler)
+ : "ebx");
+} __attribute__((always_inline));
- } else {
- PERROR("fork()");
+void enter_seccomp_mode(void) {
+ if (prctl(PR_SET_SECCOMP, 1, 0, 0) == -1) {
+ perror("prctl(PR_SET_SECCOMP) failed");
+ printf("Maybe you don't have the CONFIG_SECCOMP support built into your kernel?\n");
+ exit(1);
}
+}
+
+void fill_return_table(char *array) {
+ int i = 0;
+ printf("array=%p\n", array);
+ while (i < 256)
+ *(array+i) = (char)i++;
+ /* XXX: need to mptrotect() this zone */
+}
+
+int wrap_main(int argc, char *argv[], char *environ[]) {
+ char dummy_stack[512];
+ void *sharedmemory;
+ int ret, fd;
+
+ do {
+ fd = shm_open(SHMEM_NAME, O_RDONLY, SHMEM_MODE);
+ if ((fd < 0) && errno != ENOENT) {
+ perror("shm_open()");
+ exit(1);
+ }
+ sleep(0.5);
+ } while (fd < 0);
+
+ sharedmemory = mmap(NULL, SHMEM_SIZE, PROT_READ, MAP_SHARED, fd, 0);
+ if (sharedmemory == MAP_FAILED) {
+ perror("mmap()");
+ exit(1);
+ }
+
+ range_start = sharedmemory;
+ range_end = sharedmemory+SHMEM_SIZE;
+ syscall_dropbox = sharedmemory+OFFSET_SYSCALL_DROPBOX;
+
+ fill_return_table(retarray);
+
+ write(3, &range_start, sizeof range_start);
+ ret = clone(companion_routine, dummy_stack+sizeof dummy_stack, CLONE_FILES|CLONE_VM, 12);
+ if (ret == -1) {
+ perror("clone(trusted)");
+ exit(1);
+ }
+
+ // enter_seccomp_mode();
+ hijack_vdso_gate();
- return 0;
+ return realmain(argc, argv, environ);
}
int __libc_start_main(main_t main,
@@ -62,7 +113,6 @@ int __libc_start_main(main_t main,
ERROR(" Failed: %s\n", dlerror());
realmain = main;
- void (*__malloc_initialize_hook) (void) = my_malloc_init;
return (*libc_start_main)(wrap_main, argc, ubp_av, auxvec, init, fini, rtld_fini, stack_end);
}
View
4 inject.h
@@ -6,6 +6,10 @@
#define _ElfW_1(e,w,t) e##w##t
#define __ELF_NATIVE_CLASS __WORDSIZE
+#define SHMEM_NAME "/seccompnurse"
+#define SHMEM_MODE 277
+#define SHMEM_SIZE 0x10
+
typedef int (*main_t)(int, char **, char **);
main_t realmain;
#endif
View
151 jail.c
@@ -32,8 +32,8 @@ void syscall_proxy(void) {
"movl %%ebx, 28(%%eax)\n"
:: "a" (buf) );
- write(controlfd, buf, sizeof buf);
- ret = wait_for_orders(controlfd);
+ write(CONTROL_FD, buf, sizeof buf);
+ ret = wait_for_orders(CONTROL_FD);
asm("movl %0, %%eax\n" : : "m" (ret));
}
@@ -41,10 +41,12 @@ void (*syscall_proxy_addr)(void) = syscall_proxy;
void handler(void) {
asm("movl (%%ebp), %%ebp\n" // ignore the gcc prologue
"cmpl " ivalue(__NR_write) ", %%eax\n"
- "je wrap_write\n"
+ // "je wrap_read\n"
+ "je do_syscall\n"
"cmpl " ivalue(__NR_read) ", %%eax\n"
- "je wrap_read\n"
+ // "je wrap_read\n"
+ "je do_syscall\n"
"cmpl " ivalue(__NR_exit_group) ", %%eax\n"
"jne wrapper\n"
@@ -63,10 +65,6 @@ void handler(void) {
" popl %%edx\n"
" popl %%ecx\n"
" popl %%ebx\n"
-
-
-
- // " popl %%ecx\n"
" jmp out\n"
"do_syscall:\n"
@@ -89,140 +87,3 @@ void handler(void) {
: "m" (syscall_proxy_addr),
"m" (real_handler));
}
-
-static void hijack_vdso_gate(void) {
- asm("mov %%gs:0x10, %%ebx\n"
- "mov %%ebx, %0\n"
-
- "mov %1, %%ebx\n"
- "mov %%ebx, %%gs:0x10\n"
-
- : "=m" (real_handler)
- : "r" (handler)
- : "ebx");
-} __attribute__((always_inline));
-
-void enter_seccomp_mode(void) {
- if (prctl(PR_SET_SECCOMP, 1, 0, 0) == -1) {
- perror("prctl(PR_SET_SECCOMP) failed");
- printf("Maybe you don't have the CONFIG_SECCOMP support built into your kernel?\n");
- exit(1);
- }
-}
-
-void bind_sockets(const char *dir, int last, unsigned int n) {
- unsigned int i;
- struct sockaddr_un uaddr, client;
- size_t ret;
- socklen_t addrlen = sizeof client;
- int s, prev = last;
-
- uaddr.sun_family = AF_UNIX;
- s = socket(AF_UNIX, SOCK_STREAM, 0);
- if (!s)
- PERROR("Cannot allocate another socket");
-
- ret = snprintf(uaddr.sun_path, sizeof(uaddr.sun_path),
- "%s/sockets", dir);
-
- if (ret >= sizeof(uaddr.sun_path))
- ERROR("Unix socket's pathname is truncated.\n");
-
- DEBUGP("DADDY: %d: %s\n", s, uaddr.sun_path);
- if (bind(s, (struct sockaddr *) &uaddr, sizeof(uaddr)) != 0)
- PERROR("bind() failed");
-
- if (listen(s, 1) < 0)
- PERROR("listen() failed");
-
- prev = s;
- for (i = 0 ; i < n ; i++) {
- int fd = accept(s, (struct sockaddr *)&client, &addrlen);
-
- if (fd == -1)
- PERROR("accept()");
-
- if (fd != prev+1)
- ERROR("accept: Not linear! fd=%d needed but got fd=%d\n", prev+1, fd);
-
- if (controlfd == -1) {
- controlfd = fd;
- DEBUGP("Master socket is %d\n", controlfd);
- }
- prev=fd;
- }
-}
-
-void link_sockets(const char *dir, unsigned int n) {
- unsigned int i, ok;
- struct sockaddr_un uaddr;
- size_t ret;
- int s, prev;
-
- prev = open("/dev/null", O_RDONLY);
-
- uaddr.sun_family = AF_UNIX;
- ret = snprintf(uaddr.sun_path, sizeof(uaddr.sun_path),
- "%s/sockets", dir);
-
- if (ret >= sizeof(uaddr.sun_path))
- ERROR("Unix socket's pathname is truncated.\n");
-
- for (i = 0 ; i < n ; i++) {
- s = socket(AF_UNIX, SOCK_STREAM, 0);
- if (!s)
- PERROR("Cannot allocate another socket");
-
- if (s != prev+1)
- ERROR("connect: Not linear! fd=%d needed but got fd=%d\n", prev+1, s);
- prev = s;
-
- do {
- ok = 0;
-
- if (connect(s, (struct sockaddr *) &uaddr, sizeof(uaddr))) {
- if (errno == ENOENT || errno == ECONNREFUSED) {
- sleep(0.1);
- continue;
- } else
- PERROR("connect()");
- }
-
- ok = 1;
- } while (!ok);
- }
-}
-
-void close_sockets(int last, unsigned int n) {
- int i;
-
- for (i = last+1 ; i < n+last+1 ; i++) {
- if (close(i) != 0)
- PERROR("close()");
- }
-}
-
-void jail_exec(const char *socketdir, int argc, char **argv, char **environ) {
- bind_sockets(socketdir, STDERR_FILENO, 0x10 /* XXX */);
- init_memory(0xf000);
- enter_seccomp_mode();
- hijack_vdso_gate();
- (*realmain)(argc, argv, environ);
-}
-
-void start_trusted_process(const char *socketdir, pid_t pid)
-{
- char *new_argv[] = { MASTER_DAEMON, "XXXXXXXXXX", NULL};
- char *new_env[] = { NULL };
- char *tmp = malloc(12);
-
- if (!tmp)
- PERROR("malloc()");
- snprintf(tmp, 12, "%u", pid);
- tmp[sizeof tmp - 1] = '\0';
- new_argv[1] = tmp;
-
- link_sockets(socketdir, 0x10 /* XXX */);
- execve(MASTER_DAEMON, new_argv, new_env);
- PERROR("execve()");
-}
View
9 jail.h
@@ -1,14 +1,7 @@
#ifndef __JAIL_H
-
#define __JAIL_H
-#define MASTER_DAEMON "./trusted.py"
-#define MASTER_ARGV_SIZE 128
-#define MASTER_NUM_OF_ARGV 5
-
int (*real_handler)(void);
-static int nsyscalls = 0;
-
-void start_trusted_process(const char *socketdir, pid_t pid);
+void handler(void);
#endif
View
76 sandbox.c
@@ -0,0 +1,76 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/stat.h> /* For mode constants */
+#include <fcntl.h> /* For O_* constants */
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <sys/socket.h>
+
+#include "helper.h"
+
+extern char **environ;
+
+#define TRUSTED_PATH "./hybrid.py"
+
+int main(int argc, char *argv[]) {
+ int control_sockets[2], thread_sockets[2];
+ pid_t untrusted, trusted;
+ int ret;
+
+ if (argc <= 1) {
+ fprintf(stderr,
+ "Usage: %s <cmd> <arguments>\n"
+ " sandbox the command specified\n",
+ argv[0]);
+ exit(1);
+ }
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, control_sockets) != 0) {
+ perror("socketpair()");
+ exit(1);
+ }
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, thread_sockets) != 0) {
+ perror("socketpair()");
+ exit(1);
+ }
+
+ untrusted = fork();
+ if (untrusted > 0) {
+ dup2(control_sockets[1], THREAD_FD);
+ dup2(thread_sockets[1], CONTROL_FD);
+ close(6);
+ close(5);
+
+ setenv("LD_PRELOAD", "./sandbox.so", 1);
+ execve(argv[1], argv+1, environ);
+ perror("execve()");
+ exit(4);
+
+ } else if (untrusted == 0) {
+ trusted = fork();
+
+ if (trusted > 0) {
+ close(thread_sockets[1]); /* 4 is closed */
+ close(control_sockets[1]); /* 6 is closed */
+ dup2(thread_sockets[0], CONTROL_FD);
+ close(thread_sockets[0]);
+
+ execve(TRUSTED_PATH, NULL, NULL);
+ } else if (trusted == 0) {
+ waitpid(untrusted, &ret, 0);
+ waitpid(trusted, &ret, 0);
+ } else {
+ perror("fork()");
+ exit(5);
+ }
+
+ } else {
+ perror("fork()");
+ exit(3);
+ }
+
+ return 0;
+}
View
44 security.py
@@ -10,10 +10,11 @@ def __init__(self, fs_root='/'):
def register_descriptor(self, fd, filename):
if fd in self.fd_table:
- raise SecurityException('File descriptor %d already opened!' % fd)
+ securitylog.error('File descriptor %d already opened!' % fd)
+ return False
self.fd_table[fd] = filename
securitylog.debug('Registering file descriptor %d associated to %s' % (fd, filename))
-
+ return True
# Trying to close a not-opened-file-descriptor is not
# fatal because daemons usually try to close every
@@ -25,11 +26,40 @@ def unregister_descriptor(self, fd):
return opened
def open(self, filename, perms, mode):
- pass
+ return True # XXX
+
+ def close(self, fd):
+ return True # XXX
+
+ def brk(self, addr):
+ return self.is_valid(addr) and True # XXX
- def fstat(self, fd):
- ret = (0 <= fd <= 2) or (fd in self.fd_table)
- securitylog.info('Can fstat(%d)? %s' % (fd, ret))
+ def munmap(self, addr, length):
+ return True # XXX
+
+ def fstat(self, fd, ptr):
+ ret = self.is_valid(ptr) and ((0 <= fd <= 2) or (fd in self.fd_table))
+ securitylog.debug('Can fstat(%d)? %s' % (fd, ret))
return ret
-
+ def mmap(self, addr, length, prot, flags, fd, offset):
+ return True
+
+ def is_valid(self, ptr):
+ ret = True # XXX
+ if not ret:
+ tubelog.error('invalid pointer supplied: %#x' % ptr)
+ return ret
+
+ def lseek(self, fd, offset, whence):
+ return True # XXX
+
+ def llseek(self, fd, offset_high, offset_low, result, whence):
+ return self.is_valid(result) and True
+
+ def stat64(self, path, addr):
+ return self.is_valid(addr) and True # XXX
+
+ def access(self, path, mode):
+ return True # XXX
+
View
337 syscalls.py
@@ -0,0 +1,337 @@
+
+NR_restart_syscall = 0
+NR_exit = 1
+NR_fork = 2
+NR_read = 3
+NR_write = 4
+NR_open = 5
+NR_close = 6
+NR_waitpid = 7
+NR_creat = 8
+NR_link = 9
+NR_unlink = 10
+NR_execve = 11
+NR_chdir = 12
+NR_time = 13
+NR_mknod = 14
+NR_chmod = 15
+NR_lchown = 16
+NR_break = 17
+NR_oldstat = 18
+NR_lseek = 19
+NR_getpid = 20
+NR_mount = 21
+NR_umount = 22
+NR_setuid = 23
+NR_getuid = 24
+NR_stime = 25
+NR_ptrace = 26
+NR_alarm = 27
+NR_oldfstat = 28
+NR_pause = 29
+NR_utime = 30
+NR_stty = 31
+NR_gtty = 32
+NR_access = 33
+NR_nice = 34
+NR_ftime = 35
+NR_sync = 36
+NR_kill = 37
+NR_rename = 38
+NR_mkdir = 39
+NR_rmdir = 40
+NR_dup = 41
+NR_pipe = 42
+NR_times = 43
+NR_prof = 44
+NR_brk = 45
+NR_setgid = 46
+NR_getgid = 47
+NR_signal = 48
+NR_geteuid = 49
+NR_getegid = 50
+NR_acct = 51
+NR_umount2 = 52
+NR_lock = 53
+NR_ioctl = 54
+NR_fcntl = 55
+NR_mpx = 56
+NR_setpgid = 57
+NR_ulimit = 58
+NR_oldolduname = 59
+NR_umask = 60
+NR_chroot = 61
+NR_ustat = 62
+NR_dup2 = 63
+NR_getppid = 64
+NR_getpgrp = 65
+NR_setsid = 66
+NR_sigaction = 67
+NR_sgetmask = 68
+NR_ssetmask = 69
+NR_setreuid = 70
+NR_setregid = 71
+NR_sigsuspend = 72
+NR_sigpending = 73
+NR_sethostname = 74
+NR_setrlimit = 75
+NR_getrlimit = 76
+NR_getrusage = 77
+NR_gettimeofday = 78
+NR_settimeofday = 79
+NR_getgroups = 80
+NR_setgroups = 81
+NR_select = 82
+NR_symlink = 83
+NR_oldlstat = 84
+NR_readlink = 85
+NR_uselib = 86
+NR_swapon = 87
+NR_reboot = 88
+NR_readdir = 89
+NR_mmap = 90
+NR_munmap = 91
+NR_truncate = 92
+NR_ftruncate = 93
+NR_fchmod = 94
+NR_fchown = 95
+NR_getpriority = 96
+NR_setpriority = 97
+NR_profil = 98
+NR_statfs = 99
+NR_fstatfs = 100
+NR_ioperm = 101
+NR_socketcall = 102
+NR_syslog = 103
+NR_setitimer = 104
+NR_getitimer = 105
+NR_stat = 106
+NR_lstat = 107
+NR_fstat = 108
+NR_olduname = 109
+NR_iopl = 110
+NR_vhangup = 111
+NR_idle = 112
+NR_vm86old = 113
+NR_wait4 = 114
+NR_swapoff = 115
+NR_sysinfo = 116
+NR_ipc = 117
+NR_fsync = 118
+NR_sigreturn = 119
+NR_clone = 120
+NR_setdomainname = 121
+NR_uname = 122
+NR_modify_ldt = 123
+NR_adjtimex = 124
+NR_mprotect = 125
+NR_sigprocmask = 126
+NR_create_module = 127
+NR_init_module = 128
+NR_delete_module = 129
+NR_get_kernel_syms = 130
+NR_quotactl = 131
+NR_getpgid = 132
+NR_fchdir = 133
+NR_bdflush = 134
+NR_sysfs = 135
+NR_personality = 136
+NR_afs_syscall = 137
+NR_setfsuid = 138
+NR_setfsgid = 139
+NRllseek = 140
+NR_getdents = 141
+NRnewselect = 142
+NR_flock = 143
+NR_msync = 144
+NR_readv = 145
+NR_writev = 146
+NR_getsid = 147
+NR_fdatasync = 148
+NRsysctl = 149
+NR_mlock = 150
+NR_munlock = 151
+NR_mlockall = 152
+NR_munlockall = 153
+NR_sched_setparam = 154
+NR_sched_getparam = 155
+NR_sched_setscheduler = 156
+NR_sched_getscheduler = 157
+NR_sched_yield = 158
+NR_sched_get_priority_max = 159
+NR_sched_get_priority_min = 160
+NR_sched_rr_get_interval = 161
+NR_nanosleep = 162
+NR_mremap = 163
+NR_setresuid = 164
+NR_getresuid = 165
+NR_vm86 = 166
+NR_query_module = 167
+NR_poll = 168
+NR_nfsservctl = 169
+NR_setresgid = 170
+NR_getresgid = 171
+NR_prctl = 172
+NR_rt_sigreturn = 173
+NR_rt_sigaction = 174
+NR_rt_sigprocmask = 175
+NR_rt_sigpending = 176
+NR_rt_sigtimedwait = 177
+NR_rt_sigqueueinfo = 178
+NR_rt_sigsuspend = 179
+NR_pread64 = 180
+NR_pwrite64 = 181
+NR_chown = 182
+NR_getcwd = 183
+NR_capget = 184
+NR_capset = 185
+NR_sigaltstack = 186
+NR_sendfile = 187
+NR_getpmsg = 188
+NR_putpmsg = 189
+NR_vfork = 190
+NR_ugetrlimit = 191
+NR_mmap2 = 192
+NR_truncate64 = 193
+NR_ftruncate64 = 194
+NR_stat64 = 195
+NR_lstat64 = 196
+NR_fstat64 = 197
+NR_lchown32 = 198
+NR_getuid32 = 199
+NR_getgid32 = 200
+NR_geteuid32 = 201
+NR_getegid32 = 202
+NR_setreuid32 = 203
+NR_setregid32 = 204
+NR_getgroups32 = 205
+NR_setgroups32 = 206
+NR_fchown32 = 207
+NR_setresuid32 = 208
+NR_getresuid32 = 209
+NR_setresgid32 = 210
+NR_getresgid32 = 211
+NR_chown32 = 212
+NR_setuid32 = 213
+NR_setgid32 = 214
+NR_setfsuid32 = 215
+NR_setfsgid32 = 216
+NR_pivot_root = 217
+NR_mincore = 218
+NR_madvise = 219
+NR_madvise1 = 219
+NR_getdents64 = 220
+NR_fcntl64 = 221
+NR_gettid = 224
+NR_readahead = 225
+NR_setxattr = 226
+NR_lsetxattr = 227
+NR_fsetxattr = 228
+NR_getxattr = 229
+NR_lgetxattr = 230
+NR_fgetxattr = 231
+NR_listxattr = 232
+NR_llistxattr = 233
+NR_flistxattr = 234
+NR_removexattr = 235
+NR_lremovexattr = 236
+NR_fremovexattr = 237
+NR_tkill = 238
+NR_sendfile64 = 239
+NR_futex = 240
+NR_sched_setaffinity = 241
+NR_sched_getaffinity = 242
+NR_set_thread_area = 243
+NR_get_thread_area = 244
+NR_io_setup = 245
+NR_io_destroy = 246
+NR_io_getevents = 247
+NR_io_submit = 248
+NR_io_cancel = 249
+NR_fadvise64 = 250
+NR_exit_group = 252
+NR_lookup_dcookie = 253
+NR_epoll_create = 254
+NR_epoll_ctl = 255
+NR_epoll_wait = 256
+NR_remap_file_pages = 257
+NR_set_tid_address = 258
+NR_timer_create = 259
+NR_timer_settime = (NR_timer_create+1)
+NR_timer_gettime = (NR_timer_create+2)
+NR_timer_getoverrun = (NR_timer_create+3)
+NR_timer_delete = (NR_timer_create+4)
+NR_clock_settime = (NR_timer_create+5)
+NR_clock_gettime = (NR_timer_create+6)
+NR_clock_getres = (NR_timer_create+7)
+NR_clock_nanosleep = (NR_timer_create+8)
+NR_statfs64 = 268
+NR_fstatfs64 = 269
+NR_tgkill = 270
+NR_utimes = 271
+NR_fadvise64_64 = 272
+NR_vserver = 273
+NR_mbind = 274
+NR_get_mempolicy = 275
+NR_set_mempolicy = 276
+NR_mq_open = 277
+NR_mq_unlink = (NR_mq_open+1)
+NR_mq_timedsend = (NR_mq_open+2)
+NR_mq_timedreceive = (NR_mq_open+3)
+NR_mq_notify = (NR_mq_open+4)
+NR_mq_getsetattr = (NR_mq_open+5)
+NR_kexec_load = 283
+NR_waitid = 284
+NR_add_key = 286
+NR_request_key = 287
+NR_keyctl = 288
+NR_ioprio_set = 289
+NR_ioprio_get = 290
+NR_inotify_init = 291
+NR_inotify_add_watch = 292
+NR_inotify_rm_watch = 293
+NR_migrate_pages = 294
+NR_openat = 295
+NR_mkdirat = 296
+NR_mknodat = 297
+NR_fchownat = 298
+NR_futimesat = 299
+NR_fstatat64 = 300
+NR_unlinkat = 301
+NR_renameat = 302
+NR_linkat = 303
+NR_symlinkat = 304
+NR_readlinkat = 305
+NR_fchmodat = 306
+NR_faccessat = 307
+NR_pselect6 = 308
+NR_ppoll = 309
+NR_unshare = 310
+NR_set_robust_list = 311
+NR_get_robust_list = 312
+NR_splice = 313
+NR_sync_file_range = 314
+NR_tee = 315
+NR_vmsplice = 316
+NR_move_pages = 317
+NR_getcpu = 318
+NR_epoll_pwait = 319
+NR_utimensat = 320
+NR_signalfd = 321
+NR_timerfd_create = 322
+NR_eventfd = 323
+NR_fallocate = 324
+NR_timerfd_settime = 325
+NR_timerfd_gettime = 326
+NR_signalfd4 = 327
+NR_eventfd2 = 328
+NR_epoll_create1 = 329
+NR_dup3 = 330
+NR_pipe2 = 331
+NR_inotify_init1 = 332
+NR_preadv = 333
+NR_pwritev = 334
+NR_rt_tgsigqueueinfo = 335
+NR_perf_event_open = 336
+
+syscallnr2human = dict(map(lambda y: (y[1],y[0]), filter(lambda x: x[0].startswith('NR'), globals().items())))
View
49 trusted.py
@@ -3,7 +3,7 @@
import struct, os, sys
import logging
from errno import *
-
+from trustedthread import TrustedThread, VolatileArgument
import vfs, vm
lvl = logging.DEBUG
@@ -20,11 +20,15 @@ def __init__(self, regs):
self.ecx, self.edx,
self.esi, self.edi,
self.ebp) = regs
-
@staticmethod
def parse(raw):
return Memory(struct.unpack('7I', raw))
-
+ def pack(self):
+ return struct.pack('7I',
+ self.eax, self.ebx,
+ self.ecx, self.edx,
+ self.esi, self.edi,
+ self.ebp)
def __repr__(self):
return 'eax=%x ebx=%x ecx=%x edx=%x esi=%x edi=%x ebp=%x' % (self.eax, self.ebx,
self.ecx, self.edx,
@@ -37,14 +41,15 @@ def __repr__(self):
POKE_MEMORY = 4
RETVAL = 5
NATIVE_EXIT = 6
-GET_MEMORY_POOL = 7
+POSTBOX = 7
RAISE_TRAP = 8
class SandboxedProcess:
def __init__(self, fd, nfd):
self.fd = os.fdopen(fd, 'w+')
self.vfs = vfs.VfsManager(fd+1, fd+1+nfd, root='/')
- self.vm = vm.VirtualMemory(0x01000000)
+ #self.vm = vm.VirtualMemory(0x01000000)
+ self.trustedthread = TrustedThread(self.get_postbox_addr()) # XXX
def syscall_request(self):
sandboxlog.info('syscall request ringing...')
@@ -52,7 +57,6 @@ def syscall_request(self):
mm = Memory.parse(msg)
sandboxlog.debug('>>> %s' % mm)
-
if mm.eax == 3:
self.sys_read(mm.ebx, mm.ecx, mm.edx)
elif mm.eax == 3:
@@ -78,6 +82,13 @@ def open(self, reg):
u_mode = reg.edx
filename = self.peek_asciiz(u_ptr)
sandboxlog.debug('+++ open("%s", %x, %#x)' % (filename, u_perms, u_mode))
+ registers = {
+ 'eax': reg.eax,
+ 'ebx': VolatileArgument(filename),
+ 'ecx': reg.ecx,
+ 'edx': reg.edx,
+ }
+ ret = self.trustedthread.delegate(registers)
(ret, errno) = self.vfs.open(filename, u_perms, u_mode)
# import time
# time.sleep(20)
@@ -177,21 +188,9 @@ def mmap2(self, addr, length, prot, flags, fd, pgoffset):
return self.mmap(addr, length, prot, flags, fd, pgoffset << 12)
def mmap(self, addr, length, prot, flags, fd, offset):
- #fd = ~((fd + 1) & 0xffffffff)
sandboxlog.info('+++ mmap(%#x, %#x, %#x, %#x, %#d, %d)' %
(addr, length, prot, flags, fd, offset))
-
- # if not self.security.mmap(addr, length, prot, flags, fd, offset):
- # raise SecurityViolation("mmap denied")
-
- ## XXX: Check if fd is owned by the sandbox
- ## XXX: Offset must be page aligned
-
- if not self.vm.mm:
- self.vm.set_pool_addr(self.get_memory_pool())
- addr = self.vm.new_mapping(addr, length, prot, flags)
- ret,errno = self.vfs.mmap(addr, length, prot, flags, fd, offset, self)
- #self.raisetrap()
+ self.raisetrap()
self.op_retval(ret, errno)
def munmap(self, addr, length):
@@ -199,9 +198,9 @@ def munmap(self, addr, length):
self.vm.release_mapping(addr, length)
self.op_retval(0, 0)
- def get_memory_pool(self):
- tubelog.debug('<<< memory_pool_addr')
- self.write(struct.pack('I', GET_MEMORY_POOL))
+ def get_postbox_addr(self):
+ tubelog.debug('<<< postbox_addr')
+ self.write(struct.pack('I', POSTBOX))
addr = struct.unpack('I', self.read(4))[0]
tubelog.info('>>> memory pool is at %x' % addr)
return addr
@@ -213,7 +212,7 @@ def close(self, fd):
class TrustedProcess:
def __init__(self):
- numdescriptors = int(sys.argv[1])
+ numdescriptors = 20
self.master_socket = 4
self.sandbox = SandboxedProcess(self.master_socket, numdescriptors)
@@ -221,15 +220,11 @@ def dispatcher(self, rawtype):
msgtype = struct.unpack('I', rawtype)[0]
if msgtype == DO_SYSCALL:
self.sandbox.syscall_request()
- elif msgtype == MEMORY_POOL:
- self.sandbox.set_memory_pool()
else:
tubelog.error('Unknown message type: %#x' % msgtype)
def run(self):
while True:
- if not self.sandbox.vfs.bridge.run(self.master_socket):
- raise Exception('Select_loop failed!')
buf = os.read(self.master_socket, 4)
if not buf:
break
View
49 trustedthread.py
@@ -0,0 +1,49 @@
+#! /usr/bin/env python
+
+import os, struct
+
+REGISTERS_DROPBOX_LEN = 7*4
+
+class TrustedThread(object):
+ def __init__(self, fd, mapping):
+ self.mapping = mapping
+ self.freespace_start = REGISTERS_DROPBOX_LEN
+ self.thread = os.fdopen(fd, 'w+')
+ self.r_baseaddr = struct.unpack('I', self.thread.read(4))[0]
+
+ def delegate(self, mm):
+ for name in ['eax', 'ebx', 'ecx', 'edx', 'esi', 'edi', 'ebp']:
+ value = getattr(mm, name)
+ if isinstance(value, str):
+ ptr = self.push_volatile(value)
+ setattr(mm, name, ptr)
+ self.push_registers(mm)
+ self.wakeup()
+ ret = struct.unpack('I', self.thread.read(4))[0]
+ self.forget()
+ return ret
+
+ def push_registers(self, mm):
+ raw = mm.pack()
+ self.mapping[:len(raw)] = raw
+
+ def wakeup(self):
+ self.thread.write('PING')
+ self.thread.flush()
+
+ def push_volatile(self, value):
+ start = self.freespace_start
+ end = start + len(value)
+ if end-start > self.mapping.size():
+ raise Exception('Not enought memory to store value argument')
+ self.mapping[start:end] = value
+ self.freespace_start = end
+ return start+self.r_baseaddr
+
+ def forget(self):
+ """
+ syscall has been performed, we can now "free" the memory.
+
+ """
+ self.freespace_start = REGISTERS_DROPBOX_LEN
+ self.mapping[:] = '\x00'*self.mapping.size()
Please sign in to comment.
Something went wrong with that request. Please try again.