Change SkillResult size validation

Since leech uses trailing structs of two different sizes, just use the max SkillResult size in validation/zeroing and then check for overflow in a couple extra places
This commit is contained in:
gsemaj 2023-07-23 10:31:40 -04:00 committed by gsemaj
parent 03abb6f830
commit 4bc53b2e7e
2 changed files with 8 additions and 13 deletions

View File

@ -147,26 +147,22 @@ static SkillResult handleSkillResurrect(SkillData* skill, int power, ICombatant*
#pragma endregion #pragma endregion
static std::vector<SkillResult> handleSkill(SkillData* skill, int power, ICombatant* src, std::vector<ICombatant*> targets) { static std::vector<SkillResult> handleSkill(SkillData* skill, int power, ICombatant* src, std::vector<ICombatant*> targets) {
size_t resultSize = 0;
SkillResult (*skillHandler)(SkillData*, int, ICombatant*, ICombatant*) = nullptr; SkillResult (*skillHandler)(SkillData*, int, ICombatant*, ICombatant*) = nullptr;
std::vector<SkillResult> results; std::vector<SkillResult> results;
switch(skill->skillType) switch(skill->skillType)
{ {
case SkillType::DAMAGE: case SkillType::DAMAGE:
resultSize = sizeof(sSkillResult_Damage);
skillHandler = handleSkillDamage; skillHandler = handleSkillDamage;
break; break;
case SkillType::HEAL_HP: case SkillType::HEAL_HP:
case SkillType::RETURNHOMEHEAL: case SkillType::RETURNHOMEHEAL:
resultSize = sizeof(sSkillResult_Heal_HP);
skillHandler = handleSkillHealHP; skillHandler = handleSkillHealHP;
break; break;
case SkillType::KNOCKDOWN: case SkillType::KNOCKDOWN:
case SkillType::SLEEP: case SkillType::SLEEP:
case SkillType::SNARE: case SkillType::SNARE:
case SkillType::STUN: case SkillType::STUN:
resultSize = sizeof(sSkillResult_Damage_N_Debuff);
skillHandler = handleSkillDamageNDebuff; skillHandler = handleSkillDamageNDebuff;
break; break;
case SkillType::JUMP: case SkillType::JUMP:
@ -186,26 +182,21 @@ static std::vector<SkillResult> handleSkill(SkillData* skill, int power, ICombat
case SkillType::STAMINA_SELF: case SkillType::STAMINA_SELF:
case SkillType::NANOSTIMPAK: case SkillType::NANOSTIMPAK:
case SkillType::BUFFHEAL: case SkillType::BUFFHEAL:
resultSize = sizeof(sSkillResult_Buff);
skillHandler = handleSkillBuff; skillHandler = handleSkillBuff;
break; break;
case SkillType::BLOODSUCKING: case SkillType::BLOODSUCKING:
resultSize = sizeof(sSkillResult_Heal_HP);
skillHandler = handleSkillLeech; skillHandler = handleSkillLeech;
case SkillType::RETROROCKET_SELF: case SkillType::RETROROCKET_SELF:
// no-op // no-op
return results; return results;
case SkillType::PHOENIX_GROUP: case SkillType::PHOENIX_GROUP:
resultSize = sizeof(sSkillResult_Resurrect);
skillHandler = handleSkillResurrect; skillHandler = handleSkillResurrect;
break; break;
case SkillType::RECALL: case SkillType::RECALL:
case SkillType::RECALL_GROUP: case SkillType::RECALL_GROUP:
resultSize = sizeof(sSkillResult_Move);
skillHandler = handleSkillMove; skillHandler = handleSkillMove;
break; break;
case SkillType::BATTERYDRAIN: case SkillType::BATTERYDRAIN:
resultSize = sizeof(sSkillResult_BatteryDrain);
skillHandler = handleSkillBatteryDrain; skillHandler = handleSkillBatteryDrain;
break; break;
default: default:
@ -217,7 +208,7 @@ static std::vector<SkillResult> handleSkill(SkillData* skill, int power, ICombat
assert(target != nullptr); assert(target != nullptr);
SkillResult result = skillHandler(skill, power, src != nullptr ? src : target, target); SkillResult result = skillHandler(skill, power, src != nullptr ? src : target, target);
if(result.size == 0) continue; // skill not applicable if(result.size == 0) continue; // skill not applicable
if(result.size != resultSize) { if(result.size > MAX_SKILLRESULT_SIZE) {
std::cout << "[WARN] bad skill result size for " << (int)skill->skillType << " from " << (void*)handleSkillBuff << std::endl; std::cout << "[WARN] bad skill result size for " << (int)skill->skillType << " from " << (void*)handleSkillBuff << std::endl;
continue; continue;
} }
@ -250,7 +241,7 @@ void Abilities::useNanoSkill(CNSocket* sock, SkillData* skill, sNano& nano, std:
std::vector<SkillResult> results = handleSkill(skill, boost, plr, affected); std::vector<SkillResult> results = handleSkill(skill, boost, plr, affected);
if(results.empty()) return; // no effect; no need for confirmation packets if(results.empty()) return; // no effect; no need for confirmation packets
size_t resultSize = results.back().size; // guaranteed to be the same for every item size_t resultSize = MAX_SKILLRESULT_SIZE; // lazy
if (!validOutVarPacket(sizeof(sP_FE2CL_NANO_SKILL_USE_SUCC), results.size(), resultSize)) { if (!validOutVarPacket(sizeof(sP_FE2CL_NANO_SKILL_USE_SUCC), results.size(), resultSize)) {
std::cout << "[WARN] bad sP_FE2CL_NANO_SKILL_USE_SUCC packet size\n"; std::cout << "[WARN] bad sP_FE2CL_NANO_SKILL_USE_SUCC packet size\n";
return; return;

View File

@ -75,8 +75,12 @@ struct SkillResult {
size_t size; size_t size;
uint8_t payload[MAX_SKILLRESULT_SIZE]; uint8_t payload[MAX_SKILLRESULT_SIZE];
SkillResult(size_t len, void* dat) { SkillResult(size_t len, void* dat) {
if(len <= MAX_SKILLRESULT_SIZE) {
size = len; size = len;
memcpy(payload, dat, len); memcpy(payload, dat, len);
} else {
size = 0;
}
} }
SkillResult() { SkillResult() {
size = 0; size = 0;