free

Leer & oefen AWS-hacking:HackTricks Opleiding AWS Red Team Expert (ARTE) Leer & oefen GCP-hacking: HackTricks Opleiding GCP Red Team Expert (GRTE)

Ondersteun HackTricks

Vry Bestellingsopsomming

(Geen kontroles word in hierdie opsomming verduidelik en sommige gevalle is weggelaat vir bondigheid)

  1. As die adres nul is, moet niks gedoen word nie

  2. As die blokkie gemap is, moet dit ontmap word en klaarmaak

  3. Roep _int_free aan:

  4. Voeg die blokkie indien moontlik by die tcache

  5. Voeg die blokkie indien moontlik by die vinnige bin

  6. Roep _int_free_merge_chunk aan om die blokkie te konsolideer indien nodig en voeg dit by die ongesorteerde lys

__libc_free

Vry roep __libc_free aan.

  • As die adres wat deurgegee word Nul (0) is, moet niks gedoen word nie.

  • Kontroleer aanwysertiket

  • As die blokkie gemap is, moet dit ontmap word en dis alles

  • Indien nie, voeg die kleur by en roep _int_free daaroor aan

__lib_free kode

```c void __libc_free (void *mem) { mstate ar_ptr; mchunkptr p; /* chunk corresponding to mem */

if (mem == 0) /* free(0) has no effect */ return;

/* Quickly check that the freed pointer matches the tag for the memory. This gives a useful double-free detection. */ if (__glibc_unlikely (mtag_enabled)) *(volatile char *)mem;

int err = errno;

p = mem2chunk (mem);

if (chunk_is_mmapped (p)) /* release mmapped memory. / { / See if the dynamic brk/mmap threshold needs adjusting. Dumped fake mmapped chunks do not affect the threshold. */ if (!mp_.no_dyn_threshold && chunksize_nomask (p) > mp_.mmap_threshold && chunksize_nomask (p) <= DEFAULT_MMAP_THRESHOLD_MAX) { mp_.mmap_threshold = chunksize (p); mp_.trim_threshold = 2 * mp_.mmap_threshold; LIBC_PROBE (memory_mallopt_free_dyn_thresholds, 2, mp_.mmap_threshold, mp_.trim_threshold); } munmap_chunk (p); } else { MAYBE_INIT_TCACHE ();

/* Mark the chunk as belonging to the library again. */ (void)tag_region (chunk2mem (p), memsize (p));

ar_ptr = arena_for_chunk (p); _int_free (ar_ptr, p, 0); }

__set_errno (err); } libc_hidden_def (__libc_free)

</details>

## \_int\_free <a href="#int_free" id="int_free"></a>

### \_int\_free begin <a href="#int_free" id="int_free"></a>

Dit begin met 'n paar kontroles om seker te maak:

* die **aanwyser** is **uitgelyn,** of veroorsaak fout `free(): ongeldige aanwyser`
* die **grootte** is nie minder as die minimum nie en dat die **grootte** ook **uitgelyn** is, of veroorsaak fout: `free(): ongeldige grootte`

<details>

<summary>_int_free begin</summary>
```c
// From https://github.com/bminor/glibc/blob/f942a732d37a96217ef828116ebe64a644db18d7/malloc/malloc.c#L4493C1-L4513C28

#define aligned_OK(m) (((unsigned long) (m) &MALLOC_ALIGN_MASK) == 0)

