|
|
|
|
@ -2,6 +2,7 @@ from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
import copy
|
|
|
|
|
import importlib
|
|
|
|
|
import os
|
|
|
|
|
import sys
|
|
|
|
|
import types
|
|
|
|
|
from collections import OrderedDict
|
|
|
|
|
@ -1104,6 +1105,18 @@ class GlibcMemoryAllocator(pwndbg.aglib.heap.heap.MemoryAllocator, Generic[TheTy
|
|
|
|
|
def tcache_entry(self) -> TheType | None:
|
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
@pwndbg.lib.cache.cache_until("objfile")
|
|
|
|
|
def tcache_small_bins(self) -> int | None:
|
|
|
|
|
if not self.has_tcache():
|
|
|
|
|
return None
|
|
|
|
|
mp = self.mp
|
|
|
|
|
if "tcache_small_bins" in mp.type.keys():
|
|
|
|
|
return int(mp["tcache_small_bins"])
|
|
|
|
|
elif "tcache_bins" in mp.type.keys():
|
|
|
|
|
return int(mp["tcache_bins"])
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def mallinfo(self) -> TheType | None:
|
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
@ -1156,7 +1169,10 @@ class GlibcMemoryAllocator(pwndbg.aglib.heap.heap.MemoryAllocator, Generic[TheTy
|
|
|
|
|
"""Is malloc operating within a multithreaded environment."""
|
|
|
|
|
addr = pwndbg.aglib.symbol.lookup_symbol_addr("__libc_multiple_threads")
|
|
|
|
|
if addr:
|
|
|
|
|
return pwndbg.aglib.memory.s32(addr) > 0
|
|
|
|
|
return pwndbg.aglib.memory.u32(addr) > 0
|
|
|
|
|
# glibc 2.42 replaced __libc_multiple_threads with __libc_single_threaded
|
|
|
|
|
elif addr := pwndbg.aglib.symbol.lookup_symbol_addr("__libc_single_threaded"):
|
|
|
|
|
return pwndbg.aglib.memory.u32(addr) == 0
|
|
|
|
|
return len(pwndbg.dbg.selected_inferior().threads()) > 1
|
|
|
|
|
|
|
|
|
|
def _request2size(self, req: int) -> int:
|
|
|
|
|
@ -1252,8 +1268,11 @@ class GlibcMemoryAllocator(pwndbg.aglib.heap.heap.MemoryAllocator, Generic[TheTy
|
|
|
|
|
if tcache is None:
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
if pwndbg.glibc.get_version() >= (2, 42) and not hasattr(
|
|
|
|
|
GlibcMemoryAllocator.tcachebins, "tcache_2_42_warning_issued"
|
|
|
|
|
# this will break expected output during tests, so we skip it
|
|
|
|
|
if (
|
|
|
|
|
pwndbg.glibc.get_version() >= (2, 42)
|
|
|
|
|
and not not hasattr(GlibcMemoryAllocator.tcachebins, "tcache_2_42_warning_issued")
|
|
|
|
|
and os.environ.get("PWNDBG_IN_TEST") is None
|
|
|
|
|
):
|
|
|
|
|
print(
|
|
|
|
|
message.warn(
|
|
|
|
|
@ -1263,6 +1282,10 @@ class GlibcMemoryAllocator(pwndbg.aglib.heap.heap.MemoryAllocator, Generic[TheTy
|
|
|
|
|
)
|
|
|
|
|
setattr(GlibcMemoryAllocator.tcachebins, "tcache_2_42_warning_issued", True)
|
|
|
|
|
|
|
|
|
|
# counts was renamed to num_slots in newer version of GLIBC 2.42
|
|
|
|
|
try:
|
|
|
|
|
counts = tcache["num_slots"]
|
|
|
|
|
except Exception:
|
|
|
|
|
counts = tcache["counts"]
|
|
|
|
|
entries = tcache["entries"]
|
|
|
|
|
|
|
|
|
|
@ -1278,7 +1301,7 @@ class GlibcMemoryAllocator(pwndbg.aglib.heap.heap.MemoryAllocator, Generic[TheTy
|
|
|
|
|
size = self._request2size(tidx2usize(i))
|
|
|
|
|
count = int(counts[i])
|
|
|
|
|
if pwndbg.glibc.get_version() >= (2, 42):
|
|
|
|
|
count = pwndbg.aglib.heap.structs.TCACHE_FILL_COUNT - count
|
|
|
|
|
count = int(self.mp["tcache_count"]) - count
|
|
|
|
|
chain = pwndbg.chain.get(
|
|
|
|
|
int(entries[i]),
|
|
|
|
|
offset=self.tcache_next_offset,
|
|
|
|
|
@ -1576,7 +1599,10 @@ class DebugSymsHeap(GlibcMemoryAllocator[pwndbg.dbg_mod.Type, pwndbg.dbg_mod.Val
|
|
|
|
|
return self._main_arena
|
|
|
|
|
|
|
|
|
|
def has_tcache(self) -> bool:
|
|
|
|
|
return self.mp is not None and "tcache_bins" in self.mp.type.keys()
|
|
|
|
|
# tcache_bins was renamed to tcache_small_bins in GLIBC 2.42
|
|
|
|
|
return self.mp is not None and any(
|
|
|
|
|
x in self.mp.type.keys() for x in ["tcache_bins", "tcache_small_bins"]
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def thread_arena(self) -> Arena | None:
|
|
|
|
|
@ -1598,17 +1624,24 @@ class DebugSymsHeap(GlibcMemoryAllocator[pwndbg.dbg_mod.Type, pwndbg.dbg_mod.Val
|
|
|
|
|
"""Locate a thread's tcache struct. If it doesn't have one, use the main
|
|
|
|
|
thread's tcache.
|
|
|
|
|
"""
|
|
|
|
|
if self.has_tcache():
|
|
|
|
|
if self.multithreaded:
|
|
|
|
|
tcache_addr = pwndbg.aglib.memory.read_pointer_width(
|
|
|
|
|
pwndbg.aglib.symbol.lookup_symbol_addr("tcache", prefer_static=True)
|
|
|
|
|
)
|
|
|
|
|
if tcache_addr == 0:
|
|
|
|
|
# This thread doesn't have a tcache yet
|
|
|
|
|
if not self.has_tcache():
|
|
|
|
|
print(message.warn("This version of GLIBC was not compiled with tcache support."))
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
tcache_ptr = pwndbg.aglib.symbol.lookup_symbol_addr(
|
|
|
|
|
"tcache",
|
|
|
|
|
prefer_static=True,
|
|
|
|
|
)
|
|
|
|
|
if not tcache_ptr:
|
|
|
|
|
tcache_ptr = pwndbg.aglib.symbol.lookup_symbol_addr("tcache", prefer_static=True)
|
|
|
|
|
|
|
|
|
|
if tcache_ptr and (tcache_addr := pwndbg.aglib.memory.read_pointer_width(tcache_ptr)):
|
|
|
|
|
tcache = tcache_addr
|
|
|
|
|
else:
|
|
|
|
|
elif not self.multithreaded:
|
|
|
|
|
tcache = self.main_arena.heaps[0].start + pwndbg.aglib.arch.ptrsize * 2
|
|
|
|
|
else:
|
|
|
|
|
# This thread doesn't have a tcache yet
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
self._thread_cache = pwndbg.aglib.memory.get_typed_pointer_value(
|
|
|
|
|
@ -1618,7 +1651,7 @@ class DebugSymsHeap(GlibcMemoryAllocator[pwndbg.dbg_mod.Type, pwndbg.dbg_mod.Val
|
|
|
|
|
except Exception:
|
|
|
|
|
print(
|
|
|
|
|
message.error(
|
|
|
|
|
"Error fetching tcache. GDB cannot access "
|
|
|
|
|
"Error fetching tcache. Cannot access "
|
|
|
|
|
"thread-local variables unless you compile with -lpthread."
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
@ -1626,9 +1659,6 @@ class DebugSymsHeap(GlibcMemoryAllocator[pwndbg.dbg_mod.Type, pwndbg.dbg_mod.Val
|
|
|
|
|
|
|
|
|
|
return self._thread_cache
|
|
|
|
|
|
|
|
|
|
print(message.warn("This version of GLIBC was not compiled with tcache support."))
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def mp(self) -> pwndbg.dbg_mod.Value | None:
|
|
|
|
|
self._mp_addr = pwndbg.aglib.symbol.lookup_symbol_addr("mp_", prefer_static=True)
|
|
|
|
|
@ -1721,7 +1751,9 @@ class DebugSymsHeap(GlibcMemoryAllocator[pwndbg.dbg_mod.Type, pwndbg.dbg_mod.Val
|
|
|
|
|
addr = pwndbg.aglib.symbol.lookup_symbol_addr("__libc_malloc_initialized")
|
|
|
|
|
if addr is None:
|
|
|
|
|
addr = pwndbg.aglib.symbol.lookup_symbol_addr("__malloc_initialized")
|
|
|
|
|
assert addr is not None, "Could not find __libc_malloc_initialized or __malloc_initialized"
|
|
|
|
|
# fallback for GLIBC 2.42 as __malloc_initialized was removed
|
|
|
|
|
if addr is None:
|
|
|
|
|
return int(self.mp["sbrk_base"]) != 0
|
|
|
|
|
return pwndbg.aglib.memory.s32(addr) > 0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|