mirror of
https://github.com/ringtailsoftware/uvm32.git
synced 2026-06-05 22:43:39 +00:00
Add a stack canary, setup on boot
This commit is contained in:
parent
9596838a4b
commit
9baedb42e8
21 changed files with 61 additions and 16 deletions
21
apps/crt0.S
21
apps/crt0.S
|
|
@ -1,19 +1,24 @@
|
||||||
#include "uvm32_sys.h"
|
#include "uvm32_sys.h"
|
||||||
|
|
||||||
|
.equ uvm32_syscall_halt, 0x1000000
|
||||||
|
.equ uvm32_syscall_yield, 0x1000001
|
||||||
|
.equ uvm32_syscall_stackprotect, 0x1000002
|
||||||
|
|
||||||
.section .initial_jump , "ax", %progbits
|
.section .initial_jump , "ax", %progbits
|
||||||
.global _start
|
.global _start
|
||||||
.align 4
|
.align 4
|
||||||
_start:
|
_start:
|
||||||
|
|
||||||
|
la a0, _estack
|
||||||
|
li a7, uvm32_syscall_stackprotect
|
||||||
|
ecall
|
||||||
|
|
||||||
# sp is already setup by vm
|
# sp is already setup by vm
|
||||||
sw ra,12(sp)
|
sw ra,12(sp)
|
||||||
jal ra, main
|
jal ra, main
|
||||||
#if 1
|
|
||||||
// rust will interpret the "#if 1" and "#include" as comments and ignore
|
li a7, uvm32_syscall_halt
|
||||||
// C, asm, zig will include the file below, which references a constant from uvm32_sys.h
|
|
||||||
#include "non-rust-crt0-hack.S"
|
|
||||||
#else
|
|
||||||
// only rust will see this
|
|
||||||
li a7, {UVM32_SYSCALL_HALT}
|
|
||||||
#endif
|
|
||||||
ecall
|
ecall
|
||||||
|
|
||||||
.section .data
|
.section .data
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -78,8 +78,9 @@ SECTIONS
|
||||||
_sstack = .;
|
_sstack = .;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
/* _sstack = .;*/
|
.stack : ALIGN( 16 ) {
|
||||||
|
_estack = .;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,7 @@ void print_maze() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
init_maze();
|
init_maze();
|
||||||
carve(1, 1);
|
carve(1, 1);
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
li a7,UVM32_SYSCALL_HALT
|
|
||||||
|
|
@ -9,7 +9,7 @@ use core::panic::PanicInfo;
|
||||||
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
|
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
|
||||||
|
|
||||||
// startup code
|
// startup code
|
||||||
global_asm!(include_str!("../../crt0.S"), UVM32_SYSCALL_HALT = const UVM32_SYSCALL_HALT);
|
global_asm!(include_str!("../../crt0.S"));
|
||||||
|
|
||||||
fn syscall(id: u32, param1: u32, param2: u32) -> u32 {
|
fn syscall(id: u32, param1: u32, param2: u32) -> u32 {
|
||||||
let mut value;
|
let mut value;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
// System provided UVM32_SYSCALLs, start at 0x10000000
|
// System provided UVM32_SYSCALLs, start at 0x10000000
|
||||||
#define UVM32_SYSCALL_HALT 0x1000000
|
#define UVM32_SYSCALL_HALT 0x1000000
|
||||||
#define UVM32_SYSCALL_YIELD 0x1000001
|
#define UVM32_SYSCALL_YIELD 0x1000001
|
||||||
|
#define UVM32_SYSCALL_STACKPROTECT 0x1000002
|
||||||
|
|
||||||
#include "uvm32_common_custom.h"
|
#include "uvm32_common_custom.h"
|
||||||
|
|
|
||||||
|
|
@ -59,5 +59,11 @@ static uint32_t syscall(uint32_t id, uint32_t param1, uint32_t param2) {
|
||||||
#define yield() syscall_cast(UVM32_SYSCALL_YIELD, 0, 0)
|
#define yield() syscall_cast(UVM32_SYSCALL_YIELD, 0, 0)
|
||||||
#define printbuf(x, y) syscall_cast(UVM32_SYSCALL_PRINTBUF, x, y)
|
#define printbuf(x, y) syscall_cast(UVM32_SYSCALL_PRINTBUF, x, y)
|
||||||
|
|
||||||
|
extern char _estack;
|
||||||
|
|
||||||
|
static void stackprotect(void) {
|
||||||
|
syscall_cast(UVM32_SYSCALL_STACKPROTECT, &_estack, 0);
|
||||||
|
}
|
||||||
|
|
||||||
#include "uvm32_common_custom.h"
|
#include "uvm32_common_custom.h"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
all:
|
all:
|
||||||
gcc -Wall -pedantic -std=c99 -O2 -DUVM32_MEMORY_SIZE=65535 -I../uvm32 -I../common -o host ../uvm32/uvm32.c host.c
|
gcc -Wall -Werror -pedantic -std=c99 -O2 -DUVM32_MEMORY_SIZE=65535 -I../uvm32 -I../common -o host ../uvm32/uvm32.c host.c
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f host
|
rm -f host
|
||||||
|
|
|
||||||
|
|
@ -202,7 +202,7 @@ int main(int argc, char *argv[]) {
|
||||||
printf("%c", uvm32_getval(&vmst, &evt, ARG0));
|
printf("%c", uvm32_getval(&vmst, &evt, ARG0));
|
||||||
break;
|
break;
|
||||||
case UVM32_SYSCALL_PRINTHEX:
|
case UVM32_SYSCALL_PRINTHEX:
|
||||||
printf("%d", uvm32_getval(&vmst, &evt, ARG0));
|
printf("%08x", uvm32_getval(&vmst, &evt, ARG0));
|
||||||
break;
|
break;
|
||||||
case UVM32_SYSCALL_MILLIS: {
|
case UVM32_SYSCALL_MILLIS: {
|
||||||
clock_t now = clock() / (CLOCKS_PER_SEC / 1000);
|
clock_t now = clock() / (CLOCKS_PER_SEC / 1000);
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -10,6 +10,9 @@
|
||||||
// On an invalid operation, an error is set in uvm32_state_t, but a valid pointer still needs to be temporarily used
|
// On an invalid operation, an error is set in uvm32_state_t, but a valid pointer still needs to be temporarily used
|
||||||
static uint32_t garbage;
|
static uint32_t garbage;
|
||||||
|
|
||||||
|
// magic value for stack canary
|
||||||
|
#define STACK_CANARY_VALUE 0x42
|
||||||
|
|
||||||
#ifndef UVM32_MEMCPY
|
#ifndef UVM32_MEMCPY
|
||||||
#define UVM32_MEMCPY uvm32_memcpy
|
#define UVM32_MEMCPY uvm32_memcpy
|
||||||
void uvm32_memcpy(void *dst, const void *src, int len) {
|
void uvm32_memcpy(void *dst, const void *src, int len) {
|
||||||
|
|
@ -84,6 +87,8 @@ bool uvm32_load(uvm32_state_t *vmst, const uint8_t *rom, int len) {
|
||||||
}
|
}
|
||||||
|
|
||||||
UVM32_MEMCPY(vmst->memory, rom, len);
|
UVM32_MEMCPY(vmst->memory, rom, len);
|
||||||
|
vmst->stack_canary = (uint8_t *)UVM32_NULL;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -135,6 +140,12 @@ void uvm32_clearError(uvm32_state_t *vmst) {
|
||||||
uint32_t uvm32_run(uvm32_state_t *vmst, uvm32_evt_t *evt, uint32_t instr_meter) {
|
uint32_t uvm32_run(uvm32_state_t *vmst, uvm32_evt_t *evt, uint32_t instr_meter) {
|
||||||
uint32_t num_instr = 0;
|
uint32_t num_instr = 0;
|
||||||
|
|
||||||
|
if (vmst->stack_canary != UVM32_NULL && *vmst->stack_canary != STACK_CANARY_VALUE) {
|
||||||
|
setStatusErr(vmst, UVM32_ERR_STACKOVERFLOW);
|
||||||
|
setup_err_evt(vmst, evt);
|
||||||
|
return num_instr;
|
||||||
|
}
|
||||||
|
|
||||||
if (vmst->status != UVM32_STATUS_PAUSED) {
|
if (vmst->status != UVM32_STATUS_PAUSED) {
|
||||||
setStatusErr(vmst, UVM32_ERR_NOTREADY);
|
setStatusErr(vmst, UVM32_ERR_NOTREADY);
|
||||||
setup_err_evt(vmst, evt);
|
setup_err_evt(vmst, evt);
|
||||||
|
|
@ -163,6 +174,25 @@ uint32_t uvm32_run(uvm32_state_t *vmst, uvm32_evt_t *evt, uint32_t instr_meter)
|
||||||
vmst->ioevt.typ = UVM32_EVT_YIELD;
|
vmst->ioevt.typ = UVM32_EVT_YIELD;
|
||||||
setStatus(vmst, UVM32_STATUS_PAUSED);
|
setStatus(vmst, UVM32_STATUS_PAUSED);
|
||||||
break;
|
break;
|
||||||
|
case UVM32_SYSCALL_STACKPROTECT: {
|
||||||
|
// don't allow errant code to change it once set
|
||||||
|
if (vmst->stack_canary == (uint8_t *)UVM32_NULL) {
|
||||||
|
uint32_t param0 = vmst->core.regs[10];
|
||||||
|
uint32_t mem_offset = param0 - MINIRV32_RAM_IMAGE_OFFSET;
|
||||||
|
|
||||||
|
// check data fits in ram
|
||||||
|
if (mem_offset > UVM32_MEMORY_SIZE) {
|
||||||
|
setStatusErr(vmst, UVM32_ERR_STACKOVERFLOW);
|
||||||
|
setup_err_evt(vmst, evt);
|
||||||
|
}
|
||||||
|
// check canary is inside valid memory
|
||||||
|
if (mem_offset < UVM32_MEMORY_SIZE) {
|
||||||
|
// set canary
|
||||||
|
vmst->stack_canary = &vmst->memory[mem_offset];
|
||||||
|
*vmst->stack_canary = STACK_CANARY_VALUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} break;
|
||||||
default:
|
default:
|
||||||
// user defined syscalls
|
// user defined syscalls
|
||||||
vmst->ioevt.typ = UVM32_EVT_SYSCALL;
|
vmst->ioevt.typ = UVM32_EVT_SYSCALL;
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
X(UVM32_ERR_INTERNAL_CORE) \
|
X(UVM32_ERR_INTERNAL_CORE) \
|
||||||
X(UVM32_ERR_INTERNAL_STATE) \
|
X(UVM32_ERR_INTERNAL_STATE) \
|
||||||
X(UVM32_ERR_ARGS) \
|
X(UVM32_ERR_ARGS) \
|
||||||
|
X(UVM32_ERR_STACKOVERFLOW) \
|
||||||
|
|
||||||
#define X(name) name,
|
#define X(name) name,
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|
@ -69,6 +70,7 @@ typedef struct {
|
||||||
struct MiniRV32IMAState core;
|
struct MiniRV32IMAState core;
|
||||||
uint8_t memory[UVM32_MEMORY_SIZE];
|
uint8_t memory[UVM32_MEMORY_SIZE];
|
||||||
uvm32_evt_t ioevt; // for building up in callbacks
|
uvm32_evt_t ioevt; // for building up in callbacks
|
||||||
|
uint8_t *stack_canary;
|
||||||
} uvm32_state_t;
|
} uvm32_state_t;
|
||||||
|
|
||||||
void uvm32_init(uvm32_state_t *vmst);
|
void uvm32_init(uvm32_state_t *vmst);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue