From 2758b92f418a806f658f025ce0aa5720a78b1871 Mon Sep 17 00:00:00 2001 From: MysterD Date: Thu, 17 Mar 2022 21:42:04 -0700 Subject: [PATCH] Added sanity checking to overlapping object fields --- src/pc/lua/smlua_cobject.c | 106 +++++++++++++++++++++++++++++++++++++ src/pc/lua/smlua_hooks.c | 11 ++++ src/pc/lua/smlua_hooks.h | 1 + 3 files changed, 118 insertions(+) diff --git a/src/pc/lua/smlua_cobject.c b/src/pc/lua/smlua_cobject.c index fd6daacaa..4eda19fbb 100644 --- a/src/pc/lua/smlua_cobject.c +++ b/src/pc/lua/smlua_cobject.c @@ -330,6 +330,102 @@ static int smlua__get_field(lua_State* L) { return 1; } +static bool smlua_field_valid(struct LuaObjectField* data, enum LuaObjectType lot, size_t offset) { + size_t minimum = MIN(offset, data->valueOffset); + size_t maximum = MAX(offset + sizeof(void*), data->valueOffset + sizeof(u32)); + size_t length = maximum - minimum; + size_t maxlength = sizeof(void*) + sizeof(u32); + + if (length >= maxlength) { + return (data->lot == lot) && (lot != LOT_NONE); + } + + return (length >= maxlength); +} + +static bool smlua_is_valid_object_field(struct Object* obj, struct LuaObjectField* data) { + enum BehaviorId behaviorId = smlua_get_original_behavior_id(obj->behavior); + switch (behaviorId) { + case id_bhvBowlingBall: + case id_bhvKoopa: + case id_bhvMantaRay: + case id_bhvMips: + case id_bhvPlatformOnTrack: + case id_bhvRacingPenguin: + case id_bhvSnowmansBottom: + case id_bhvUkiki: + case id_bhvUnagi: + if (!smlua_field_valid(data, LOT_WAYPOINT, offsetof(struct Object, oPathedStartWaypoint))) { return false; } + if (!smlua_field_valid(data, LOT_WAYPOINT, offsetof(struct Object, oPathedPrevWaypoint))) { return false; } + break; + case id_bhvHiddenBlueCoin: + if (!smlua_field_valid(data, LOT_OBJECT, offsetof(struct Object, oHiddenBlueCoinSwitch))) { return false; } + break; + case id_bhvBoo: + if (!smlua_field_valid(data, LOT_OBJECT, offsetof(struct Object, oBooParentBigBoo))) { return false; } + break; + case id_bhvLllBowserPuzzlePiece: + if (!smlua_field_valid(data, LOT_NONE, offsetof(struct Object, oBowserPuzzlePieceActionList))) { return false; } + if (!smlua_field_valid(data, LOT_NONE, offsetof(struct Object, oBowserPuzzlePieceNextAction))) { return false; } + break; + case id_bhvChainChomp: + for (int i = 0; i < 4; i++) { + if (!smlua_field_valid(data, LOT_CHAINSEGMENT, offsetof(struct Object, oChainChompSegments) + sizeof(struct ChainSegment *) * i)) { return false; } + } + break; + case id_bhvBowser: + if (!smlua_field_valid(data, LOT_OBJECT, offsetof(struct Object, oFlameBowser))) { return false; } + break; + case id_bhvHauntedChair: + if (!smlua_field_valid(data, LOT_NONE, offsetof(struct Object, oHauntedChairUnk100))) { return false; } + break; + case id_bhvBreakableBox: + case id_bhvHiddenObject: + if (!smlua_field_valid(data, LOT_OBJECT, offsetof(struct Object, oHiddenObjectUnkF4))) { return false; } + break; + case id_bhvBeginningLakitu: + if (!smlua_field_valid(data, LOT_OBJECT, offsetof(struct Object, oIntroLakituCloud))) { return false; } + break; + case id_bhvMontyMole: + if (!smlua_field_valid(data, LOT_OBJECT, offsetof(struct Object, oMontyMoleCurrentHole))) { return false; } + break; + case id_bhvMrBlizzard: + if (!smlua_field_valid(data, LOT_OBJECT, offsetof(struct Object, oMrBlizzardHeldObj))) { return false; } + break; + case id_bhvRespawner: + if (!smlua_field_valid(data, LOT_NONE, offsetof(struct Object, oRespawnerBehaviorToRespawn))) { return false; } + break; + case id_bhvOpenableGrill: + if (!smlua_field_valid(data, LOT_OBJECT, offsetof(struct Object, oOpenableGrillUnkF4))) { return false; } + break; + case id_bhvFallingBowserPlatform: + if (!smlua_field_valid(data, LOT_OBJECT, offsetof(struct Object, oPlatformUnkF8))) { return false; } + break; + case id_bhvJrbSlidingBox: + if (!smlua_field_valid(data, LOT_OBJECT, offsetof(struct Object, oJrbSlidingBoxUnkF4))) { return false; } + break; + case id_bhvToxBox: + if (!smlua_field_valid(data, LOT_NONE, offsetof(struct Object, oToxBoxMovementPattern))) { return false; } + break; + case id_bhvTTCTreadmill: + if (!smlua_field_valid(data, LOT_NONE, offsetof(struct Object, oTTCTreadmillBigSurface))) { return false; } + if (!smlua_field_valid(data, LOT_NONE, offsetof(struct Object, oTTCTreadmillSmallSurface))) { return false; } + break; + case id_bhvStrongWindParticle: + if (!smlua_field_valid(data, LOT_OBJECT, offsetof(struct Object, oStrongWindParticlePenguinObj))) { return false; } + break; + case id_bhvWigglerHead: + for (int i = 0; i < 3; i++) { + if (!smlua_field_valid(data, LOT_CHAINSEGMENT, offsetof(struct Object, oWigglerSegments) + sizeof(struct ChainSegment *) * i)) { return false; } + } + break; + default: + break; + } + + return true; +} + static int smlua__set_field(lua_State* L) { LUA_STACK_CHECK_BEGIN(); if (!smlua_functions_valid_param_count(L, 5)) { return 0; } @@ -365,12 +461,22 @@ static int smlua__set_field(lua_State* L) { if (data == NULL) { data = smlua_get_custom_field(L, lot, 3); } + if (data == NULL) { LOG_LUA("_set_field on invalid key '%s'", key); smlua_logline(); return 0; } + if ((u32)lot == (u32)LOT_OBJECT) { + struct Object* obj = (struct Object*)pointer; + if (!smlua_is_valid_object_field(obj, data)) { + LOG_LUA("_set_field tried to set a custom field that overlapped with a pointer. '%s'", key); + smlua_logline(); + return 0; + } + } + if (data->immutable) { LOG_LUA("_set_field on immutable key '%s'", key); smlua_logline(); diff --git a/src/pc/lua/smlua_hooks.c b/src/pc/lua/smlua_hooks.c index 675cb3a21..481ad519b 100644 --- a/src/pc/lua/smlua_hooks.c +++ b/src/pc/lua/smlua_hooks.c @@ -373,6 +373,17 @@ struct LuaHookedBehavior { static struct LuaHookedBehavior sHookedBehaviors[MAX_HOOKED_BEHAVIORS] = { 0 }; static int sHookedBehaviorsCount = 0; +enum BehaviorId smlua_get_original_behavior_id(const BehaviorScript* behavior) { + enum BehaviorId id = get_id_from_behavior(behavior); + for (int i = 0; i < sHookedBehaviorsCount; i++) { + struct LuaHookedBehavior* hooked = &sHookedBehaviors[i]; + if (hooked->behavior == behavior) { + id = hooked->overrideId; + } + } + return id; +} + const BehaviorScript* smlua_override_behavior(const BehaviorScript* behavior) { lua_State* L = gLuaState; if (L == NULL) { return behavior; } diff --git a/src/pc/lua/smlua_hooks.h b/src/pc/lua/smlua_hooks.h index 577995092..6dfa7d1dd 100644 --- a/src/pc/lua/smlua_hooks.h +++ b/src/pc/lua/smlua_hooks.h @@ -53,6 +53,7 @@ void smlua_call_event_hooks_mario_params_ret_bool(enum LuaHookedEventType hookTy void smlua_call_event_hooks_interact_params(enum LuaHookedEventType hookType, struct MarioState* m, struct Object* obj, u32 interactType, bool interactValue); void smlua_call_event_hooks_object_param(enum LuaHookedEventType hookType, struct Object* obj); +enum BehaviorId smlua_get_original_behavior_id(const BehaviorScript* behavior); const BehaviorScript* smlua_override_behavior(const BehaviorScript* behavior); const BehaviorScript* get_lua_behavior_from_id(enum BehaviorId id, bool returnOriginal); bool smlua_call_behavior_hook(const BehaviorScript** behavior, struct Object* object, bool before);