malloc & sysmalloc

Unterstützen Sie HackTricks

Zusammenfassung der Allokationsreihenfolge

(In dieser Zusammenfassung werden keine Überprüfungen erläutert und einige Fälle wurden der Kürze halber ausgelassen)

  1. __libc_malloc versucht, einen Chunk aus dem tcache zu erhalten. Wenn nicht, ruft es _int_malloc auf.

  2. _int_malloc:

    1. Versucht, die Arena zu generieren, wenn keine vorhanden ist.

    2. Wenn ein passender Fast-Bin-Chunk vorhanden ist, wird dieser verwendet.

      1. Füllen Sie den tcache mit anderen Fast-Chunks.

    3. Wenn ein Small-Bin-Chunk der richtigen Größe vorhanden ist, wird dieser verwendet.

      1. Füllen Sie den tcache mit anderen Chunks dieser Größe.

    4. Wenn die angeforderte Größe nicht für Small-Bins ist, konsolidieren Sie den Fast-Bin in den unsortierten Bin.

    5. Überprüfen Sie den unsortierten Bin und verwenden Sie den ersten Chunk mit ausreichend Platz.

      1. Wenn der gefundene Chunk größer ist, teilen Sie ihn auf, um einen Teil zurückzugeben, und fügen Sie den Rest wieder dem unsortierten Bin hinzu.

      2. Wenn ein Chunk die gleiche Größe wie die angeforderte Größe hat, verwenden Sie ihn, um den tcache anstelle der Rückgabe zu füllen (bis der tcache voll ist, dann geben Sie den nächsten zurück).

      3. Für jeden überprüften Chunk kleinerer Größe legen Sie ihn in den entsprechenden Small- oder Large-Bin.

    6. Überprüfen Sie den Large-Bin im Index der angeforderten Größe.

      1. Beginnen Sie mit der Suche ab dem ersten Chunk, der größer als die angeforderte Größe ist. Wenn einer gefunden wird, geben Sie ihn zurück und fügen Sie die Reste dem Small-Bin hinzu.

    7. Überprüfen Sie die Large-Bins von den nächsten Indizes bis zum Ende.

      1. Überprüfen Sie ab dem nächsten größeren Index auf einen beliebigen Chunk, teilen Sie den ersten gefundenen Chunk auf, um ihn für die angeforderte Größe zu verwenden, und fügen Sie den Rest dem unsortierten Bin hinzu.

    8. Wenn in den vorherigen Bins nichts gefunden wurde, erhalten Sie einen Chunk vom Top-Chunk.

    9. Wenn der Top-Chunk nicht groß genug war, vergrößern Sie ihn mit sysmalloc.

__libc_malloc

Die malloc-Funktion ruft tatsächlich __libc_malloc auf. Diese Funktion überprüft den tcache, um zu sehen, ob ein verfügbarer Chunk der gewünschten Größe vorhanden ist. Wenn ja, wird er verwendet, andernfalls wird überprüft, ob es sich um einen einzelnen Thread handelt, und in diesem Fall wird _int_malloc in der Hauptarena aufgerufen, andernfalls wird _int_malloc in der Arena des Threads aufgerufen.

__libc_malloc code

```c // From https://github.com/bminor/glibc/blob/master/malloc/malloc.c

#if IS_IN (libc) void * __libc_malloc (size_t bytes) { mstate ar_ptr; void *victim;

_Static_assert (PTRDIFF_MAX <= SIZE_MAX / 2, "PTRDIFF_MAX is not more than half of SIZE_MAX");

if (!__malloc_initialized) ptmalloc_init (); #if USE_TCACHE /* int_free also calls request2size, be careful to not pad twice. */ size_t tbytes = checked_request2size (bytes); if (tbytes == 0) { __set_errno (ENOMEM); return NULL; } size_t tc_idx = csize2tidx (tbytes);

MAYBE_INIT_TCACHE ();

DIAG_PUSH_NEEDS_COMMENT; if (tc_idx < mp_.tcache_bins && tcache != NULL && tcache->counts[tc_idx] > 0) { victim = tcache_get (tc_idx); return tag_new_usable (victim); } DIAG_POP_NEEDS_COMMENT; #endif

if (SINGLE_THREAD_P) { victim = tag_new_usable (_int_malloc (&main_arena, bytes)); assert (!victim || chunk_is_mmapped (mem2chunk (victim)) || &main_arena == arena_for_chunk (mem2chunk (victim))); return victim; }

arena_get (ar_ptr, bytes);

victim = _int_malloc (ar_ptr, bytes); /* Retry with another arena only if we were able to find a usable arena before. */ if (!victim && ar_ptr != NULL) { LIBC_PROBE (memory_malloc_retry, 1, bytes); ar_ptr = arena_get_retry (ar_ptr, bytes); victim = _int_malloc (ar_ptr, bytes); }

if (ar_ptr != NULL) __libc_lock_unlock (ar_ptr->mutex);

victim = tag_new_usable (victim);

assert (!victim || chunk_is_mmapped (mem2chunk (victim)) || ar_ptr == arena_for_chunk (mem2chunk (victim))); return victim; }

</details>

Beachten Sie, wie der zurückgegebene Zeiger immer mit `tag_new_usable` markiert wird, aus dem Code:
```c
void *tag_new_usable (void *ptr)

