Handle load_segs overflow in register_dynlib_callback gracefully
authorKjetil Matheussen <k.s.matheussen@notam02.no>
Sat, 16 Jul 2016 12:43:32 +0000 (14:43 +0200)
committerIvan Maidanski <ivmai@mail.ru>
Fri, 22 Jul 2016 18:18:21 +0000 (21:18 +0300)
* dyn_load.c [HAVE_DL_ITERATE_PHDR and PT_GNU_RELRO]
(GC_register_dynlib_callback): If n_load_segs reaches MAX_LOAD_SEGS
then call WARN (with the appropriate message) and call
GC_add_roots_inner to register the segment directly instead of ABORT.

dyn_load.c

index c0f9c5b..3d6b98b 100644 (file)
@@ -527,7 +527,6 @@ STATIC int GC_register_dynlib_callback(struct dl_phdr_info * info,
           if (callback != 0 && !callback(info->dlpi_name, start, p->p_memsz))
             break;
 #         ifdef PT_GNU_RELRO
-            if (n_load_segs >= MAX_LOAD_SEGS) ABORT("Too many PT_LOAD segs");
 #           if CPP_WORDSZ == 64
               /* FIXME: GC_push_all eventually does the correct         */
               /* rounding to the next multiple of ALIGNMENT, so, most   */
@@ -536,11 +535,17 @@ STATIC int GC_register_dynlib_callback(struct dl_phdr_info * info,
               /* start pointer value may require aligning */
               start = (ptr_t)((word)start & ~(sizeof(word) - 1));
 #           endif
-            load_segs[n_load_segs].start = start;
-            load_segs[n_load_segs].end = end;
-            load_segs[n_load_segs].start2 = 0;
-            load_segs[n_load_segs].end2 = 0;
-            ++n_load_segs;
+            if (n_load_segs >= MAX_LOAD_SEGS) {
+              WARN("Too many PT_LOAD segments;"
+                   " registering as roots directly...\n", 0);
+              GC_add_roots_inner(start, end, TRUE);
+            } else {
+              load_segs[n_load_segs].start = start;
+              load_segs[n_load_segs].end = end;
+              load_segs[n_load_segs].start2 = 0;
+              load_segs[n_load_segs].end2 = 0;
+              ++n_load_segs;
+            }
 #         else
             GC_add_roots_inner(start, end, TRUE);
 #         endif /* PT_GNU_RELRO */