From 789cd7451690e67299a9b86857872e156c3b807b Mon Sep 17 00:00:00 2001 From: Toby Jaffey Date: Fri, 12 Dec 2025 21:01:40 +0000 Subject: [PATCH] Disable stack canary by default --- doc/README.md | 2 ++ precompiled/self.bin | Bin 5524 -> 5396 bytes uvm32/uvm32.c | 12 +++++++++--- uvm32/uvm32.h | 2 ++ 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/doc/README.md b/doc/README.md index 22b3e9f..f8a3c22 100644 --- a/doc/README.md +++ b/doc/README.md @@ -183,6 +183,8 @@ The uvm32 memory size is set at compile time with `-DUVM32_MEMORY_SIZE=X` (in by Define `UVM32_ERROR_STRINGS` to add an `errstr` field to `uvm32_evt_err_t` giving a printable error string. +Define `UVM32_STACK_PROTECTION` to enable a basic stack canary, to cause an early crash when the stack grows too large. Without this, the VM will normally crash (safely) in some other way which is less easily detected. + ## Debugging Binaries can be disassembled with diff --git a/precompiled/self.bin b/precompiled/self.bin index 20484c7ded57f7d91ac14e11c95f9c290afbaa9f..d25ca78314df373498a3fe21dc20eecd2cf317b6 100755 GIT binary patch delta 1668 zcmZ{jUrbw77{I@K+jDOzw-mTAh~SE?qj4;=SvAbamZD>Wjku2Ru!kj>+$Ao?q&Vk> zk)(BPDKIjfA92e<91q*@f#^fgE|CW|aiBv+BG|={L4?U3FkB53)Nc5lBCe9qpb3D-`}C>h|N95Ft@&N#vpp`S2C4O@xQ+BjF*|@;I08X@QFu>i z!7qgE>~mRhoW=XXuG*LrK)W?0s)DepvasSP&4C5IVKG>8ld5L}*@ZU(yb}Pvmdl{K zBM*Q&7GtFp+q^7Ar3naLyKTWH(JnUphFzk|;0`~)A4Pjvb9}{ZS^`6LtD+T~ASTi2 zwX`VF@C3Nom%PDbYVc3vNh~%T%)K(rEAvBjT$jBV8S-M2p>Au#&wMOLDf6oATdz;Q z@`x8t74D(J4-L-?JF(FCrZ_cP1|10*1pc;XTu2vDTGwQjILHYK8JizDW&dQdVoy2Lq>ZEaP4Ebi5Jc zL!c(k{OfDDj7QBj;bm+x-x6(?up;xjqIRhsBU?c0lwl@|jkv2OM4#U9gLYo3!xAOm z&?492Zly=?;I!i2QyGoKA=o3+CCU8w03-5%rX;G@`I z9Nn38fmb?InYMS%iP|R_<64(2#2`WQg-@9OLA)kzhZ;{=>ZpUjPMY( z#E2CFgG4vcM~o9m`b^fD-Jnly(C0Vk$ql-aoyz6^FJU1W>N6m4iC8akmE>NckLV|q zEC`$+yo4)fjaHIt%@8TApraX{5K8y delta 1667 zcmZ{kUrdu%6u{5@{@p^qmcl3Clt9<7qfU(@tJ6K04Kq{_#&mxiGbEUN$s~KhWplbo z#y1NT85w^LnZ%I6mQ8#x+e4Yn5+Bgusu_#CxVp>;8B87|v5N?1BJA9DOh)Fz@4M%m zd;Z;fPusn|dxIl48^BQ2{hf{%c5G*NU?@A93$}ckzZJ~}8=F+Wp$a>!6?Wr9*i5bp z^WceHrlA#Us4~hReC&!)K~v$boFLcSfv&L?U;^Lmo z)4U49u_~;VU(N5kE>3I~s#S)1sfzk|C~7C`4p7|@`5Cqa=jC^#f}gQg@kym_Y*WgZ zg1;!+vT82MfeWJ215}IPPNL=l`qi?njocj?h`G>7m(Zxv6LFAZ9FThzR1bi)W)4CF zPOv`XqCwRvX{fr4O)DJfjDn zDvN~UbP^5+Z7yz>T=L@I}pRi|JMGAw5JrVK`hHr!U z?UWvA{w?`FX5*|*KasG(sdV?0WObyC;*e*JcGa#+WW;dXle4e=lEJ-TotmPvmxJk5 z!1T>f2N}bt9-?*ZII3P++kZ9G#A03Im6_CtU%i`JYpxjD>`%yxVB%J6R7@m>ckRQ9 z%qKIZ?_GZMushzw`b=-6KeK{0tW&_=MpO_-iE5&jP&{DIXMla3m?m`6H}gm2t2@!jS z)OL$vl1*NF<^EODM# zYDP395X~(4j*z_Ecga4v+}^M(AhCR7nSK5-b_YGn{}ovE7`u0c9Z27}nm&GFhKd{| TmQGYp@*p8jME~xvkpcV-S+M*2 diff --git a/uvm32/uvm32.c b/uvm32/uvm32.c index c1ccba0..536a7b7 100644 --- a/uvm32/uvm32.c +++ b/uvm32/uvm32.c @@ -16,8 +16,9 @@ // 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; -// magic value for stack canary -#define STACK_CANARY_VALUE 0x42 +#ifdef UVM32_STACK_PROTECTION +#define STACK_CANARY_VALUE 0x42 // magic value for stack canary +#endif #ifndef UVM32_MEMCPY #define UVM32_MEMCPY uvm32_memcpy @@ -101,8 +102,9 @@ bool uvm32_load(uvm32_state_t *vmst, const uint8_t *rom, int len) { } UVM32_MEMCPY(vmst->_memory, rom, len); +#ifdef UVM32_STACK_PROTECTION vmst->_stack_canary = (uint8_t *)NULL; - +#endif return true; } @@ -207,11 +209,13 @@ uint32_t uvm32_run(uvm32_state_t *vmst, uvm32_evt_t *evt, uint32_t instr_meter) orig_instr_meter = min_instrs; } +#ifdef UVM32_STACK_PROTECTION if (vmst->_stack_canary != NULL && *vmst->_stack_canary != STACK_CANARY_VALUE) { setStatusErr(vmst, UVM32_ERR_INTERNAL_CORE); setup_err_evt(vmst, evt); return orig_instr_meter - instr_meter; } +#endif if (vmst->_status != UVM32_STATUS_PAUSED) { setStatusErr(vmst, UVM32_ERR_NOTREADY); @@ -243,6 +247,7 @@ uint32_t uvm32_run(uvm32_state_t *vmst, uvm32_evt_t *evt, uint32_t instr_meter) setStatus(vmst, UVM32_STATUS_ENDED); break; case UVM32_SYSCALL_STACKPROTECT: { +#ifdef UVM32_STACK_PROTECTION // don't allow errant code to change it once set if (vmst->_stack_canary == (uint8_t *)NULL) { uint32_t param0 = vmst->_core.regs[10]; // a0 @@ -263,6 +268,7 @@ uint32_t uvm32_run(uvm32_state_t *vmst, uvm32_evt_t *evt, uint32_t instr_meter) *vmst->_stack_canary = STACK_CANARY_VALUE; } } +#endif } break; default: // user defined syscalls diff --git a/uvm32/uvm32.h b/uvm32/uvm32.h index 1027686..51a207e 100644 --- a/uvm32/uvm32.h +++ b/uvm32/uvm32.h @@ -118,7 +118,9 @@ typedef struct { struct MiniRV32IMAState _core; /*! CPU registers */ uint8_t _memory[UVM32_MEMORY_SIZE]; /*! Memory */ uvm32_evt_t _ioevt; /*! Event to be returned on next pause */ +#ifdef UVM32_STACK_PROTECTION uint8_t *_stack_canary; /*! Location of stack canary */ +#endif uint8_t *_extram; /*! External RAM pointer, or NULL */ uint32_t _extramLen; /*! Length of external RAM */ bool _extramDirty; /*! Flag to indicate VM code has modified extram since last run */