Allocate a new random color and use it to color the user region of
a chunk; this may include data from the subsequent chunk's header
if tagging is sufficiently fine grained.  Returns PTR suitably
recolored for accessing the memory there.

_int_malloc

Dies ist die Funktion, die Speicher unter Verwendung der anderen Bins und des Top-Chunks zuweist.

  • Start

Es beginnt mit der Definition einiger Variablen und dem Ermitteln der tatsächlichen Größe, die der angeforderte Speicherplatz haben muss:

Fast Bin

Wenn die benötigte Größe innerhalb der Größen der Fast Bins liegt, versuchen Sie, einen Chunk aus dem Fast Bin zu verwenden. Basierend auf der Größe wird der Fast Bin-Index gefunden, an dem gültige Chunks liegen sollten, und falls vorhanden, wird einer davon zurückgegeben. Darüber hinaus, wenn tcache aktiviert ist, wird der tcache-Bin dieser Größe mit Fast Bins gefüllt.

Während dieser Aktionen werden einige Sicherheitsüberprüfungen durchgeführt:

  • Wenn der Chunk nicht ausgerichtet ist: malloc(): unaligned fastbin chunk detected 2

  • Wenn der vorwärts liegende Chunk nicht ausgerichtet ist: malloc(): unaligned fastbin chunk detected

  • Wenn der zurückgegebene Chunk eine Größe hat, die aufgrund seines Index im Fast Bin nicht korrekt ist: malloc(): memory corruption (fast)

  • Wenn ein beliebiger Chunk, der verwendet wird, um den tcache zu füllen, nicht ausgerichtet ist: malloc(): unaligned fastbin chunk detected 3

Wenn kein Chunk für dies geeignet ist, fahren Sie fort

Großer Bin (nächstgrößer)

Wenn im genauen großen Bin kein Chunk gefunden wurde, der verwendet werden konnte, beginnen Sie damit, alle nächsten großen Bins durchzugehen (beginnend mit dem unmittelbar größeren), bis einer gefunden wird (falls vorhanden).

Der Rest des aufgeteilten Chunks wird dem unsortierten Bin hinzugefügt, last_reminder wird aktualisiert und die gleiche Sicherheitsüberprüfung wird durchgeführt:

  • bck->fd-> bk != bck: malloc(): corrupted unsorted chunks2

sysmalloc Überprüfungen

Es beginnt damit, alte Top-Chunk-Informationen zu erhalten und zu überprüfen, ob einige der folgenden Bedingungen zutreffen:

  • Die alte Heap-Größe beträgt 0 (neuer Heap)

  • Die Größe des vorherigen Heaps ist größer als MINSIZE und der alte Top ist in Benutzung

  • Der Heap ist auf die Seitengröße ausgerichtet (0x1000, sodass die unteren 12 Bits 0 sein müssen)

Dann wird auch überprüft, ob:

  • Die alte Größe nicht genügend Platz hat, um einen Chunk für die angeforderte Größe zu erstellen

sysmalloc Hauptarena

Es beginnt mit der Berechnung der benötigten Speichermenge. Es wird damit beginnen, zusammenhängenden Speicher anzufordern, sodass in diesem Fall der alte nicht verwendete Speicher verwendet werden kann. Außerdem werden einige Ausrichtungsoperationen durchgeführt.

sysmalloc Hauptarena fortsetzen

Wenn das Vorherige nicht MORECORE_FAILURE zurückgegeben hat, und es funktioniert hat, erstellen Sie einige Ausrichtungen:

Last updated