core/heap.c
/* Allocates a landing pad so that a hook inserted at addr_to_hook can reach
 * its trampoline via the landing pad.  The landing pad will reachable by a
 * 32-bit relative jmp from addr_to_hook.
 * Note: we may want to generalize this at some point such that the size of the
 *       landing pad is passed as an argument.
 */
Allocates a landing pad so that a hook inserted at addr_to_hook can reach
its trampoline via the landing pad.  The landing pad will reachable by a
32-bit relative jmp from addr_to_hook.
Note: we may want to generalize this at some point such that the size of the
landing pad is passed as an argument.
Allocates a landing pad so that a hook inserted at addr_to_hook can reach its trampoline via the landing pad . The landing pad will reachable by a 32 - bit relative jmp from addr_to_hook . Note : we may want to generalize this at some point such that the size of the landing pad is passed as an argument .
byte *
alloc_landing_pad(app_pc addr_to_hook)
{
    app_pc hook_region_start, hook_region_end;
    app_pc alloc_region_start, alloc_region_end;
    app_pc lpad_area_start = NULL, lpad_area_end;
    app_pc lpad = NULL;
    landing_pad_area_t *lpad_area = NULL;
    hook_region_start = get_allocation_base(addr_to_hook);
    if (hook_region_start == NULL) {  
        ASSERT_CURIOSITY("trying to hook raw or unallocated memory?");
        hook_region_start = addr_to_hook;
        hook_region_end = addr_to_hook;
    } else {
        hook_region_end = hook_region_start +
                          get_allocation_size(hook_region_start, NULL);
        ASSERT(hook_region_end > hook_region_start);    
        if (hook_region_end - hook_region_start > 100 * 1024 * 1024) {
            ASSERT_CURIOSITY(false && "seeing patch region > 100 MB - DGC?");
            hook_region_start = MIN(addr_to_hook, MAX(hook_region_start,
                                                      addr_to_hook - 50 * 1024 * 1024));
            hook_region_end = MAX(addr_to_hook, MIN(hook_region_end,
                                                    addr_to_hook + 50 * 1024 * 1024));
        }
    }
    alloc_region_start = REACHABLE_32BIT_START(hook_region_start,
                                               hook_region_end);
    alloc_region_end = REACHABLE_32BIT_END(hook_region_start, hook_region_end);
    ASSERT(alloc_region_start < alloc_region_end);
    write_lock(&landing_pad_areas->lock);
    if (vmvector_overlap(landing_pad_areas, alloc_region_start,
                         alloc_region_end)) {
        vmvector_iterator_t lpad_area_iter;
        vmvector_iterator_start(landing_pad_areas, &lpad_area_iter);
        while (vmvector_iterator_hasnext(&lpad_area_iter)) {
            lpad_area = vmvector_iterator_next(&lpad_area_iter,
                                               &lpad_area_start,
                                               &lpad_area_end);
            if (lpad_area_start < alloc_region_end &&
                lpad_area_end > alloc_region_start &&
                (lpad_area->cur_ptr + LANDING_PAD_SIZE) < lpad_area_end) {
                 if ((lpad_area->cur_ptr + LANDING_PAD_SIZE) >=
                     lpad_area->commit_end) {
                     extend_commitment(lpad_area->commit_end, PAGE_SIZE,
                                       MEMPROT_READ|MEMPROT_EXEC,
                                       false );
                     lpad_area->commit_end += PAGE_SIZE;
                 }
                lpad = lpad_area->cur_ptr;
                lpad_area->cur_ptr += LANDING_PAD_SIZE;
                break;
            }
        }
        vmvector_iterator_stop(&lpad_area_iter);
    } 
    if (lpad == NULL) {
        heap_error_code_t heap_error;
        lpad_area_start = os_heap_reserve_in_region(alloc_region_start,
                                                    alloc_region_end,
                                                    LANDING_PAD_AREA_SIZE,
                                                    &heap_error, true);
        if (lpad_area_start == NULL ||
            heap_error == HEAP_ERROR_CANT_RESERVE_IN_REGION) {
            lpad_area_start = os_heap_reserve(
                                  (void *)ALIGN_FORWARD(addr_to_hook,
                                                        LANDING_PAD_AREA_SIZE),
                                  LANDING_PAD_AREA_SIZE, &heap_error, true);
            if (lpad_area_start == NULL) {
                SYSLOG_INTERNAL_WARNING("unable to reserve memory for landing pads");
                report_low_on_memory(OOM_RESERVE, heap_error);
            }
        }
        extend_commitment(lpad_area_start, PAGE_SIZE, MEMPROT_READ|MEMPROT_EXEC,
                          true );
        lpad_area = HEAP_TYPE_ALLOC(GLOBAL_DCONTEXT, landing_pad_area_t,
                                    ACCT_VMAREAS, PROTECTED);
        lpad_area->start = lpad_area_start;
        lpad_area->end = lpad_area_start + LANDING_PAD_AREA_SIZE;
        lpad_area->commit_end = lpad_area_start + PAGE_SIZE;
        lpad_area->cur_ptr = lpad_area_start;
        lpad = lpad_area->cur_ptr;
        lpad_area->cur_ptr += LANDING_PAD_SIZE;
        vmvector_add(landing_pad_areas, lpad_area->start,
                     lpad_area->end, lpad_area);
        STATS_INC(num_landing_pad_areas);
    }
    ASSERT(lpad_area->cur_ptr <= lpad_area->start + LANDING_PAD_AREA_SIZE);
    write_unlock(&landing_pad_areas->lock);
    return lpad;
}
byte * alloc_landing_pad ( app_pc addr_to_hook ) { app_pc hook_region_start , hook_region_end ; app_pc alloc_region_start , alloc_region_end ; app_pc lpad_area_start = NULL , lpad_area_end ; app_pc lpad = NULL ; landing_pad_area_t * lpad_area = NULL ; hook_region_start = get_allocation_base ( addr_to_hook ) ; if ( hook_region_start == NULL ) { ASSERT_CURIOSITY ( " " ) ; hook_region_start = addr_to_hook ; hook_region_end = addr_to_hook ; } else { hook_region_end = hook_region_start + get_allocation_size ( hook_region_start , NULL ) ; ASSERT ( hook_region_end > hook_region_start ) ; if ( hook_region_end - hook_region_start > 100 * 1024 * 1024 ) { ASSERT_CURIOSITY ( false && " " ) ; hook_region_start = MIN ( addr_to_hook , MAX ( hook_region_start , addr_to_hook - 50 * 1024 * 1024 ) ) ; hook_region_end = MAX ( addr_to_hook , MIN ( hook_region_end , addr_to_hook + 50 * 1024 * 1024 ) ) ; } } alloc_region_start = REACHABLE_32BIT_START ( hook_region_start , hook_region_end ) ; alloc_region_end = REACHABLE_32BIT_END ( hook_region_start , hook_region_end ) ; ASSERT ( alloc_region_start < alloc_region_end ) ; write_lock ( & landing_pad_areas -> lock ) ; if ( vmvector_overlap ( landing_pad_areas , alloc_region_start , alloc_region_end ) ) { vmvector_iterator_t lpad_area_iter ; vmvector_iterator_start ( landing_pad_areas , & lpad_area_iter ) ; while ( vmvector_iterator_hasnext ( & lpad_area_iter ) ) { lpad_area = vmvector_iterator_next ( & lpad_area_iter , & lpad_area_start , & lpad_area_end ) ; if ( lpad_area_start < alloc_region_end && lpad_area_end > alloc_region_start && ( lpad_area -> cur_ptr + LANDING_PAD_SIZE ) < lpad_area_end ) { if ( ( lpad_area -> cur_ptr + LANDING_PAD_SIZE ) >= lpad_area -> commit_end ) { extend_commitment ( lpad_area -> commit_end , PAGE_SIZE , MEMPROT_READ | MEMPROT_EXEC , false ) ; lpad_area -> commit_end += PAGE_SIZE ; } lpad = lpad_area -> cur_ptr ; lpad_area -> cur_ptr += LANDING_PAD_SIZE ; break ; } } vmvector_iterator_stop ( & lpad_area_iter ) ; } if ( lpad == NULL ) { heap_error_code_t heap_error ; lpad_area_start = os_heap_reserve_in_region ( alloc_region_start , alloc_region_end , LANDING_PAD_AREA_SIZE , & heap_error , true ) ; if ( lpad_area_start == NULL || heap_error == HEAP_ERROR_CANT_RESERVE_IN_REGION ) { lpad_area_start = os_heap_reserve ( ( void * ) ALIGN_FORWARD ( addr_to_hook , LANDING_PAD_AREA_SIZE ) , LANDING_PAD_AREA_SIZE , & heap_error , true ) ; if ( lpad_area_start == NULL ) { SYSLOG_INTERNAL_WARNING ( " " ) ; report_low_on_memory ( OOM_RESERVE , heap_error ) ; } } extend_commitment ( lpad_area_start , PAGE_SIZE , MEMPROT_READ | MEMPROT_EXEC , true ) ; lpad_area = HEAP_TYPE_ALLOC ( GLOBAL_DCONTEXT , landing_pad_area_t , ACCT_VMAREAS , PROTECTED ) ; lpad_area -> start = lpad_area_start ; lpad_area -> end = lpad_area_start + LANDING_PAD_AREA_SIZE ; lpad_area -> commit_end = lpad_area_start + PAGE_SIZE ; lpad_area -> cur_ptr = lpad_area_start ; lpad = lpad_area -> cur_ptr ; lpad_area -> cur_ptr += LANDING_PAD_SIZE ; vmvector_add ( landing_pad_areas , lpad_area -> start , lpad_area -> end , lpad_area ) ; STATS_INC ( num_landing_pad_areas ) ; } ASSERT ( lpad_area -> cur_ptr <= lpad_area -> start + LANDING_PAD_AREA_SIZE ) ; write_unlock ( & landing_pad_areas -> lock ) ; return lpad ; }
Allocates a landing pad so that a hook inserted at addr_to_hook can reach
 its trampoline via the landing pad.
