mirror of https://github.com/pwndbg/pwndbg.git
add mallocng-explain command (#3104)
parent
31dd105e52
commit
15fc059bac
@ -0,0 +1,19 @@
|
||||
<!-- THIS PART OF THIS FILE IS AUTOGENERATED. DO NOT MODIFY IT. See scripts/generate-docs.sh -->
|
||||
# mallocng-explain
|
||||
|
||||
```text
|
||||
usage: mallocng-explain [-h]
|
||||
|
||||
```
|
||||
|
||||
Gives a quick explanation of musl's mallocng allocator.
|
||||
|
||||
**Alias:** ng-explain
|
||||
### Optional arguments
|
||||
|
||||
|Short|Long|Help|
|
||||
| :--- | :--- | :--- |
|
||||
|-h|--help|show this help message and exit|
|
||||
|
||||
<!-- END OF AUTOGENERATED PART. Do not modify this line or the line below, they mark the end of the auto-generated part of the file. If you want to extend the documentation in a way which cannot easily be done by adding to the command help description, write below the following line. -->
|
||||
<!-- ------------\>8---- ----\>8---- ----\>8------------ -->
|
||||
@ -0,0 +1,146 @@
|
||||
"""
|
||||
Commands that help with debugging musl's allocator, mallocng.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import pwndbg
|
||||
import pwndbg.aglib.heap
|
||||
import pwndbg.color as C
|
||||
from pwndbg.commands import CommandCategory
|
||||
|
||||
|
||||
@pwndbg.commands.Command(
|
||||
"Gives a quick explanation of musl's mallocng allocator.",
|
||||
category=CommandCategory.MUSL,
|
||||
aliases=["ng-explain"],
|
||||
)
|
||||
def mallocng_explain() -> None:
|
||||
txt = (
|
||||
C.bold("mallocng")
|
||||
+ ' is a slab allocator. The "unit of allocation" is called a '
|
||||
+ C.bold("slot")
|
||||
+ "\n"
|
||||
)
|
||||
txt += '(the equivalent of glibc\'s "chunk"). Slots are in 0x10 granularity and\n'
|
||||
txt += (
|
||||
"alignment. The slots are organized into objects called " + C.bold('"groups"') + " (the \n"
|
||||
)
|
||||
txt += "slabs). Each group is composed of slots of the same size. If a group is big\n"
|
||||
txt += "it is allocated using mmap, otherwise it is allocated as a slot of a larger\n"
|
||||
txt += "group.\n\n"
|
||||
|
||||
txt += "Each group has some associated metadata. This metadata is stored in a separate\n"
|
||||
txt += "object called " + C.bold('"meta"') + ". Metas are allocated separately from groups in\n"
|
||||
txt += C.bold('"meta areas"') + " to make it harder to reach them during exploitation.\n\n"
|
||||
|
||||
txt += "Here are the definitions of group, meta and meta_area.\n\n"
|
||||
|
||||
txt += C.bold("struct group {\n")
|
||||
txt += " // the metadata of this group\n"
|
||||
txt += C.bold(" struct meta *meta;\n")
|
||||
txt += " unsigned char active_idx:5;\n"
|
||||
txt += " char pad[UNIT - sizeof(struct meta *) - 1];\n"
|
||||
txt += " // start of the slots array\n"
|
||||
txt += C.bold(" unsigned char storage[];\n")
|
||||
txt += C.bold("};\n\n")
|
||||
|
||||
txt += C.bold("struct meta {\n")
|
||||
txt += " // doubly linked list connecting meta's\n"
|
||||
txt += C.bold(" struct meta *prev, *next;\n")
|
||||
txt += " // which group is this metadata for\n"
|
||||
txt += C.bold(" struct group *mem;\n")
|
||||
txt += " // slot bitmap\n"
|
||||
txt += " // avail - slots which have not yet been allocated\n"
|
||||
txt += " // freed - free slots\n"
|
||||
txt += C.bold(" volatile int avail_mask, freed_mask;\n")
|
||||
txt += " uintptr_t last_idx:5;\n"
|
||||
txt += " uintptr_t freeable:1;\n"
|
||||
txt += " // describes the size of the slots\n"
|
||||
txt += C.bold(" uintptr_t sizeclass:6;\n")
|
||||
txt += " // if this group was mmaped, how many pages did we use?\n"
|
||||
txt += " uintptr_t maplen:8*sizeof(uintptr_t)-12;\n"
|
||||
txt += C.bold("};\n\n")
|
||||
|
||||
txt += C.bold("struct meta_area {\n")
|
||||
txt += " uint64_t check;\n"
|
||||
txt += " struct meta_area *next;\n"
|
||||
txt += " int nslots;\n"
|
||||
txt += " // start of the meta array\n"
|
||||
txt += C.bold(" struct meta slots[];\n")
|
||||
txt += C.bold("};\n\n")
|
||||
|
||||
txt += "The allocator state is stored in the global `ctx` variable which is of\n"
|
||||
txt += "type `struct malloc_context`. It is accessible through the __malloc_context\n"
|
||||
txt += "symbol.\n\n"
|
||||
|
||||
txt += C.bold("struct malloc_context {\n")
|
||||
txt += C.bold(" uint64_t secret;\n")
|
||||
txt += "#ifndef PAGESIZE\n"
|
||||
txt += " size_t pagesize;\n"
|
||||
txt += "#endif\n"
|
||||
txt += " int init_done;\n"
|
||||
txt += " unsigned mmap_counter;\n"
|
||||
txt += C.bold(" struct meta *free_meta_head;\n")
|
||||
txt += C.bold(" struct meta *avail_meta;\n")
|
||||
txt += " size_t avail_meta_count, avail_meta_area_count, meta_alloc_shift;\n"
|
||||
txt += C.bold(" struct meta_area *meta_area_head, *meta_area_tail;\n")
|
||||
txt += C.bold(" unsigned char *avail_meta_areas;\n")
|
||||
txt += ' // the "active" group for each sizeclass\n'
|
||||
txt += " // it will be picked for allocation\n"
|
||||
txt += C.bold(" struct meta *active[48];\n")
|
||||
txt += " size_t usage_by_class[48];\n"
|
||||
txt += " uint8_t unmap_seq[32], bounces[32];\n"
|
||||
txt += " uint8_t seq;\n"
|
||||
txt += " uintptr_t brk;\n"
|
||||
txt += C.bold("};\n\n")
|
||||
|
||||
txt += "Here is a diagram of how these components interact.\n\n"
|
||||
|
||||
diag = """+-malloc_context--+
|
||||
| |
|
||||
| free_meta_head |-----------------------> Points to a free meta which is connected
|
||||
| avail_meta |---------------+ to other free meta's via a doubly linked list.
|
||||
| meta_area_head |------------+ |
|
||||
| active[48] |---+ | +-> Points to a not-yet-allocated meta.
|
||||
| | | | When it gets allocated, the next
|
||||
|-----------------+ | 1/48 | meta in the meta_area gets selected
|
||||
| | i.e. avail_meta++ .
|
||||
Each size class has | +-------------------------------------------+
|
||||
an "active" group. +-------+ |
|
||||
v |
|
||||
+-meta--+ +-meta--+ +-meta--+ |
|
||||
| | | | | | |
|
||||
... <---| prev |<------| prev |------>| prev |------> ... |
|
||||
... --->| next |------>| next |<------| next |<------ ... |
|
||||
| mem | +->| mem |-+ | mem | |
|
||||
| | | | | | | | v
|
||||
+-------+ | +-------+ | +-------+ +-meta_area----------------+
|
||||
| | (yes these metas) | |
|
||||
| | (are in some meta_area) | check (ctx.secret) |
|
||||
+---------------------+ | | next |----> ...
|
||||
| v | nslots |
|
||||
| +-group----------------------------------------+ | meta0 |
|
||||
| | | | Meta objects are |
|
||||
+-| meta (8) | active_idx (1) | pad (7) | | meta1 stored here. |
|
||||
| slot0 | | |
|
||||
| | | ... |
|
||||
| | | |
|
||||
| slot1 Slots contain the actual | | meta(nslots-1) |
|
||||
| user data. | | |
|
||||
| | +--------------------------+
|
||||
| slot2 |
|
||||
| |
|
||||
| ... |
|
||||
| |
|
||||
| slot(cnt-1) |
|
||||
| |
|
||||
| |
|
||||
+----------------------------------------------+
|
||||
"""
|
||||
|
||||
txt += diag
|
||||
|
||||
# TODO: explain what a slot looks like.
|
||||
|
||||
print(txt)
|
||||
Loading…
Reference in new issue