|
|
|
|
@ -1,5 +1,8 @@
|
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
import random
|
|
|
|
|
import re
|
|
|
|
|
|
|
|
|
|
import gdb
|
|
|
|
|
import pytest
|
|
|
|
|
|
|
|
|
|
@ -90,8 +93,6 @@ def test_x64_extra_registers_under_kernel_mode():
|
|
|
|
|
def get_slab_object_address():
|
|
|
|
|
"""helper function to get the address of some kmalloc slab object
|
|
|
|
|
and the associated slab cache name"""
|
|
|
|
|
import re
|
|
|
|
|
|
|
|
|
|
caches = pwndbg.aglib.kernel.slab.caches()
|
|
|
|
|
for cache in caches:
|
|
|
|
|
cache_name = cache.name
|
|
|
|
|
@ -135,6 +136,42 @@ def test_command_msr_write():
|
|
|
|
|
)
|
|
|
|
|
def test_command_buddydump():
|
|
|
|
|
res = gdb.execute("buddydump", to_string=True)
|
|
|
|
|
assert (
|
|
|
|
|
"Order" in res and "Zone" in res and ("per_cpu_pageset" in res or "free_area" in res)
|
|
|
|
|
) or res == "WARNING: Symbol 'node_data' not found\n"
|
|
|
|
|
NOFREEPAGE = "No free pages with specified filters found.\n"
|
|
|
|
|
if res == "WARNING: Symbol 'node_data' not found\n" or NOFREEPAGE == res:
|
|
|
|
|
return
|
|
|
|
|
# this indicates the buddy allocator contains at least one entry
|
|
|
|
|
assert "Order" in res and "Zone" in res and ("per_cpu_pageset" in res or "free_area" in res)
|
|
|
|
|
|
|
|
|
|
ansi_escape = re.compile(r"\x1b\[[0-9;]*m")
|
|
|
|
|
res = ansi_escape.sub("", res)
|
|
|
|
|
# find the starting addresses of all entries within the freelists
|
|
|
|
|
matches = re.findall(r"\[0x[0-9a-fA-F\-]{2}\] (0x[0-9a-fA-F]{16})", res)
|
|
|
|
|
for i in range(0, len(matches), 20):
|
|
|
|
|
# check every 20 elements so tests do not take too long
|
|
|
|
|
match = int(matches[i], 16)
|
|
|
|
|
res = gdb.execute(f"bud -f {hex(match + random.randint(0, 0x1000 - 1))}", to_string=True)
|
|
|
|
|
res = ansi_escape.sub("", res)
|
|
|
|
|
_matches = re.findall(r"\[0x[0-9a-fA-F\-]{2}\] (0x[0-9a-fA-F]{16})", res)
|
|
|
|
|
# asserting `bud -f` behaviour -- should be able to find the corresponding entry to an address
|
|
|
|
|
# even if the address is not aligned
|
|
|
|
|
assert len(_matches) == 1 and int(_matches[0], 16) == match
|
|
|
|
|
|
|
|
|
|
# nonexistent node index should not contain any entries
|
|
|
|
|
no_output = gdb.execute("buddydump -n 10", to_string=True)
|
|
|
|
|
assert NOFREEPAGE == no_output
|
|
|
|
|
|
|
|
|
|
# below checks are for filters
|
|
|
|
|
# for example, if a zone name is specified, other zones should not be present
|
|
|
|
|
filter_res = gdb.execute("bud -z DMA", to_string=True)
|
|
|
|
|
for name in ["DMA32", "Normal", "HighMem", "Movable", "Device"]:
|
|
|
|
|
assert f"Zone {name}" not in filter_res
|
|
|
|
|
filter_res = gdb.execute("bud -m Unmovable", to_string=True)
|
|
|
|
|
for name in ["Movable", "Reclaimable", "HighAtomic", "CMA", "Isolate"]:
|
|
|
|
|
assert f"- {name}" not in filter_res
|
|
|
|
|
filter_res = gdb.execute("bud -o 1", to_string=True)
|
|
|
|
|
for i in range(11):
|
|
|
|
|
if i == 1:
|
|
|
|
|
continue
|
|
|
|
|
assert f"Order {i}" not in filter_res
|
|
|
|
|
filter_res = gdb.execute("bud -p", to_string=True)
|
|
|
|
|
assert "free_area" not in filter_res
|
|
|
|
|
|