Discussion:
[Gc] Fwd: Large offset in negative GC_DS_PER_OBJECT descriptors can lead to arbitrary data being misinterpreted as type descriptors (#92)
Ivan Maidanski
2016-02-17 21:13:29 UTC
Permalink
Copied to ML
-------- Forwarded message --------
From: Niklas Therning <***@github.com>
CC: ivmai/bdwgc <***@noreply.github.com>
Date: Wed, 17 Feb 2016, 16:45 +03:00
Subj: [bdwgc] Large offset in negative GC_DS_PER_OBJECT descriptors can lead to arbitrary data being misinterpreted as type descriptors (#92)
Added a check in GC_mark_from() for GC_DS_PER_OBJECT objects with negative descriptors to prevent mistaking the free list pointers in free objects for being type descriptor pointers. If the specified descriptor offset was larger than the object size this could lead to arbitrary data from allocated objects
being misinterpreted as descriptors and the process crashing.
The patch tries to determine if the object pointed to by type_descr is large enough to hold a type descriptor at the configured offset. If it's too small current_p is ignored.
To illustrate the problem I have pasted some info from LLDB below when a crash occurred in GC_mark_from(). current_p in GC_mark_from() is 0x31eca68 which is a free object (i.e. not allocated) but it's probably marked due to being referenced by the stack. mark_stack_top has the following value:
(lldb) p *mark_stack_top
(mse) $1 = {
  mse_start = 0x031eca68 "P\xffffffca\x1e\x03"
  mse_descr = (w = 4294967219, sw = -77, vp = 0xffffffb3, ao = 4294967219)
}
The mse_descr value (0xffffffb3) is a GC_DS_PER_OBJECT with our MARK_DESCR_OFFSET of 64.
The hblkhdr of the block containing this object:
(lldb) p *(struct hblkhdr*)0x432c660
(struct hblkhdr) $2 = {
  hb_next = 0x00000000
  hb_prev = 0x00000000
  hb_block = 0x031ec000
  hb_obj_kind = '\x04'
  hb_flags = '\0'
  hb_last_reclaimed = 1
  hb_sz = 24
  hb_descr = 4294967219
  hb_map = 0x00fef0f8
  hb_n_marks = 112
  _mark_byte_union = (_hb_marks = char [513] @ 0x7f9fc43b1c50, dummy = 16777217)
}
As can be seen size (hb_sz) of objects in this block is 24.
Dump of 10 objects of size 24 bytes around current_p (0x31eca68):
(lldb) memory read -G 60wx -l 6 current_p-24*5
0x031ec9f0: 0x031ec9d8 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
0x031eca08: 0x031ec9f0 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
0x031eca20: 0x031eca08 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
0x031eca38: 0x031eca20 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
0x031eca50: 0x031eca38 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
0x031eca68: 0x031eca50 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
0x031eca80: 0x00fdb4c0 0x00000000 0x00000005 0x30303336 0x00000030 0x00000000
0x031eca98: 0x00fdb4c0 0x00000000 0x00000005 0x30303236 0x00000030 0x00000000
0x031ecab0: 0x00fdb4c0 0x00000000 0x00000005 0x30303136 0x00000030 0x00000000
0x031ecac8: 0x00fdb4c0 0x00000000 0x00000005 0x30303036 0x00000030 0x00000000
The free list link pointers can clearly be seen in this dump. The object at 0x031eca68 points at 0x031eca50, which points at 0x031eca20, etc.
To get the actual GC descriptor the GC will dereference the first word:
(lldb) p *(void**)current_p
(void *) $3 = 0x031eca50
Add our MARK_DESCR_OFFSET of 64 (this is a 32-bit process):
(lldb) p (*(char**)current_p)+64
(char *) $4 = 0x031eca90 "0"
And read the value at that memory position:
(lldb) p *(word*)((*(char**)current_p)+64)
(word) $5 = 48
----------------------------------------------------------------------
You can view, comment on, or merge this pull request online at:
   https://github.com/ivmai/bdwgc/pull/92
Commit Summary
*  Added a check in GC_mark_from() for GC_DS_PER_OBJECT objects with negative
File Changes
*  M mark.c (20)
Patch Links:
*  https://github.com/ivmai/bdwgc/pull/92.patch
*  https://github.com/ivmai/bdwgc/pull/92.diff
—
Reply to this email directly or  view it on GitHub .

Loading...