Skip to content

Commit

Permalink
vm: separate VM creation from code loading
Browse files Browse the repository at this point in the history
This is to support external function calls and maps, where the user needs to
configure the VM before the code can be validated.
  • Loading branch information
rlane committed Sep 16, 2015
1 parent 63ae285 commit c40586a
Show file tree
Hide file tree
Showing 17 changed files with 72 additions and 37 deletions.
2 changes: 1 addition & 1 deletion tests/err-div-by-zero-imm.data
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ mov32 r0, 1
div32 r0, 0
exit
-- error
Failed to create VM: division by zero at PC 1
Failed to load code: division by zero at PC 1
2 changes: 1 addition & 1 deletion tests/err-endian-size.data
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
0x00000000000010b7
0x0000000000000095
-- error
Failed to create VM: invalid endian immediate at PC 0
Failed to load code: invalid endian immediate at PC 0
2 changes: 1 addition & 1 deletion tests/err-incomplete-lddw.data
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
0x5566778800000018
0x0000000000000095
-- error
Failed to create VM: incomplete lddw at PC 0
Failed to load code: incomplete lddw at PC 0
2 changes: 1 addition & 1 deletion tests/err-incomplete-lddw2.data
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
0x5566778800000018
0x0000000000000095
-- error
Failed to create VM: incomplete lddw at PC 0
Failed to load code: incomplete lddw at PC 0
2 changes: 1 addition & 1 deletion tests/err-infinite-loop.data
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
ja -1
exit
-- error
Failed to create VM: infinite loop at PC 0
Failed to load code: infinite loop at PC 0
2 changes: 1 addition & 1 deletion tests/err-invalid-reg-dst.data
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
mov r11, 1
exit
-- error
Failed to create VM: invalid destination register at PC 0
Failed to load code: invalid destination register at PC 0
2 changes: 1 addition & 1 deletion tests/err-invalid-reg-src.data
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
mov r0, r11
exit
-- error
Failed to create VM: invalid source register at PC 0
Failed to load code: invalid source register at PC 0
2 changes: 1 addition & 1 deletion tests/err-jmp-lddw.data
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ ja +1
lddw r0, 0x1122334455667788
exit
-- error
Failed to create VM: jump to middle of lddw at PC 0
Failed to load code: jump to middle of lddw at PC 0
2 changes: 1 addition & 1 deletion tests/err-jmp-out.data
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
ja +2
exit
-- error
Failed to create VM: jump out of bounds at PC 0
Failed to load code: jump out of bounds at PC 0
2 changes: 1 addition & 1 deletion tests/err-noexit.data
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
-- asm
mov32 r0, 0
-- error
Failed to create VM: no exit at end of instructions
Failed to load code: no exit at end of instructions
2 changes: 1 addition & 1 deletion tests/err-too-many-instructions.data
Original file line number Diff line number Diff line change
Expand Up @@ -65537,4 +65537,4 @@
0x00000000000001b7
0x0000000000000095
-- error
Failed to create VM: too many instructions (max 65536)
Failed to load code: too many instructions (max 65536)
2 changes: 1 addition & 1 deletion tests/err-unknown-opcode.data
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
0x0000000000000006
0x0000000000000095
-- error
Failed to create VM: unknown opcode 0x06 at PC 0
Failed to load code: unknown opcode 0x06 at PC 0
2 changes: 1 addition & 1 deletion tests/err-write-r10.dst
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
mov r10, 1
exit
-- error
Failed to create VM: invalid destination register at PC 0
Failed to load code: invalid destination register at PC 0
15 changes: 14 additions & 1 deletion vm/inc/ubpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,22 @@
struct ubpf_vm;
typedef uint64_t (*ubpf_jit_fn)(void *mem, size_t mem_len);

struct ubpf_vm *ubpf_create(const void *code, uint32_t code_len, char **errmsg);
struct ubpf_vm *ubpf_create(void);
void ubpf_destroy(struct ubpf_vm *vm);

