From 4c1f2ffa48a74ce9cd0547e9d34c96a9e3549375 Mon Sep 17 00:00:00 2001 From: Patric Mueller Date: Sat, 17 Jul 2021 12:44:50 +0200 Subject: [PATCH] Fix heap-use-after-free when attacking monster with potion Attacking a monster which has a passive attack (e.g. a red mold) with a wielded potion that breaks during the attack, the variable weapon would not be correctly reset and passive() would be called with the pointer to the freed object. --- doc/fixes37.0 | 1 + src/uhitm.c | 14 ++++++++------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/doc/fixes37.0 b/doc/fixes37.0 index 8d32e02ec..9a2b103ec 100644 --- a/doc/fixes37.0 +++ b/doc/fixes37.0 @@ -568,6 +568,7 @@ deal with gold leaving a shop via scatter() defer encumbrance check during polymorph to new man; newman() -> redist_attr() -> encumber_msg() could report change in encumbrance that immediately became obsolete if polyman() subsequently restored old attributes +fix heap-use-after-free when attacking monster with potion Fixes to 3.7.0-x Problems that Were Exposed Via git Repository diff --git a/src/uhitm.c b/src/uhitm.c index a0269477e..36f0c2109 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -4441,6 +4441,7 @@ hmonas(struct monst *mon) int i, tmp, armorpenalty, sum[NATTK], nsum = MM_MISS, dhit = 0, attknum = 0; int dieroll, multi_claw = 0; + boolean monster_survived; /* not used here but umpteen mhitm_ad_xxxx() need this */ g.vis = (canseemon(mon) || distu(mon->mx, mon->my) <= 2); @@ -4521,17 +4522,18 @@ hmonas(struct monst *mon) dieroll = rnd(20); dhit = (tmp > dieroll || u.uswallow); /* caller must set g.bhitpos */ - if (!known_hitum(mon, weapon, &dhit, tmp, - armorpenalty, mattk, dieroll)) { + monster_survived = known_hitum(mon, weapon, &dhit, tmp, + armorpenalty, mattk, dieroll); + /* originalweapon points to an equipment slot which might + now be empty if the weapon was destroyed during the hit; + passive(,weapon,...) won't call passive_obj() in that case */ + weapon = *originalweapon; /* might receive passive erosion */ + if (!monster_survived) { /* enemy dead, before any special abilities used */ sum[i] = MM_DEF_DIED; break; } else sum[i] = dhit ? MM_HIT : MM_MISS; - /* originalweapon points to an equipment slot which might - now be empty if the weapon was destroyed during the hit; - passive(,weapon,...) won't call passive_obj() in that case */ - weapon = *originalweapon; /* might receive passive erosion */ /* might be a worm that gets cut in half; if so, early return */ if (m_at(u.ux + u.dx, u.uy + u.dy) != mon) { i = NATTK; /* skip additional attacks */