static void
_int_free (mstate av, mchunkptr p, int have_lock)
{
INTERNAL_SIZE_T size;        /* its size */
mfastbinptr *fb;             /* associated fastbin */

size = chunksize (p);

/* Little security check which won't hurt performance: the
allocator never wraps around at the end of the address space.
Therefore we can exclude some size values which might appear
here by accident or by "design" from some intruder.  */
if (__builtin_expect ((uintptr_t) p > (uintptr_t) -size, 0)
|| __builtin_expect (misaligned_chunk (p), 0))
malloc_printerr ("free(): invalid pointer");
/* We know that each chunk is at least MINSIZE bytes in size or a
multiple of MALLOC_ALIGNMENT.  */
if (__glibc_unlikely (size < MINSIZE || !aligned_OK (size)))
malloc_printerr ("free(): invalid size");

check_inuse_chunk(av, p);

_int_free tcache

Dit sal eerste probeer om hierdie blok toe te wijs in die betrokke tcache. Daar word egter voorafgaande kontroles uitgevoer. Dit sal deurloop deur al die blokke van die tcache in dieselfde indeks as die vrygestelde blok en:

  • As daar meer inskrywings is as mp_.tcache_count: free(): te veel blokke opgespoor in tcache

  • As die inskrywing nie belyn is nie: free(): ongealigneerde blok opgespoor in tcache 2

  • as die vrygestelde blok reeds vrygestel is en teenwoordig is as blok in die tcache: free(): dubbele vrystelling opgespoor in tcache 2

As alles goed verloop, word die blok by die tcache gevoeg en die funksies keer terug.

// From https://github.com/bminor/glibc/blob/f942a732d37a96217ef828116ebe64a644db18d7/malloc/malloc.c#L4515C1-L4554C7
#if USE_TCACHE
{
size_t tc_idx = csize2tidx (size);
if (tcache != NULL && tc_idx < mp_.tcache_bins)
{
/* Check to see if it's already in the tcache.  */
tcache_entry *e = (tcache_entry *) chunk2mem (p);

/* This test succeeds on double free.  However, we don't 100%
trust it (it also matches random payload data at a 1 in
2^<size_t> chance), so verify it's not an unlikely
coincidence before aborting.  */
if (__glibc_unlikely (e->key == tcache_key))
{
tcache_entry *tmp;
size_t cnt = 0;
LIBC_PROBE (memory_tcache_double_free, 2, e, tc_idx);
for (tmp = tcache->entries[tc_idx];
tmp;
tmp = REVEAL_PTR (tmp->next), ++cnt)
{
if (cnt >= mp_.tcache_count)
malloc_printerr ("free(): too many chunks detected in tcache");
if (__glibc_unlikely (!aligned_OK (tmp)))
malloc_printerr ("free(): unaligned chunk detected in tcache 2");
if (tmp == e)
malloc_printerr ("free(): double free detected in tcache 2");
/* If we get here, it was a coincidence.  We've wasted a
few cycles, but don't abort.  */
}
}

if (tcache->counts[tc_idx] < mp_.tcache_count)
{
tcache_put (p, tc_idx);
return;
}
}
}
#endif

_int_free vinnige bin

Begin deur te kontroleer of die grootte geskik is vir 'n vinnige bin en kyk of dit moontlik is om dit naby die boonste brokkie te stel.

Voeg dan die vrygemaakte brokkie by die boonste van die vinnige bin terwyl jy 'n paar kontroles uitvoer:

  • As die grootte van die brokkie ongeldig is (te groot of te klein) trigger: free(): invalid next size (fast)

  • As die bygevoegde brokkie reeds die boonste van die vinnige bin was: double free or corruption (fasttop)

  • As die grootte van die brokkie bo aan 'n verskillende grootte het as die brokkie wat ons byvoeg: invalid fastbin entry (free)

_int_free Vinnige Bin

```c // From https://github.com/bminor/glibc/blob/f942a732d37a96217ef828116ebe64a644db18d7/malloc/malloc.c#L4556C2-L4631C4

/* If eligible, place chunk on a fastbin so it can be found and used quickly in malloc. */

if ((unsigned long)(size) <= (unsigned long)(get_max_fast ())

#if TRIM_FASTBINS /* If TRIM_FASTBINS set, don't place chunks bordering top into fastbins */ && (chunk_at_offset(p, size) != av->top) #endif ) {

if (__builtin_expect (chunksize_nomask (chunk_at_offset (p, size)) <= CHUNK_HDR_SZ, 0) || __builtin_expect (chunksize (chunk_at_offset (p, size))

= av->system_mem, 0)) { bool fail = true; /* We might not have a lock at this point and concurrent modifications of system_mem might result in a false positive. Redo the test after getting the lock. */ if (!have_lock) { __libc_lock_lock (av->mutex); fail = (chunksize_nomask (chunk_at_offset (p, size)) <= CHUNK_HDR_SZ || chunksize (chunk_at_offset (p, size)) >= av->system_mem); __libc_lock_unlock (av->mutex); }

if (fail) malloc_printerr ("free(): invalid next size (fast)"); }

free_perturb (chunk2mem(p), size - CHUNK_HDR_SZ);

atomic_store_relaxed (&av->have_fastchunks, true); unsigned int idx = fastbin_index(size); fb = &fastbin (av, idx);

/* Atomically link P to its fastbin: P->FD = *FB; *FB = P; */ mchunkptr old = *fb, old2;

if (SINGLE_THREAD_P) { /* Check that the top of the bin is not the record we are going to add (i.e., double free). */ if (__builtin_expect (old == p, 0)) malloc_printerr ("double free or corruption (fasttop)"); p->fd = PROTECT_PTR (&p->fd, old); fb = p; } else do { / Check that the top of the bin is not the record we are going to add (i.e., double free). */ if (__builtin_expect (old == p, 0)) malloc_printerr ("double free or corruption (fasttop)"); old2 = old; p->fd = PROTECT_PTR (&p->fd, old); } while ((old = catomic_compare_and_exchange_val_rel (fb, p, old2)) != old2);

/* Check that size of fastbin chunk at the top is the same as size of the chunk that we are adding. We can dereference OLD only if we have the lock, otherwise it might have already been allocated again. */ if (have_lock && old != NULL && __builtin_expect (fastbin_index (chunksize (old)) != idx, 0)) malloc_printerr ("invalid fastbin entry (free)"); }

### \_int\_free finale <a href="#int_free" id="int_free"></a>

Indien die blok nog nie toegewys is aan enige bak nie, roep `_int_free_merge_chunk` aan.

<details>

<summary>_int_free finale</summary>
```c
/*
Consolidate other non-mmapped chunks as they arrive.
*/

else if (!chunk_is_mmapped(p)) {

/* If we're single-threaded, don't lock the arena.  */
if (SINGLE_THREAD_P)
have_lock = true;

if (!have_lock)
__libc_lock_lock (av->mutex);

_int_free_merge_chunk (av, p, size);

if (!have_lock)
__libc_lock_unlock (av->mutex);
}
/*
If the chunk was allocated via mmap, release via munmap().
*/

else {
munmap_chunk (p);
}
}

