Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix tcache and support it on targets w/o -lpthread #552

Conversation

disconnect3d
Copy link
Member

@disconnect3d disconnect3d commented Oct 21, 2018

Short summary:

  • fixes tcache having wrong address
  • adds tcache support on targets that are compiled without -lpthread - we assume that tcache address is at offset 0x10 on the heap
  • fixes pwndbg.symbol.address as it could return offsets instead of an address

Long description below.

This commit fixes tcache: we used the address of &tcache instead of tcache for dereferencing the struct. This can be observed with:

pwndbg> p *tcache
$8 = {
  counts = '\000' <repeats 63 times>,
  entries = {0x0 <repeats 64 times>}
}
pwndbg> tcache
{
  counts = "\020`uUUU\000\000\000\000\000\000\000\000\000\000"...,
  entries = {0x0, 0x0, 0x7ffff7fd7740, 0x7ffff7fd80a0, 0x7ffff7fd7740, 0x1, 0x0, 0x7025de0aec8a0300, 0x236a7550e4a6104e, 0x0 <repeats 55 times>}
}

It also adds possibility to retrieve tcache information from targets that are compiled without -lpthread [-pthread].

It also fixes pwndbg.symbol.address's info address path when it returned addresses that were out of memory maps due to the fact GDB may return a string containing an offset instead of an address. E.g.:

pwndbg> info address tcache
Symbol "tcache" is a thread-local variable at offset 0x40 in the thread-local storage for `/lib/x86_64-linux-gnu/libc.so.6'.

Short summary:
* fixes tcache having wrong address
* adds heuristic to retrieve tcache address when binary is compiled w/o
-lpthread (may not work on glibc's other than 2.27)
* fixes `pwndbg.symbol.address` as it could return offsets instead of
an address

---

Long description below.

This commit fixes tcache: we used the address of &tcache instead of
tcache for dereferencing the struct. This can be observed with:
```
pwndbg> p *tcache
$8 = {
  counts = '\000' <repeats 63 times>,
  entries = {0x0 <repeats 64 times>}
}
pwndbg> tcache
{
  counts = "\020`uUUU\000\000\000\000\000\000\000\000\000\000"...,
  entries = {0x0, 0x0, 0x7ffff7fd7740, 0x7ffff7fd80a0, 0x7ffff7fd7740, 0x1, 0x0, 0x7025de0aec8a0300, 0x236a7550e4a6104e, 0x0 <repeats 55 times>}
}
```

It also adds possibility to retrieve tcache information from targets
that are compiled without -lpthread [-pthread].

**NOTE: This is experimental and may not work across different glibc
versions. It was tested on Ubuntu 18.04 on 2.27 glibc.**

This is because we get tcache pointer by making an assumption that it
will lie 0x10 bytes before one of the addresses that points to
&main_arena.

It also fixes `pwndbg.symbol.address`'s `info address` path when it
returned addresses that were out of memory maps due to the fact GDB may
return a string containing an offset instead of an address. E.g.:
```
pwndbg> info address tcache
Symbol "tcache" is a thread-local variable at offset 0x40 in the thread-local storage for `/lib/x86_64-linux-gnu/libc.so.6'.
```
@disconnect3d disconnect3d mentioned this pull request Oct 21, 2018
@disconnect3d
Copy link
Member Author

Oh also it seems the tcache is the first allocation made by glibc and so as a result the first chunk is indeed tcache structure, see https://github.com/bminor/glibc/blob/master/malloc/malloc.c#L2971 or :

static void
tcache_init(void)
{
  mstate ar_ptr;
  void *victim = 0;
  const size_t bytes = sizeof (tcache_perthread_struct);

  if (tcache_shutting_down)
    return;

  arena_get (ar_ptr, bytes);
  victim = _int_malloc (ar_ptr, bytes);  // first allocation made in glibc!
  if (!victim && ar_ptr != NULL)
    {
      ar_ptr = arena_get_retry (ar_ptr, bytes);
      victim = _int_malloc (ar_ptr, bytes);
    }


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

  /* In a low memory situation, we may not be able to allocate memory
     - in which case, we just keep trying later.  However, we
     typically do this very early, so either there is sufficient
     memory, or there isn't enough memory to do non-trivial
     allocations anyway.  */
  if (victim)
    {
      tcache = (tcache_perthread_struct *) victim;
      memset (tcache, 0, sizeof (tcache_perthread_struct));
    }

}

@disconnect3d disconnect3d merged commit 8f33ec4 into pwndbg:dev Oct 22, 2018
@disconnect3d disconnect3d deleted the fix-tcache-and-support-targets-without-pthread branch October 22, 2018 21:14
@disconnect3d disconnect3d mentioned this pull request Nov 8, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

None yet

1 participant