From 2d324c97bea8bdd081d337252d1f096e1cdd410b Mon Sep 17 00:00:00 2001 From: helixhorned Date: Tue, 26 Jun 2012 19:49:59 +0000 Subject: [PATCH] Lunatic: safety tweaks, expose more stuff Arrays inside structs must not be accessible, since they're not bound-checked by the FFI. Therefore, we flatten them into repeated scalar fields and need to write accessor functions later. git-svn-id: https://svn.eduke32.com/eduke32@2786 1a8010ca-5511-0410-912e-c29ae57300e0 --- polymer/eduke32/source/game.c | 9 + polymer/eduke32/source/lunatic/defs.ilua | 271 +++++++++++++++++----- polymer/eduke32/source/lunatic/dynsymlist | 4 + polymer/eduke32/source/lunatic/test.elua | 3 + 4 files changed, 232 insertions(+), 55 deletions(-) diff --git a/polymer/eduke32/source/game.c b/polymer/eduke32/source/game.c index d624b3ae3..d2b5a62aa 100644 --- a/polymer/eduke32/source/game.c +++ b/polymer/eduke32/source/game.c @@ -9779,6 +9779,15 @@ void CON_EnableGecko(int channel,int safe); bool fatInit (uint32_t cacheSize, bool setAsDefaultDevice); #endif +#ifdef LUNATIC +const char *g_sizes_of_what[] = { + "sectortype", "walltype", "spritetype", + "actor_t", "DukePlayer_t", "playerdata_t", "user_defs" }; +int32_t g_sizes_of[] = { + sizeof(sectortype), sizeof(walltype), sizeof(spritetype), + sizeof(actor_t), sizeof(DukePlayer_t), sizeof(playerdata_t), sizeof(user_defs) }; +#endif + int32_t app_main(int32_t argc, const char **argv) { int32_t i = 0, j; diff --git a/polymer/eduke32/source/lunatic/defs.ilua b/polymer/eduke32/source/lunatic/defs.ilua index d5d73e5c1..920702173 100644 --- a/polymer/eduke32/source/lunatic/defs.ilua +++ b/polymer/eduke32/source/lunatic/defs.ilua @@ -68,18 +68,39 @@ typedef struct { vec3_t pos; int16_t hitsprite, hitwall, hitsect; } hitdata_t; + +typedef struct { + char r,g,b,f; +} palette_t; #pragma pack(pop) ]] -local vec3_t = ffi.typeof("vec3_t") +local vec3_ct = ffi.typeof("vec3_t") local hitdata_ct = ffi.typeof("hitdata_t") -assert(ffi.sizeof('sectortype')==40) -assert(ffi.sizeof('walltype')==32) -assert(ffi.sizeof('spritetype')==44) - ---- engine data and functions ---- +-- GLOBAL gv: provides access to C global *scalars* and safe functions +-- XXX: still exposes C library functions etc. contained in ffi.C. +-- Is this a problem? +local gv_ = { + -- all non-scalars need to be explicitly listed here and access to them is + -- redirected to the dummy empty table... +} + +local dummy_empty_table = {} + +-- this is for declarations of arrays or pointers +-- NOTE: don't declare multiple pointers on one line (like int32_t *a, *b;)! +local function decl(str) + for varname in string.gmatch(str, "([%a_][%w_]*)[[(;]") do +-- print("protect "..varname) + gv_[varname] = dummy_empty_table + end + + ffi.cdef(str) +end + ffi.cdef[[int32_t engine_main_arrays_are_static, engine_v8;]] -- NOTE TO SELF: This is not C, never EVER write @@ -87,20 +108,20 @@ ffi.cdef[[int32_t engine_main_arrays_are_static, engine_v8;]] -- when checking a C variable x for 'thuthiness' if (ffi.C.engine_main_arrays_are_static ~= 0) then -- print('main arrays are static'); - ffi.cdef[[ -sectortype sector[]; -walltype wall[]; -spritetype sprite[]; -spriteext_t spriteext[]; -]] + decl[[ + sectortype sector[]; + walltype wall[]; + spritetype sprite[]; + spriteext_t spriteext[]; + ]] else -- print('main arrays are pointers'); - ffi.cdef[[ -sectortype *sector; -walltype *wall; -spritetype *sprite; -spriteext_t *spriteext; -]] + decl[[ + sectortype *sector; + walltype *wall; + spritetype *sprite; + spriteext_t *spriteext; + ]] end if (ffi.C.engine_v8 == 0) then @@ -141,28 +162,86 @@ enum { ffi.cdef[[ const int16_t numsectors, numwalls; const int32_t numyaxbunches; +]] +decl[[ const int16_t headspritesect[MAXSECTORS+1], headspritestat[MAXSTATUS+1]; const int16_t prevspritesect[MAXSPRITES], prevspritestat[MAXSPRITES]; const int16_t nextspritesect[MAXSPRITES], nextspritestat[MAXSPRITES]; const int16_t headsectbunch[2][MAXBUNCHES], nextsectbunch[2][MAXSECTORS]; - int16_t yax_getbunch(int16_t i, int16_t cf); int32_t hitscan(const vec3_t *sv, int16_t sectnum, int32_t vx, int32_t vy, int32_t vz, hitdata_t *hitinfo, uint32_t cliptype); ]] +-- array -> element flattening inside structs, +-- e.g. int32_t a[4] --> int32_t _a0, _a1, _a2, _a3; +local function repeat_n_elts(type, namebase, num) + local strbuf = { "const "..type.." " } + + for i=1,num do + local str = namebase..tostring(i-1) + if (i < num) then + str = str.."," + end + strbuf[#strbuf+1] = str + end + strbuf[#strbuf+1] = ";" + + return table.concat(strbuf) +end ---- game structs ---- ffi.cdef[[ +enum dukeinv_t { + GET_STEROIDS, + GET_SHIELD, + GET_SCUBA, + GET_HOLODUKE, + GET_JETPACK, + GET_DUMMY1, + GET_ACCESS, + GET_HEATS, + GET_DUMMY2, + GET_FIRSTAID, + GET_BOOTS, + GET_MAX +}; + +enum dukeweapon_t { + KNEE_WEAPON, + PISTOL_WEAPON, + SHOTGUN_WEAPON, + CHAINGUN_WEAPON, + RPG_WEAPON, + HANDBOMB_WEAPON, + SHRINKER_WEAPON, + DEVISTATOR_WEAPON, + TRIPBOMB_WEAPON, + FREEZE_WEAPON, + HANDREMOTE_WEAPON, + GROW_WEAPON, + MAX_WEAPONS +}; + +enum { + MAXPLAYERS = 16, +}; +]] + +ffi.cdef([[ #pragma pack(push,1) -// XXX: might still need to make some fields read-only +// TODO: still need to make some fields read-only +// NOTE: must not expose arrays in structs!!! typedef struct { - const int32_t t_data[14]; // 56b sometimes used to hold offsets to con code +]] +..repeat_n_elts("int32_t", "_t", 14).. +[[ +// const int32_t t_data[14]; // 56b sometimes used to hold offsets to con code int16_t picnum,ang,extra,owner; //8b int16_t movflag,tempang,timetosleep; //6b @@ -172,9 +251,106 @@ typedef struct const int16_t lightId, lightcount, lightmaxrange, cgg; //8b int16_t actorstayput, dispicnum, shootzvel; // 6b - - const int8_t _do_not_use[8]; +]] +..repeat_n_elts("int8_t", "_d", 8).. +[[ +// const int8_t _do_not_use[8]; } actor_t; + +typedef struct { + vec3_t pos, opos, vel, npos; + int32_t bobposx, bobposy; + int32_t truefz, truecz, player_par; + int32_t randomflamex, exitx, exity; + int32_t runspeed, max_player_health, max_shield_amount; + + uint32_t interface_toggle_flag; + + uint8_t palette; + + uint16_t max_actors_killed, actors_killed; + uint16_t gotweapon, zoom; +]] +..repeat_n_elts("int16_t", "_lx", 64)..repeat_n_elts("int16_t", "_ly", 64).. +[[ +// int16_t loogiex[64], loogiey[64]; + int16_t sbs, sound_pitch; + + int16_t ang, oang, angvel, cursectnum, look_ang, last_extra, subweapon; +]] +..repeat_n_elts("int16_t", "_ma", ffi.C.MAX_WEAPONS) +..repeat_n_elts("int16_t", "_aa", ffi.C.MAX_WEAPONS) +..repeat_n_elts("int16_t", "_ia", ffi.C.GET_MAX).. +[[ +// int16_t max_ammo_amount[MAX_WEAPONS], ammo_amount[MAX_WEAPONS], inv_amount[GET_MAX]; + int16_t wackedbyactor, pyoff, opyoff; + + int16_t horiz, horizoff, ohoriz, ohorizoff; + int16_t newowner, jumping_counter, airleft; + int16_t fta, ftq, access_wallnum, access_spritenum; + int16_t got_access, weapon_ang, visibility; + int16_t somethingonplayer, on_crane, i, one_parallax_sectnum; + int16_t random_club_frame, one_eighty_count; + int16_t dummyplayersprite, extra_extra8; + int16_t actorsqu, timebeforeexit, customexitsound, last_pissed_time; +]] +..repeat_n_elts("int16_t", "_w", ffi.C.MAX_WEAPONS).. +[[ +// int16_t weaprecs[MAX_WEAPONS]; + int16_t weapon_sway, crack_time, bobcounter; + + int16_t orotscrnang, rotscrnang, dead_flag; // JBF 20031220: added orotscrnang + int16_t holoduke_on, pycount; + + uint8_t max_secret_rooms, secret_rooms; + uint8_t frag, fraggedself, quick_kick, last_quick_kick; + uint8_t return_to_center, reloading, weapreccnt; + uint8_t aim_mode, auto_aim, weaponswitch, movement_lock, team; + uint8_t tipincs, hbomb_hold_delay, frag_ps, kickback_pic; + + uint8_t gm, on_warping_sector, footprintcount, hurt_delay; + uint8_t hbomb_on, jumping_toggle, rapid_fire_hold, on_ground; + uint8_t inven_icon, buttonpalette, over_shoulder_on, show_empty_weapon; + + uint8_t jetpack_on, spritebridge, lastrandomspot; + uint8_t scuba_on, footprintpal, heat_on, invdisptime; + + uint8_t holster_weapon, falling_counter, footprintshade; + uint8_t refresh_inventory, last_full_weapon; + + uint8_t toggle_key_flag, knuckle_incs, knee_incs, access_incs; + uint8_t walking_snd_toggle, palookup, hard_landing, fist_incs; + + int8_t numloogs, loogcnt, scream_voice, transporter_hold; + int8_t last_weapon, cheat_phase, weapon_pos, wantweaponfire, curr_weapon; + + palette_t pals; +]] +..repeat_n_elts("char", "_n", 32).. +[[ +// char name[32]; +} DukePlayer_t; + +typedef struct { + uint32_t bits; // 4b + int16_t fvel, svel; // 4b + int8_t avel, horz; // 2b + int8_t extbits, filler; // 2b +} input_t; + +typedef struct { + DukePlayer_t *ps; + input_t *sync; + + int32_t netsynctime; + int16_t ping, filler; + int32_t pcolor, pteam; + uint8_t frags[MAXPLAYERS], wchoice[MAX_WEAPONS]; + + char vote, gotvote, pingcnt, playerquitflag; + char user_name[32]; + uint32_t revision; +} playerdata_t; #pragma pack(pop) enum @@ -284,17 +460,26 @@ typedef struct { char display_bonus_screen; char show_level_text; } user_defs; -]] +]]) -ffi.cdef[[ +decl[[ +const char *g_sizes_of_what[]; +int32_t g_sizes_of[]; actor_t actor[MAXSPRITES]; user_defs ud; +playerdata_t g_player[MAXPLAYERS]; ]] -- functions -ffi.cdef[[ -double gethitickms(void); -]] +ffi.cdef "double gethitickms(void);" + +local ffiC = ffi.C + +-- sanity-check struct type sizes +for i=0,6 do + assert(ffi.sizeof(ffi.typeof(ffi.string(ffiC.g_sizes_of_what[i]))) + == ffiC.g_sizes_of[i]) +end --- default defines local con = require("con_lang") @@ -393,40 +578,16 @@ end ---=== Restricted access to C variables from Lunatic ===--- -local ffiC = ffi.C - -- error(..., 2) is to blame the caller and get its line numbers -local det = {} -- dummy empty table local tmpmt = { __index = function() error('dummy variable: read access forbidden', 2) end, __newindex = function() error('dummy variable: write access forbidden', 2) end, - __metatable = true -- forbid setting the metatable + __metatable = true, -- forbid setting the metatable } -oG.setmetatable(det, tmpmt) +oG.setmetatable(dummy_empty_table, tmpmt) --- XXX: this is incorrect -- ffi.C also contains C library functions, etc. --- GLOBAL gv: provides access to C global *scalars* -gv = { - -- all non-scalars need to be explicitly listed - -- and access to them is redirected to the dummy - -- empty table... this is somewhat ugly - sector = det, - wall = det, - sprite = det, - spriteext = det, - - headspritesect = det, headspritestat = det, - prevspritesect = det, prevspritestat = det, - nextspritesect = det, nextspritestat = det, - - actor = det, - ud = det, - - -- functions, too! - yax_getbunch = det, - hitscan = det, -} +gv = gv_ local tmpmt = { __index = ffiC, __newindex = function() error("cannot create new or write into existing fields of 'gv'", 2) end, @@ -572,7 +733,7 @@ function hitscan(x,y,z, sectnum, vx,vy,vz, cliptype) error('passed out-of-bounds sector number'..sectnum, 2) end - local vec = vec3_t(x,y,z) + local vec = vec3_ct(x,y,z) local hitdata = hitdata_ct() ffiC.hitscan(vec, sectnum, vx,vy,vz, hitdata, cliptype) diff --git a/polymer/eduke32/source/lunatic/dynsymlist b/polymer/eduke32/source/lunatic/dynsymlist index 2d3474ee6..eb9288162 100644 --- a/polymer/eduke32/source/lunatic/dynsymlist +++ b/polymer/eduke32/source/lunatic/dynsymlist @@ -2,6 +2,9 @@ engine_main_arrays_are_static; engine_v8; +g_sizes_of_what; +g_sizes_of; + sector; wall; sprite; @@ -27,6 +30,7 @@ hitscan; actor; ud; +g_player; luaJIT_BC_*; diff --git a/polymer/eduke32/source/lunatic/test.elua b/polymer/eduke32/source/lunatic/test.elua index a5962288a..68f007480 100644 --- a/polymer/eduke32/source/lunatic/test.elua +++ b/polymer/eduke32/source/lunatic/test.elua @@ -91,6 +91,7 @@ end --]] --DBG_.printkv('_G in test.elua', _G) +checkfail('local i = sprite["qwe"]') -- indexing struct array with non-numeric type checkfail('print(sprite[100000].ceilingpal)') -- oob read access checkfail('setmetatable(sprite, {})') -- set metatable forbidden checkfail('sector[-1].ceilingpal = 4') -- oob write access @@ -113,6 +114,8 @@ checkfail('string.dump(gameevent)') -- string.dump is unavailable checkfail('gv.luaJIT_setmode(nil, 0, 0)') checkfail('gv.luaJIT_BC_con_lang') checkfail('gv.yax_getbunch(0,0)') +-- we don't have arrays in Lua-accessible structs now +checkfail('local i = actor[0].t_data[15]') printf('ceilingbunch of sector 0: %d', getbunch(0, gv.CEILING))