_int_free_merge_chunk

Hierdie funksie sal probeer om blok P van GROOTTE bytes met sy bure te kombineer. Plaas die resulterende blok op die ongesorteerde bin lys.

Sekere kontroles word uitgevoer:

  • As die blok die boonste blok is: double free or corruption (top)

  • As die volgende blok buite die grense van die arena is: double free or corruption (out)

  • As die blok nie gemerk is as gebruik (in die prev_inuse van die volgende blok nie): double free or corruption (!prev)

  • As die volgende blok 'n te klein of te groot grootte het: free(): invalid next size (normal)

  • as die vorige blok nie in gebruik is nie, sal dit probeer konsolideer. Maar, as die prev_size verskil van die grootte wat in die vorige blok aangedui word: corrupted size vs. prev_size while consolidating

_int_free_merge_chunk kode

```c // From https://github.com/bminor/glibc/blob/f942a732d37a96217ef828116ebe64a644db18d7/malloc/malloc.c#L4660C1-L4702C2

/* Try to merge chunk P of SIZE bytes with its neighbors. Put the resulting chunk on the appropriate bin list. P must not be on a bin list yet, and it can be in use. */ static void _int_free_merge_chunk (mstate av, mchunkptr p, INTERNAL_SIZE_T size) { mchunkptr nextchunk = chunk_at_offset(p, size);

/* Lightweight tests: check whether the block is already the top block. / if (__glibc_unlikely (p == av->top)) malloc_printerr ("double free or corruption (top)"); / Or whether the next chunk is beyond the boundaries of the arena. */ if (__builtin_expect (contiguous (av) && (char *) nextchunk

= ((char ) av->top + chunksize(av->top)), 0)) malloc_printerr ("double free or corruption (out)"); / Or whether the block is actually not marked used. */ if (__glibc_unlikely (!prev_inuse(nextchunk))) malloc_printerr ("double free or corruption (!prev)");

INTERNAL_SIZE_T nextsize = chunksize(nextchunk); if (__builtin_expect (chunksize_nomask (nextchunk) <= CHUNK_HDR_SZ, 0) || __builtin_expect (nextsize >= av->system_mem, 0)) malloc_printerr ("free(): invalid next size (normal)");

free_perturb (chunk2mem(p), size - CHUNK_HDR_SZ);

/* Consolidate backward. */ if (!prev_inuse(p)) { INTERNAL_SIZE_T prevsize = prev_size (p); size += prevsize; p = chunk_at_offset(p, -((long) prevsize)); if (__glibc_unlikely (chunksize(p) != prevsize)) malloc_printerr ("corrupted size vs. prev_size while consolidating"); unlink_chunk (av, p); }

/* Write the chunk header, maybe after merging with the following chunk. */ size = _int_free_create_chunk (av, p, size, nextchunk, nextsize); _int_free_maybe_consolidate (av, size); }

</details>

<div data-gb-custom-block data-tag="hint" data-style='success'>

Leer & oefen AWS Hack: <img src="/.gitbook/assets/arte.png" alt="" data-size="line">[**HackTricks Opleiding AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="/.gitbook/assets/arte.png" alt="" data-size="line">\
Leer & oefen GCP Hack: <img src="/.gitbook/assets/grte.png" alt="" data-size="line">[**HackTricks Opleiding GCP Red Team Expert (GRTE)**<img src="/.gitbook/assets/grte.png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)

<details>

<summary>Ondersteun HackTricks</summary>

* Kontroleer die [**inskrywingsplanne**](https://github.com/sponsors/carlospolop)!
* **Sluit aan by die** 💬 [**Discord-groep**](https://discord.gg/hRep4RUj7f) of die [**telegram-groep**](https://t.me/peass) of **volg** ons op **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
* **Deel hacktruuks deur PR's in te dien by die** [**HackTricks**](https://github.com/carlospolop/hacktricks) en [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github-opslag.

</details>

</div>

Last updated