Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 22 additions & 6 deletions gef.py
Original file line number Diff line number Diff line change
Expand Up @@ -1588,20 +1588,27 @@ class GlibcArena:
BITSPERMAP = 1 << BINMAPSHIFT
BINMAPSIZE = NBINS // BITSPERMAP

@staticmethod
def has_fastbins() -> bool:
"""Fastbins were removed in glibc 2.43, see
https://sourceware.org/git/?p=glibc.git;a=commit;h=bb5a4f5295ced26532939703867c35f2ce8c149b"""
return not (gef and gef.libc.version and gef.libc.version >= (2, 43))

@staticmethod
def malloc_state_t() -> Type[ctypes.Structure]:
pointer = ctypes.c_uint64 if gef and gef.arch.ptrsize == 8 else ctypes.c_uint32
fields = [
("mutex", ctypes.c_uint32),
("flags", ctypes.c_uint32),
]
if gef and gef.libc.version and gef.libc.version >= (2, 27):
# https://elixir.bootlin.com/glibc/glibc-2.27/source/malloc/malloc.c#L1684
fields += [("have_fastchunks", ctypes.c_uint32)]
if gef.arch.ptrsize == 8:
fields += [("UNUSED_c", ctypes.c_uint32)]
if GlibcArena.has_fastbins():
if gef and gef.libc.version and gef.libc.version >= (2, 27):
# https://elixir.bootlin.com/glibc/glibc-2.27/source/malloc/malloc.c#L1684
fields += [("have_fastchunks", ctypes.c_uint32)]
if gef.arch.ptrsize == 8:
fields += [("UNUSED_c", ctypes.c_uint32)]
fields += [("fastbinsY", GlibcArena.NFASTBINS * pointer)]
fields += [
("fastbinsY", GlibcArena.NFASTBINS * pointer),
("top", pointer),
("last_remainder", pointer),
("bins", (GlibcArena.NBINS * 2 - 2) * pointer),
Expand Down Expand Up @@ -1697,6 +1704,9 @@ def last_remainder(self) -> int:

@property
def fastbinsY(self) -> ctypes.Array:
if not GlibcArena.has_fastbins():
pointer = ctypes.c_uint64 if gef.arch.ptrsize == 8 else ctypes.c_uint32
return (pointer * GlibcArena.NFASTBINS)()
return self.__arena.fastbinsY

@property
Expand Down Expand Up @@ -8067,6 +8077,12 @@ def __init__(self) -> None:
@parse_arguments({"arena_address": ""}, {})
@only_if_gdb_running
def do_invoke(self, *_: Any, **kwargs: Any) -> None:
if not GlibcArena.has_fastbins():
err(
"Fastbins were removed in glibc 2.43, this command is not supported here"
)
return

def fastbin_index(sz: int) -> int:
return (sz >> 4) - 2 if SIZE_SZ == 8 else (sz >> 3) - 2

Expand Down
6 changes: 6 additions & 0 deletions tests/commands/canary.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@
`canary` command test module
"""

import pytest
from tests.utils import (
ERROR_INACTIVE_SESSION_MESSAGE,
debug_target,
p64,
p32,
is_64b,
is_glibc_ge,
u32,
)
from tests.base import RemoteGefUnitTestGeneric
Expand All @@ -20,6 +22,10 @@ def setUp(self) -> None:
self._target = debug_target("canary")
return super().setUp()

@pytest.mark.skipif(
is_glibc_ge(2, 44),
reason="Skipped for glibc >= 2.44 (canary is no longer derived from AT_RANDOM)",
)
def test_cmd_canary(self):
assert ERROR_INACTIVE_SESSION_MESSAGE == self._gdb.execute(
"canary", to_string=True
Expand Down
34 changes: 34 additions & 0 deletions tests/commands/heap.py
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ def setUp(self) -> None:
self._target = debug_target("heap-fastbins")
return super().setUp()

@pytest.mark.skipif(is_glibc_ge(2, 43), reason="Skipped for glibc >= 2.43")
def test_cmd_heap_bins_fast(self):
gdb = self._gdb
cmd = "heap bins fast"
Expand All @@ -267,6 +268,39 @@ def test_cmd_heap_bins_fast(self):
self.assertIn("Chunk(addr=", res)


class HeapCommandNoFastbins(RemoteGefUnitTestGeneric):
"""Fastbin commands when running on glibc >= 2.43, where fastbins were
removed from the malloc implementation (see
https://github.com/hugsy/gef/issues/1225)."""

def setUp(self) -> None:
self._target = debug_target("heap")
super().setUp()
self._gdb.execute("python gef.libc._version = (2, 43)")

def test_cmd_heap_bins_fast_not_supported(self):
gdb = self._gdb
gdb.execute("run")
res = gdb.execute("heap bins fast", to_string=True)
self.assertIn("not supported", res.lower())

def test_arena_layout_has_no_fastbins(self):
gdb = self._gdb
gdb.execute("run")
gdb.execute("heap set-arena &main_arena")
res = gdb.execute(
"python print([f[0] for f in type(gef.heap.main_arena).malloc_state_t()._fields_])",
to_string=True,
)
self.assertNotIn("fastbinsY", res)
self.assertNotIn("have_fastchunks", res)
res = gdb.execute(
"python print(gef.heap.main_arena.fastbin(0) is None, len(gef.heap.main_arena.fastbinsY))",
to_string=True,
)
self.assertIn("True 10", res)


class HeapCommandBins(RemoteGefUnitTestGeneric):
def setUp(self) -> None:
self._target = debug_target("heap-bins")
Expand Down
Loading