feat(memhub): detection 增强 - free 后用户区填 0xCD + 记录保留并置 free 标志,探测时对仍 free 的块验证 0xCD 完整(首末 8 字节),被写穿即 [DET] UAF 写入 报警终止 - 拦截 use-after-free 写入(如 SlotsBugTest KwEntry cargs 块 free 后被部分覆盖),与后标记越界写检测互补;块被重新 alloc 后块头变奇数自动跳过旧 free 记录防误报

This commit is contained in:
TermiNexus committed 2026-08-25 15:02:14 +08:00
1 parent 0efd438bfb
commit 91120ae00a
1 file changed
+30 -5
+30 -5
View File
@@ -729,13 +729,18 @@ class MemBuddy(MemManager):
if self.detection != 0:
# [DET] 返回指针比实际用户区靠后 2 字节,回收时向前偏移 2
p_eff = t.CVoid(t.CUInt64T(ptr) - 2, t.CPtr)
# 从记录表移除该条(置 size=0):块复用后旧后标记位置
# 会被新数据覆盖,若不移除会导致 _det_probe 误报
# 从记录表取本条真实 size,free 后把用户区填 0xCD(UAF 写入
# 检测:free 后块被写穿 → 探测时 0xCD 被破坏 → 报警);记录
# 保留并置 free 标志(探测时对仍 free 的块验证 0xCD 完整)。
if self._det_records is not None:
ri: t.CSizeT = 0
while ri < self._det_count:
if self._det_records[ri * 2] == t.CUInt64T(ptr):
self._det_records[ri * 2 + 1] = 0
rp: t.CUInt64T = self._det_records[ri * 2]
rs: t.CUInt64T = self._det_records[ri * 2 + 1]
if rp == t.CUInt64T(ptr) and (rs & (t.CUInt64T(1) << 63)) == 0:
if rs > 0:
string.memset(ptr, MEMBUDDY_FILL_PATTERN, rs)
self._det_records[ri * 2 + 1] = rs | (t.CUInt64T(1) << 63)
break
ri += 1
if self._is_valid_ptr(p_eff) != 0:
@@ -821,13 +826,33 @@ class MemBuddy(MemManager):
def _det_probe(self):
if self._det_records is None:
return
free_flag: t.CUInt64T = t.CUInt64T(1) << 63
cd_word: t.CUInt64T = (t.CUInt64T(0xCDCDCDCD) << 32) | t.CUInt64T(0xCDCDCDCD)
i: t.CSizeT = 0
while i < self._det_count:
p: t.CUInt64T = self._det_records[i * 2]
s: t.CUInt64T = self._det_records[i * 2 + 1]
if (s & free_flag) != 0:
# free 记录:块头仍为 0(未被重新 alloc)则验证用户区 0xCD
# 完整——被写穿 = use-after-free 写入(free 后块被某代码覆盖)
real_s: t.CUInt64T = s & (free_flag - 1)
if real_s > 0:
blk_h: t.CUInt64T = p - 2 - MEMBUDDY_HEADER_SIZE
hdr_v: t.CUInt64T = t.CUInt64T(c.Deref(t.CUInt64T(blk_h, t.CPtr)))
if (hdr_v & 1) == 0:
w0: t.CUInt64T = t.CUInt64T(c.Deref(t.CUInt64T(p, t.CPtr)))
w1: t.CUInt64T = w0
if real_s >= 8:
w1 = t.CUInt64T(c.Deref(t.CUInt64T(p + real_s - 8, t.CPtr)))
if w0 != cd_word or w1 != cd_word:
stdio.printf("[DET] UAF 写入: ptr=%llu size=%llu(free 后块被写,首=0x%llX 末=0x%llX)\n",
p, real_s, w0, w1)
stdlib.exit(1)
i += 1
continue
if s == 0:
i += 1
continue # 该条已被 free(记录移除)
continue # 无 size 记录(理论不发生,防御)
m16: t.CUInt16T | t.CPtr = (t.CUInt16T | t.CPtr)(t.CVoid(p + s, t.CPtr))
mv: t.CUInt16T = m16[0]
if mv != t.CUInt16T(MEMBUDDY_DET_MARKER):