mallocng ¤
Implements handling of musl's allocator mallocng. https://elixir.bootlin.com/musl/v1.2.5/source/src/malloc/mallocng
Classes:
-
Group
–A group is an array of slots.
-
Slot
–The "unit of allocation" (analogous to glibc's "chunk").
-
Meta
–The metadata of a group.
-
MetaArea
–Slabs that contain metas, linked in a singly-linked list.
-
MallocContext
–The global object that holds all allocator state.
-
Mallocng
–Tracks the allocator state.
Functions:
-
int_size
–
Attributes:
-
UNIT
– -
IB
– -
size_classes
(list[int]
) – -
mallocng
–
size_classes module-attribute
¤
size_classes: list[int] = [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
12,
15,
18,
20,
25,
31,
36,
42,
50,
63,
72,
84,
102,
127,
146,
170,
204,
255,
292,
340,
409,
511,
584,
682,
818,
1023,
1169,
1364,
1637,
2047,
2340,
2730,
3276,
4095,
4680,
5460,
6552,
8191,
]
Group ¤
A group is an array of slots.
https://elixir.bootlin.com/musl/v1.2.5/source/src/malloc/mallocng/meta.h#L17 struct group { struct meta *meta; unsigned char active_idx:5; char pad[UNIT - sizeof(struct meta *) - 1]; unsigned char storage[]; };
Methods:
-
preload
–Read all the necessary process memory to populate the group's
-
set_meta
–Sets the meta object for this group.
-
at_index
–Get the address of the slot at index idx.
Attributes:
-
addr
– -
meta
(Meta
) –Raises:
-
active_idx
(int
) –Raises:
-
storage
(int
) – -
group_size
(int
) –The size of this group, in bytes.
group_size property
¤
preload ¤
Read all the necessary process memory to populate the group's fields.
Do this if you know you will be using most of the fields of the group. It will be faster, since we can do one reads instead of two small ones. You may also catch inaccessible memory exceptions here and not worry about it later.
Raises:
-
Error
–When reading memory fails.
Slot ¤
The "unit of allocation" (analogous to glibc's "chunk"). There is no struct in the source code that describes it.
Methods:
-
preload
–Read all the necessary process memory to populate the slot's
-
preload_meta_dependants
–Preloads all fields that depend on a sane meta.
-
is_cyclic
–Returns whether mallocng reports that p != start.
-
contains_group
–Does this slot nest a group?
-
from_p
– -
from_start
–
Attributes:
-
p
(int
) – -
offset
(int
) –Raises:
-
pn3
(int
) –Raises:
-
idx
(int
) –Raises:
-
reserved_in_header
(int
) – -
big_offset_check
(int
) –Raises:
-
start
(int
) –Raises:
-
cyclic_offset
(int
) –Returns zero if is_cyclic() is False.
-
startn3
(int
) –Raises:
-
reserved_in_footer
(int
) –Returns -1 if the value is invalid, i.e.
-
end
(int
) –Raises:
-
reserved
(int
) –Returns 0 if reserved_in_header() == 6.
-
nominal_size
(int
) –Raises:
-
user_size
(int
) –Raises:
-
slack
(int
) –Raises:
-
group
(Group
) – -
meta
(Meta
) –Raises:
cyclic_offset property
¤
reserved_in_footer property
¤
Returns -1 if the value is invalid, i.e. reserved_in_header() != 5.
Raises:
-
Error
–When reading memory fails.
reserved property
¤
Returns 0 if reserved_in_header() == 6. Returns -1 if reserved_in_header() == 7.
Raises:
-
Error
–When reading memory fails.
preload ¤
Read all the necessary process memory to populate the slot's p header fields.
Do this if you know you will be using most of the fields of the slot. It will be faster, since we can do a few big reads instead of many small ones. You may also catch inaccessible memory exceptions here and not worry about it later.
Fields dependant on the meta are not loaded - you will still need to worry about exceptions coming from them.
Raises:
-
Error
–When reading memory fails.
preload_meta_dependants ¤
Preloads all fields that depend on a sane meta.
It generally only makes sense to run this after preload(). Calling this reduces the amount of process writes and centralizes field exceptions to this function.
If both preload() and preload_meta_dependants() return without exceptions, all the fields in this class are guaranteed to not cause any more memory reads nor raise any more exceptions.
Raises:
-
Error
–When the meta is corrupt and/or reading memory fails.
Meta ¤
The metadata of a group.
https://elixir.bootlin.com/musl/v1.2.5/source/src/malloc/mallocng/meta.h#L24 struct meta { struct meta *prev, *next; struct group *mem; volatile int avail_mask, freed_mask; uintptr_t last_idx:5; uintptr_t freeable:1; uintptr_t sizeclass:6; uintptr_t maplen:8*sizeof(uintptr_t)-12; };
Methods:
Attributes:
-
addr
(int
) – -
prev
(int
) –Raises:
-
next
(int
) –Raises:
-
mem
(int
) –Raises:
-
avail_mask
(int
) –Raises:
-
freed_mask
(int
) –Raises:
-
last_idx
(int
) –Raises:
-
freeable
(int
) –Raises:
-
sizeclass
(int
) –Raises:
-
maplen
(int
) –Raises:
-
stride
–Returns -1 if sizeclass >= len(size_classes).
-
cnt
–Number of slots in the group.
-
is_donated
(bool
) –Returns whether the group object referred to by this meta has been
-
is_mmaped
(bool
) –Returns whether the group object referred to by this meta has been
-
is_nested
(bool
) –Returns whether the group object referred to by this meta has been
is_donated property
¤
Returns whether the group object referred to by this meta has been created by being donated by ld.
is_mmaped property
¤
Returns whether the group object referred to by this meta has been created by being mmaped.
is_nested property
¤
Returns whether the group object referred to by this meta has been created by being nested into a slot.
preload ¤
Read all the necessary process memory to populate the meta's fields.
Do this if you know you will be using most of the fields of the meta. It will be faster, since we can do a one big read instead of many small ones. You may also catch inaccessible memory exceptions here and not worry about it later.
Raises:
-
Error
–When reading memory fails.
MetaArea ¤
Slabs that contain metas, linked in a singly-linked list.
https://elixir.bootlin.com/musl/v1.2.5/source/src/malloc/mallocng/meta.h#L34 struct meta_area { uint64_t check; struct meta_area *next; int nslots; struct meta slots[]; };
Methods:
Attributes:
MallocContext ¤
The global object that holds all allocator state.
https://elixir.bootlin.com/musl/v1.2.5/source/src/malloc/mallocng/meta.h#L41 struct malloc_context { uint64_t secret;
ifndef PAGESIZE¤
size_t pagesize;
endif¤
int init_done; unsigned mmap_counter; struct meta *free_meta_head; struct meta *avail_meta; size_t avail_meta_count, avail_meta_area_count, meta_alloc_shift; struct meta_area *meta_area_head, *meta_area_tail; unsigned char *avail_meta_areas; struct meta *active[48]; size_t usage_by_class[48]; uint8_t unmap_seq[32], bounces[32]; uint8_t seq; uintptr_t brk; };
Methods:
-
load
–
Attributes:
-
addr
(int
) – -
secret
(int
) – -
pagesize
(int
) – -
init_done
(int
) – -
mmap_counter
(int
) – -
free_meta_head
(int
) – -
avail_meta
(int
) – -
avail_meta_count
(int
) – -
avail_meta_area_count
(int
) – -
meta_alloc_shift
(int
) – -
meta_area_head
(int
) – -
meta_area_tail
(int
) – -
avail_meta_areas
(int
) – -
active
(list[int]
) – -
usage_by_class
(list[int]
) – -
unmap_seq
(list[int]
) – -
bounces
(list[int]
) – -
seq
(int
) – -
brk
(int
) – -
sizeof
(int
) – -
has_pagesize_field
(bool
) –
Mallocng ¤
Bases: MemoryAllocator
Tracks the allocator state. By leveraging the __malloc_context symbol.
Import this singleton class like: from pwndbg.aglib.heap.mallocng import mallocng as ng
and make sure that you have run ng.init_if_needed() before you used the object.
Methods:
-
init_if_needed
–We want this class to be a singleton, but also we can't
-
set_ctx_addr
–Find where the __malloc_context global symbol is. Try using debug information,
-
libc_has_debug_syms
– -
containing
–Get the
start
of a slot which contains this address. -
is_initialized
–Returns whether the allocator is initialized or not.
Attributes:
-
finished_init
(bool
) – -
ctx_addr
(int
) – -
ctx
(MallocContext | None
) – -
has_debug_syms
(bool
) – -
secret
(bytearray
) – -
hope
(bool
) –
init_if_needed ¤
We want this class to be a singleton, but also we can't initialize it as soon as pwndbg is loaded.
Users of the object are responsible for calling this to make sure the object is initialized.
set_ctx_addr ¤
Find where the __malloc_context global symbol is. Try using debug information, but if it isn't available try using a heuristic.
containing ¤
Get the start
of a slot which contains this address.
We say a slot "contains" an address, if the address is in [start, start + stride). Thus, this will match the previous slot if you provide the address of the header inband metadata of a slot.
If metadata
is True, then we check [start - IB, end) for containment.
If shallow
is True, return the first slot hit without trying to look for nested groups.
is_initialized ¤
Returns whether the allocator is initialized or not.
Returns:
-
bool
–A boolean.