From e5fd17aff61a8d0f176c0135e4d25204b32212f4 Mon Sep 17 00:00:00 2001 From: Toby Jaffey Date: Sun, 14 Dec 2025 18:35:00 +0000 Subject: [PATCH] Fix issues with unaligned memory bus rd/wr. Improve fuzzing. --- hosts/fuzz/Makefile | 2 +- hosts/fuzz/fuzz.c | 17 +++++++++------ precompiled/self.bin | Bin 3460 -> 3700 bytes uvm32/uvm32.c | 49 ++++++++++++++++++++++++++++++++++++------- uvm32/uvm32.h | 17 +++++++++++++++ 5 files changed, 70 insertions(+), 15 deletions(-) diff --git a/hosts/fuzz/Makefile b/hosts/fuzz/Makefile index 92e0b93..3ba5ade 100644 --- a/hosts/fuzz/Makefile +++ b/hosts/fuzz/Makefile @@ -1,6 +1,6 @@ TOPDIR=../.. all: - afl-clang-fast -g3 -fsanitize=address,undefined -Wall -DUVM32_MEMORY_SIZE=8388608 -I${TOPDIR}/uvm32 -I${TOPDIR}/common -o host-fuzz ${TOPDIR}/uvm32/uvm32.c fuzz.c + afl-clang-fast -g3 -fsanitize=address,undefined -Wall -DUVM32_MEMORY_SIZE=4096 -I${TOPDIR}/uvm32 -I${TOPDIR}/common -o host-fuzz ${TOPDIR}/uvm32/uvm32.c fuzz.c afl-fuzz -i${TOPDIR}/precompiled -oo ./host-fuzz clean: diff --git a/hosts/fuzz/fuzz.c b/hosts/fuzz/fuzz.c index 9d2cb94..08fae0a 100644 --- a/hosts/fuzz/fuzz.c +++ b/hosts/fuzz/fuzz.c @@ -9,14 +9,19 @@ __AFL_FUZZ_INIT(); int main(int argc, char *argv[]) { __AFL_INIT(); - uvm32_state_t vmst; uvm32_evt_t evt; - uvm32_init(&vmst); - unsigned char *rom = __AFL_FUZZ_TESTCASE_BUF; - while (__AFL_LOOP(10000)) { - uvm32_load(&vmst, rom, __AFL_FUZZ_TESTCASE_LEN); - uvm32_run(&vmst, &evt, 1000); + uvm32_state_t *vmst = malloc(sizeof(uvm32_state_t)); + + while (__AFL_LOOP(100000)) { + memset(vmst, 0x00, sizeof(uvm32_state_t)); + uvm32_init(vmst); + unsigned char *rom = __AFL_FUZZ_TESTCASE_BUF; + uvm32_load(vmst, rom, __AFL_FUZZ_TESTCASE_LEN); + memset(&evt, 0x00, sizeof(evt)); + for (int i=0;i<10;i++) { + uvm32_run(vmst, &evt, 1000); + } } return 0; diff --git a/precompiled/self.bin b/precompiled/self.bin index b59ef39987672e9e1eb4e5c6a775962d26ccd4e4..531f49e1a1081b79b7fa5d3f7ad6082ecbb7c1a8 100755 GIT binary patch delta 2503 zcmah~ZERcB8GeuN$FZFT0w*6+K}yC=<5JqH+Xc+_D`i9x6P1e8B$~v?;4*cZCc>no zLHmK-IkuZNRE0CzsZ2`-C4p%m*d2KMn1s6~rd=D#v?kM}kyW>i`7_n)65o`Nc+a_Z z+pT|Q>DBQ$=RM~>&+~qqk-L`eKJu*xin%6A%Czx`F!JmQCGX0$P*RL$XM<5^^>Va( zR+ycpH1<=~=c7F@J^v~@=Qgr$g!m+1l-a_f+@pOb(P1nKV|sC*G`=PnTemv$WE<}j zPLnk9WNp8Lu9U|Anrh24?1%Oyi2}ct>wazUyIAvUo%?UU_+}zIY_L@9K-9_bu(tW* zD9%=LVJcZ2caYV-pAv4mi8)sdE_4G>8^{@(#Mnm8PbYOZn4z>u!xLbgHpf zIIUP{oAQe34aQZ!HhkbZ+x|k}*K_gz_${0Y{F-k11>pHIrDBO}Rhn3#Dveo{#!X)! z=jvrsa412Gy7O#-oMtnm6w$y+u?4s)OTL>NbFsQN%?WJRt19*Tif!PFGs=IU)cUWQ zg8v>UEv(7}q`p$>|4_+>g)h`tlV(++w6=duv$ns-T%bkFbi_=z?s-YK+P-R7TX$;K zmd7<~^HZAD@na2p8um1+?N^$0fJaj?gJeBy)F9_D*CoP>5d1bZwTrBY2#GqPg!S4r z#YRW$^i=y!UAvd*seAL9wq?JT+Okti-Iot(Tla@jTX%-EZ7h`9hD0>#NV|_|U}OYf z>&zezoJNzxA&$$}FfUicgUv|fa>X4iQ+yi*KJkr2xw}y=V^Aa-O(fkzZ!C5%x%JfbXNqGz})m7NTef5sW&0-vi8=C;haH9*Z7c}^*0Q$^Z+>< zbzNq5MMT@$va|mrS>8utpAphxS(2G@ z#fh2^OW$YmSd8548j0rbQ)((p&XZ=RFuzC6({ta9H=}nP?SL>d3vOnHQj;d_O(db9 zSu&l&^HFE9tV?r;=_KbH0Mzu36w9}Q5j_AhG|lbw+oXVLu`~(&QGB#W(l1uTXrVGd zAL$^&asI08o5uQZ$ve(Vsj2#i^yB1>sQ>455qT78aAI2|&WSlM7ax{%>8{1iJJ3o~^g5#D-$;QylHU^_5axObizj3S8X3o$TSu zBzj&6z}iDy%q>olIF=))7wYnV++UR!3`FE~#U72R3$MxEE+&VIO!(#tf&499xTqV4 z)d!YkYj|U#77@|&Mi3E*!nBSoTGJ~`@Y5ApE;E<=5D0Yu)!oeBp?HS&5+|o|PM6tk zvQDgpAqvS48cB{URYcaWhRTBq*OQHvxL&$x!Chzm9 z^Xgra*{mm;HbEKH_Y8CyPHy@G(ni#o){ClcP&01<=xX)nA|= zT9r(q$_5W2iq%-xknAc~McHSrpF;sa@?syeGv~-%?nY=bx%pvE3xwdIW$z7l|5E=e9JHs#)vHA+NzWsZd+VX%&{mn@^Ww*m@8OU9K_7 zVE>Y>`ynv>)NWMc_<6fMn4h=r59XgZ2l)o4nWMs6P&DSO{YbDsEA&z&;f?XL_MTwj z92}!J9Fyi*`WfKGrIcgl&A{ z!VJbvFrEQOkm{cSNEMRAG*GIAX`oUIr-J^|+(ZCH-e=}XjGfs3BfzNrlK`RoPb&17 z=M^~2^AaynEz4(b$?{q2H>+WpeNnUCQDePkO{_*`c9&-T`oTjH>$TOWHBqlFIV(pR z2|b7Gx>q~B_Ac!Au-#EgJ^}jyOzjV1Ou}dbCBv`=*jHd}u!mrsFv4#GBl-`M C1cliE delta 2243 zcmZuyU2Ggz6+U-nXYTHhP?PI8KtSGl9Iu|?xeh&GF}tL6?TjAyNkOhFJ}D9u}-ks{tB;2zq%s7rhhZ{pivV>d1btD@uOmf$l*=$GQQ=` z@}!=rT1Ar@!PE_M-&->UPm}xcb-mCgB)+foOr zLu9jq)_xX?8mk`x1i%g71=m~oA8?Gt5w!bHXm(OX!e7jWA@M}v-f_L z*@NF@_Q3ZU{FvRBJHzbsbId-;EiVJq3CN5A~xBRMP&DVKsZ>_ zafsJHs_FMJ&Aaak^Y)H1{eH&0`>&8bbb`F0QPLk^U~iGW_XGoYJ&vGd#zft2lf*11 zJD0wViB=>Y>LFpaqTpDIvO{2xXcRw1RNRfsI>kxOr1F7PVDi+dciam{z9o1ga({YL zbLaWDi+kWdbs&X|V}bEY9GX(Ve}$ZCdP9X|kyAeK?~uFU8={#dx5r3`lW}bg?o)vfbk1M{VX7s@?7rElcpHm^)YRmV>-6M+XHT*4)|p=b`m*p}r|s#+cL2 zGB?2~+m523UMI0qBQaU!qEW5B+ifP#XDHy{e(o@Nmwa-U zjS*>nhuptb9xnEvx~41FMb7{^W{tc7laA!_h?vmA|=~d z3JYpnO31m#C};PdO=UST_dwh`|P}hgeWwA#uJ)?l%x!{_Yn# z;RORZw-g0)=hcQEh}syFlXYxl{x}Z*`7v@PvskPSXvq(gpZ?0-8EBs+FZ!f1Q6R;|u1p+oeZVIi3=n)%U3^f#)F~VDUu6?afe08Xri#@6BN^VQ zmt-w>mr)%4-WLGiZ(A(g(}!97M&#GEaKU_Cfs9*j<4`>w&sP=Tbtj4W^i_;k*Bqm* zfzUh7PNi4hcJ{>f+s?k&zK(Zjo7;o_Grfz#)8;iNcOZ6nOBjtPoaWb@ugCT^I9mU7 zoHdu6@5LJ|34>Gk6Tam9Ahv%i4HWs`%cP!Am2P-OYmWIUQVvBQZcGH2V%RTI*VB7A%LRrakB)Cg%?Wzqx?$%q5R)a z;9*0@SNOVm^g0QB&maFYp?j~}FKr|xFX;9wN+(8j``Hak^8LE~izid|^Bb0(PN+?P zCkx%Uw_$Rur$@pI_2(s?YdalR#n05WVD5tQ3rgD_X2*|Ols^XfA*29#2J#Z51UZ(Z z{I4NTm>nr$yaZW>`~h+_Mfu~90z~=DLq7xQ`WWRu2}wf+A;XYIAqOFZZyO`}2a=aQ A3jhEB diff --git a/uvm32/uvm32.c b/uvm32/uvm32.c index 7b982e4..ca57642 100644 --- a/uvm32/uvm32.c +++ b/uvm32/uvm32.c @@ -254,6 +254,7 @@ uint32_t uvm32_run(uvm32_state_t *vmst, uvm32_evt_t *evt, uint32_t instr_meter) while(vmst->_status == UVM32_STATUS_RUNNING && instr_meter > 0) { uint64_t elapsedUs = 1; uint32_t ret; + ret = MiniRV32IMAStep(vmst, &vmst->_core, vmst->_memory, elapsedUs, 1); instr_meter--; @@ -420,22 +421,22 @@ uint32_t _uvm32_extramLoad(void *userdata, uint32_t addr, uint32_t accessTyp) { // Any other value will have caused UVM32_ERR_INTERNAL_CORE switch(accessTyp) { case 0: - return ((int8_t *)vmst->_extram)[addr]; + return _uvm32_load1s(vmst->_extram, addr); break; case 1: - return ((int16_t *)vmst->_extram)[addr/2]; + return _uvm32_load2s(vmst->_extram, addr); break; case 2: - return ((uint32_t *)vmst->_extram)[addr / 4]; + return _uvm32_load4(vmst->_extram, addr); break; case 5: - return ((uint16_t *)vmst->_extram)[addr/2]; + return _uvm32_load2(vmst->_extram, addr); break; // have a default case to keep coverage check happy // no other values are possible here default: // fall through case 4: - return ((uint8_t *)vmst->_extram)[addr]; + return _uvm32_load1(vmst->_extram, addr); break; } @@ -454,15 +455,15 @@ uint32_t _uvm32_extramStore(void *userdata, uint32_t addr, uint32_t val, uint32_ if (addr < vmst->_extramLen) { switch(accessTyp) { case 1: - ((uint16_t *)vmst->_extram)[addr/2] = val; + _uvm32_store2(vmst->_extram, addr, val); break; case 2: - ((uint32_t *)vmst->_extram)[addr/4] = val; + _uvm32_store4(vmst->_extram, addr, val); break; // no other values are valid here and will be stopped above default: // fall through case 0: - ((uint8_t *)vmst->_extram)[addr] = val; + _uvm32_store1(vmst->_extram, addr, val); break; } vmst->_extramDirty = true; @@ -490,3 +491,35 @@ uint32_t uvm32_getProgramCounter(const uvm32_state_t *vmst) { return vmst->_core.pc; } +// Access of memory bus in alignment safe way +void _uvm32_store4(void *p, uint32_t off, uint32_t val) { + UVM32_MEMCPY((uint8_t *)p + off, &val, 4); +} +void _uvm32_store2(void *p, uint32_t off, uint16_t val) { + UVM32_MEMCPY((uint8_t *)p + off, &val, 2); +} +void _uvm32_store1(void *p, uint32_t off, uint8_t val) { + ((uint8_t *)p)[off] = val; +} +uint32_t _uvm32_load4(void *p, uint32_t off) { + uint32_t v; + UVM32_MEMCPY(&v, (uint8_t *)p + off, 4); + return v; +} +uint16_t _uvm32_load2(void *p, uint32_t off) { + uint16_t v; + UVM32_MEMCPY(&v, (uint8_t *)p + off, 2); + return v; +} +uint8_t _uvm32_load1(void *p, uint32_t off) { + return ((uint8_t *)p)[off]; +} +int16_t _uvm32_load2s(void *p, uint32_t off) { + int16_t v; + UVM32_MEMCPY(&v, (uint8_t *)p + off, 2); + return v; +} +int8_t _uvm32_load1s(void *p, uint32_t off) { + return ((int8_t *)p)[off]; +} + diff --git a/uvm32/uvm32.h b/uvm32/uvm32.h index e33613b..edb96dc 100644 --- a/uvm32/uvm32.h +++ b/uvm32/uvm32.h @@ -51,6 +51,23 @@ uint32_t _uvm32_extramLoad(void *userdata, uint32_t addr, uint32_t accessTyp); uint32_t _uvm32_extramStore(void *userdata, uint32_t addr, uint32_t val, uint32_t accessTyp); #define MINIRV32_HANDLE_MEM_LOAD_CONTROL( addy, rval ) rval = _uvm32_extramLoad(userdata, addy, ( ir >> 12 ) & 0x7); #define MINIRV32_HANDLE_MEM_STORE_CONTROL( addy, val ) if( _uvm32_extramStore(userdata, addy, val, ( ir >> 12 ) & 0x7) ) return val; +void _uvm32_store4(void *p, uint32_t off, uint32_t val); +void _uvm32_store2(void *p, uint32_t off, uint16_t val); +void _uvm32_store1(void *p, uint32_t off, uint8_t val); +uint32_t _uvm32_load4(void *p, uint32_t off); +uint16_t _uvm32_load2(void *p, uint32_t off); +uint8_t _uvm32_load1(void *p, uint32_t off); +int16_t _uvm32_load2s(void *p, uint32_t off); +int8_t _uvm32_load1s(void *p, uint32_t off); +#define MINIRV32_CUSTOM_MEMORY_BUS + #define MINIRV32_STORE4( ofs, val ) _uvm32_store4(image, ofs, val) + #define MINIRV32_STORE2( ofs, val ) _uvm32_store2(image, ofs, val) + #define MINIRV32_STORE1( ofs, val ) _uvm32_store1(image, ofs, val) + #define MINIRV32_LOAD4( ofs ) _uvm32_load4(image, ofs) + #define MINIRV32_LOAD2( ofs ) _uvm32_load2(image, ofs) + #define MINIRV32_LOAD1( ofs ) _uvm32_load1(image, ofs) + #define MINIRV32_LOAD2_SIGNED( ofs ) _uvm32_load2s(image, ofs) + #define MINIRV32_LOAD1_SIGNED( ofs ) _uvm32_load1s(image, ofs) #ifndef MINIRV32_IMPLEMENTATION #define MINIRV32_STEPPROTO #endif