/*
* Load code into a VM
*
* This must be done before calling ubpf_exec or ubpf_compile.
*
* 'code' should point to eBPF bytecodes and 'code_len' should be the size in
* bytes of that buffer.
*
* Returns 0 on success, -1 on error. In case of error a pointer to the error
* message will be stored in 'errmsg' and should be freed by the caller.
*/
int ubpf_load(struct ubpf_vm *vm, const void *code, uint32_t code_len, char **errmsg);

uint64_t ubpf_exec(const struct ubpf_vm *vm, void *mem, size_t mem_len);

ubpf_jit_fn ubpf_compile(struct ubpf_vm *vm, char **errmsg);
Expand Down
11 changes: 8 additions & 3 deletions vm/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,15 @@ int main(int argc, char **argv)
}
}

struct ubpf_vm *vm = ubpf_create();
if (!vm) {
fprintf(stderr, "Failed to create VM\n");
return 1;
}

char *errmsg;
struct ubpf_vm *vm = ubpf_create(code, code_len, &errmsg);
if (vm == NULL) {
fprintf(stderr, "Failed to create VM: %s\n", errmsg);
if (ubpf_load(vm, code, code_len, &errmsg) < 0) {
fprintf(stderr, "Failed to load code: %s\n", errmsg);
free(errmsg);
return 1;
}
Expand Down
5 changes: 5 additions & 0 deletions vm/ubpf_jit.dasm
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,11 @@ ubpf_compile(struct ubpf_vm *vm, char **errmsg)
return vm->jitted;
}

if (!vm->insts) {
*errmsg = ubpf_error("code has not been loaded into this VM");
return NULL;
}

|.section code
dasm_init(&d, DASM_MAXSECTION);

Expand Down
52 changes: 32 additions & 20 deletions vm/ubpf_vm.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,43 +31,50 @@ static bool validate(const struct ebpf_inst *insts, uint32_t num_insts, char **e
static bool bounds_check(void *addr, int size, const char *type, uint16_t cur_pc, void *mem, size_t mem_len, void *stack);

struct ubpf_vm *
ubpf_create(const void *code, uint32_t code_len, char **errmsg)
ubpf_create(void)
{
return calloc(1, sizeof(struct ubpf_vm));
}

void
ubpf_destroy(struct ubpf_vm *vm)
{
if (vm->jitted) {
munmap(vm->jitted, vm->jitted_size);
}
free(vm->insts);
free(vm);
}

int
ubpf_load(struct ubpf_vm *vm, const void *code, uint32_t code_len, char **errmsg)
{
*errmsg = NULL;

if (vm->insts) {
*errmsg = ubpf_error("code has already been loaded into this VM");
return -1;
}

if (code_len % 8 != 0) {
*errmsg = ubpf_error("code_len must be a multiple of 8");
return NULL;
return -1;
}

if (!validate(code, code_len/8, errmsg)) {
return NULL;
}

struct ubpf_vm *vm = calloc(1, sizeof(*vm));
if (!vm) {
return NULL;
return -1;
}

vm->insts = malloc(code_len);
if (vm->insts == NULL) {
return NULL;
*errmsg = ubpf_error("out of memory");
return -1;
}

memcpy(vm->insts, code, code_len);
vm->num_insts = code_len/sizeof(vm->insts[0]);

return vm;
}

void
ubpf_destroy(struct ubpf_vm *vm)
{
if (vm->jitted) {
munmap(vm->jitted, vm->jitted_size);
}
free(vm->insts);
free(vm);
return 0;
}

static uint32_t
Expand All @@ -84,6 +91,11 @@ ubpf_exec(const struct ubpf_vm *vm, void *mem, size_t mem_len)
uint64_t reg[16];
uint64_t stack[(STACK_SIZE+7)/8];

if (!insts) {
/* Code must be loaded before we can execute */
return UINT64_MAX;
}

reg[1] = (uintptr_t)mem;
reg[10] = (uintptr_t)stack + sizeof(stack);

Expand Down

0 comments on commit c40586a

Please sign in to comment.