Allocates a landing pad so that a hook inserted at addr_to_hook can reach its trampoline via the landing pad .
/* Allocate the landing pad area such that any hook from within the module
     * or memory region containing addr_to_hook can use the same area for a
     * landing pad.  Makes it more efficient. */ /* to support raw virtual address hooks */ /* check overflow */ /* If region size is > 2 GB, then it isn't an image; PE32{,+} restrict
         * images to 2 GB.  Also, if region is > 2 GB the reachability macros
         * called below will return a region smaller (and with start and end
         * inverted) than the region from which the reachability is desired,
         * i.e., some of the areas in [hook_region_start, hook_region_end)
         * won't be able to reach the region computed.
         *
         * A better choice is to pick something smaller (100 MB) because if the
         * region is close to 2 GB in size then we might not be able to
         * allocate memory for a landing pad that is reachable.
         */ /* Try a smaller region of 100 MB around the address to hook. */ /* Define the region that can be reached from anywhere within the
     * hook region with a 32-bit rel jmp.
     */ /* Check if there is an existing landing pad area within the reachable
     * region for the hook location.  If so use it, else allocate one.
     */ /* Now we have to get that landing pad area that is FULLY contained
         * within alloc_region_start and alloc_region_end.  If a landing pad
         * area is only partially within the alloc region, then a landing pad
         * created there won't be able to reach the addr_to_hook.  BTW, that
         * landing pad area should have enough space to allocate a landing pad!
         * If these conditions are met allocate a landing pad.
         */ /* See if enough memory in this landing pad area has been
                  * committed, if not commit more memory.
                  */ /* not initial commit */ /* Update the current pointer for the landing pad area, i.e.,
                 * allocate the landing pad.
                 */ /* If a landing pad area wasn't found because there wasn't any in the
     * allocation region or none fully contained within the allocation region,
     * then create a new one within the allocation region.  Then allocate a
     * landing pad in it.
     */ /*+x*/ /* Should retry with using just the aligned target address - we may
             * have made the region so large that there's nothing nearby to
             * reserve.
             */ /*+x*/ /* Even at startup when there will be enough memory,
                 * theoritically 2 GB of dlls might get packed together before
                 * we get control (very unlikely), so we can fail.  If it does,
                 * then say 'oom' and exit.
                 */ /* Allocate the landing pad area as rx, allocate a landing pad in it
         * and add it to landing_pad_areas vector.  Note, we only commit 4k
         * initially even though we reserve 64k (LANDING_PAD_AREA_SIZE), to
         * avoid wastage.
         */ /* initial commit */ /* Landing pads aren't added to executable_areas here because not all
     * landing pads should be added.  Only the ones used for DR hooks should be
     * added to executable areas (which is done using
     * landing_pads_to_executable_areas() at the end of inserting DR hooks).
     * hotp_only related landing pads shouldn't be added to executable areas as
     * their trampolines aren't added to executable_areas.  This is why landing
     * pads aren't added to executable_areas here, at the point of allocation.
     */ /* Boundary check to make sure the allocation is within the landing pad area. */