From: Niklas Therning Date: Wed, 17 Feb 2016 13:16:01 +0000 (+0100) Subject: Skip GC_DS_PER_OBJECT objects with negative descriptor in GC_mark_from X-Git-Tag: gc7_6_0~61 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=57f36b93c1f1f2beb6bbbf0cb38c714b518abfdd;p=gc Skip GC_DS_PER_OBJECT objects with negative descriptor in GC_mark_from 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. * mark.c (GC_mark_from): In case of GC_DS_PER_OBJECT, skip objects those descriptor is outside object. --- diff --git a/mark.c b/mark.c index d669afdf..5a233884 100644 --- a/mark.c +++ b/mark.c @@ -757,6 +757,28 @@ GC_INNER mse * GC_mark_from(mse *mark_stack_top, mse *mark_stack, mark_stack_top--; continue; } + if ((GC_word)(type_descr) >= (GC_word)GC_least_plausible_heap_addr + && (GC_word)(type_descr) + <= (GC_word)GC_greatest_plausible_heap_addr) { + /* type_descr looks like a pointer into the heap. */ + /* It could still be the link pointer in a free list */ + /* though. That's not a problem as long as the offset */ + /* of the actual descriptor in the pointed to object is */ + /* within the same object. In that case it will either */ + /* point at the next free object in the list (if offset */ + /* is 0) or be zeroed (which we check for below, */ + /* descr == 0). If the offset is larger than the */ + /* objects in the block type_descr points to it cannot */ + /* be a proper pointer. */ + word offset = ~(descr + (GC_INDIR_PER_OBJ_BIAS + - GC_DS_PER_OBJECT - 1)); + hdr *hhdr; + GET_HDR(type_descr, hhdr); + if (NULL == hhdr || hhdr->hb_sz - sizeof(word) < offset) { + mark_stack_top--; + continue; + } + } descr = *(word *)(type_descr - (descr + (GC_INDIR_PER_OBJ_BIAS - GC_DS_PER_OBJECT)));