Exemple #1
0
static void
event_thread_init(void *drcontext)
{
    per_thread_t *data = dr_thread_alloc(drcontext, sizeof(*data));

    DR_ASSERT(data != NULL);
    dr_set_tls_field(drcontext, data);
    /* Keep seg_base in a per-thread data structure so we can get the TLS
     * slot and find where the pointer points to in the buffer.
     * It is mainly for users using a debugger to get the execution history.
     */
    data->seg_base = dr_get_dr_segment_base(tls_seg);
    /* We allocate a 128KB buffer to make sure we have a 64KB buffer with
     * 64KB-aligned starting address, so that we can fill the buffer
     * cyclically by incrementing the bottom 16 bits of the pointer.
     */
    data->buf_base = dr_raw_mem_alloc(TLS_BUF_SIZE,
                                      DR_MEMPROT_READ | DR_MEMPROT_WRITE,
                                      NULL);
    DR_ASSERT(data->seg_base != NULL && data->buf_base != NULL);
    memset(data->buf_base, 0, TLS_BUF_SIZE);
    /* put the 64KB-aligned address into TLS slot as the pointer pointing
     * to the 64KB cyclic buffer
     */
    *(void **)((byte *)(data->seg_base) + tls_offs) = (void *)
        ALIGN_FORWARD(data->buf_base, BUF_64K_BYTE);
}
Exemple #2
0
static
bool exception_event_redirect(void *dcontext, dr_exception_t *excpt)
{
    app_pc addr;
    dr_mcontext_t mcontext = {sizeof(mcontext),DR_MC_ALL,};
    module_data_t *data = dr_lookup_module_by_name("client.events.exe");
    dr_fprintf(STDERR, "exception event redirect\n");
    if (data == NULL) {
        dr_fprintf(STDERR, "couldn't find events.exe module\n");
        return true;
    }
    addr = (app_pc)dr_get_proc_address(data->handle, "redirect");
    dr_free_module_data(data);
    mcontext = *excpt->mcontext;
    mcontext.pc = addr;
    if (addr == NULL) {
        dr_fprintf(STDERR, "Couldn't find function redirect in events.exe\n");
        return true;
    }
#ifdef X64
    /* align properly in case redirect function relies on conventions (i#419) */
    mcontext.xsp = ALIGN_FORWARD(mcontext.xsp, 16) - 8;
#endif
    dr_redirect_execution(&mcontext);
    dr_fprintf(STDERR, "should not be reached, dr_redirect_execution() should not return\n");
    return true;
}
Exemple #3
0
static uint
hash_key(hashtable_t *table, void *key)
{
    uint hash = 0;
    if (table->hash_key_func != NULL) {
        hash = table->hash_key_func(key);
    } else if (table->hashtype == HASH_STRING || table->hashtype == HASH_STRING_NOCASE) {
        const char *s = (const char *) key;
        char c;
        uint i, shift;
        uint max_shift = ALIGN_FORWARD(table->table_bits, 8);
        /* XXX: share w/ core's hash_value() function */
        for (i = 0; s[i] != '\0'; i++) {
            c = s[i];
            if (table->hashtype == HASH_STRING_NOCASE)
                c = (char) tolower(c);
            shift = (i % 4) * 8;
            if (shift > max_shift)
                shift = max_shift;
            hash ^= c << shift;
        }
    } else {
        /* HASH_INTPTR, or fallback for HASH_CUSTOM in release build */
        ASSERT(table->hashtype == HASH_INTPTR,
               "hashtable.c hash_key internal error: invalid hash type");
        hash = (uint)(ptr_uint_t) key;
    }
    return HASH_FUNC_BITS(hash, table->table_bits);
}
Exemple #4
0
uint
CDynamoRIOView::PrintClientStats(TCHAR *c, TCHAR *max)
{
    if (m_clientStats == NULL)
        return 0;
#define CLIENTSTAT_NAME_MAX_SHOW CLIENTSTAT_NAME_MAX_LEN
    uint i;
    TCHAR *start = c;
    char(*names)[CLIENTSTAT_NAME_MAX_LEN] =
        (char(*)[CLIENTSTAT_NAME_MAX_LEN])m_clientStats->data;
    stats_int_t *vals = (stats_int_t *)((char *)m_clientStats->data +
                                        m_clientStats->num_stats *
                                            CLIENTSTAT_NAME_MAX_LEN * sizeof(char));
    /* account for struct alignment */
    vals = (stats_int_t *)ALIGN_FORWARD(vals, sizeof(stats_int_t));
    for (i = 0; i < m_clientStats->num_stats; i++) {
        if (c >= max - CLIENTSTAT_NAME_MAX_SHOW * 2 - 3)
            break;
        c += _stprintf(c, _T("%*.*") ASCII_PRINTF _T(" = ") CLIENT_STAT_PFMT _T("\r\n"),
                       CLIENTSTAT_NAME_MAX_SHOW, CLIENTSTAT_NAME_MAX_SHOW, names[i],
                       vals[i]);
        assert(c < max);
    }
    return (uint)(c - start);
}
Exemple #5
0
bool
get_named_section_bounds(byte *module_base, const char *name,
                         byte **start/*OUT*/, byte **end/*OUT*/)
{
    IMAGE_DOS_HEADER *dos;
    IMAGE_NT_HEADERS *nt;
    IMAGE_SECTION_HEADER *sec;
    uint i;
    bool prev_sec_same_chars = false;
    assert(module_base != NULL);
    dos = (IMAGE_DOS_HEADER *) module_base;
    if (dos->e_magic != IMAGE_DOS_SIGNATURE)
        return false;
    nt = (IMAGE_NT_HEADERS *) (((ptr_uint_t)dos) + dos->e_lfanew);
    if (nt == NULL || nt->Signature != IMAGE_NT_SIGNATURE)
        return false;
    assert(start != NULL || end != NULL);
    sec = IMAGE_FIRST_SECTION(nt);
    for (i = 0; i < nt->FileHeader.NumberOfSections; i++) {
        if (sec->Name != NULL && strncmp(sec->Name, name, strlen(name)) == 0) {
            if (start != NULL)
                *start = module_base + sec->VirtualAddress;
            if (end != NULL)
                *end = module_base + sec->VirtualAddress +
                    ALIGN_FORWARD(sec->Misc.VirtualSize, PAGE_SIZE);
            return true;
        }
        sec++;
    }
    return false;
}
void
privload_tls_exit(void *dr_tp)
{
    byte *alloc;
    if (dr_tp == NULL || dr_tp == init_thread.tls)
        return;
    alloc = (byte *)dr_tp - offsetof(android_pthread_internal_t, tls);
    heap_munmap(alloc, ALIGN_FORWARD(sizeof(android_pthread_internal_t), PAGE_SIZE));
}
Exemple #7
0
void dc_invalidaterange(void *start, u32 size)
{
	u32 cookie = irq_kill();
	void *end = ALIGN_FORWARD(((u8*)start) + size, LINESIZE);
	start = ALIGN_BACKWARD(start, LINESIZE);
	_dc_inval_entries(start, (end - start) / LINESIZE);
	ahb_flush_to(AHB_STARLET);
	irq_restore(cookie);
}
Exemple #8
0
app_pc
umbra_align_cache_line(app_pc pc)
{
    app_pc new_pc;

    new_pc = (app_pc)ALIGN_FORWARD(pc, proc_get_cache_line_size());
    SET_TO_NOPS(pc, new_pc - pc);
    return new_pc;
}
Exemple #9
0
void dc_flushrange(const void *start, u32 size)
{
	u32 cookie = irq_kill();
	if(size > 0x4000) {
		_dc_flush();
	} else {
		void *end = ALIGN_FORWARD(((u8*)start) + size, LINESIZE);
		start = ALIGN_BACKWARD(start, LINESIZE);
		_dc_flush_entries(start, (end - start) / LINESIZE);
	}
	_drain_write_buffer();
	ahb_flush_from(AHB_1);
	irq_restore(cookie);
}
Exemple #10
0
app_pc
get_heap_start(void)
{
    static app_pc heap_start; /* cached value */
    if (heap_start == NULL) {
        app_pc cur_brk = get_brk(true/*pre-us*/);
        dr_mem_info_t info;
        module_data_t *data;
        /* Locate the heap */
        if (!dr_query_memory_ex(cur_brk - 1, &info)) {
            ASSERT(false, "cannot find heap region");
            return NULL;
        }
        if (info.type == DR_MEMTYPE_FREE || info.type == DR_MEMTYPE_IMAGE ||
            !TEST(DR_MEMPROT_WRITE, info.prot)) {
            /* Heap is empty */
            heap_start = cur_brk;
        } else {
            ASSERT(!dr_memory_is_dr_internal(info.base_pc), "heap location error");
            /* we no longer assert that these are equal b/c -replace_malloc
             * has extended the brk already
             */
            ASSERT(info.base_pc + info.size >= cur_brk, "heap location error");
            heap_start = info.base_pc;
            /* workaround for PR 618178 where /proc/maps is wrong on suse
             * and lists last 2 pages of executable as heap!
             */
            /* On some old Linux kernel, the heap might be right after the bss
             * segment. DR's map iterator used by dr_query_memory_ex cannot
             * split bss out of heap.
             * We use dr_lookup_module to find the right bounds of bss so that
             * we can check whether the base is bss, existing heap, or merge of
             * the two.
             */
            /* XXX: we still cannot handle the case that the application creates
             * memory right before the heap.
             */
            data = dr_lookup_module(info.base_pc);
            if (data != NULL) {
                if (data->start < heap_start && data->end > heap_start) {
                    heap_start = (byte *) ALIGN_FORWARD(data->end, PAGE_SIZE);
                    LOG(1, "WARNING: workaround for invalid heap_start "PFX" => "PFX"\n",
                        info.base_pc, heap_start);
                }
                dr_free_module_data(data);
            }
        }
    }
    return heap_start;
}
Exemple #11
0
/*
 * allocate_memory(): Simple memory allocation routine */
void_t *allocate_memory(uint64_t size_request)
{
	uint64_t address;

	if (heap_current + size_request > heap_tops) {
		PRINT_STRING("Allocation request exceeds heap's size\r\n");
		PRINT_STRING_AND_VALUE("Heap current = 0x", heap_current);
		PRINT_STRING_AND_VALUE("Requested size = 0x", size_request);
		PRINT_STRING_AND_VALUE("Heap tops = 0x", heap_tops);

		return NULL;
	}
	address = ALIGN_FORWARD(heap_current, MEM_ALLOCATE_ALIGNMENT);
	heap_current += size_request;
	zero_mem((void_t *)address, size_request);
	return (void_t *)address;
}
Exemple #12
0
bool
handle_mem_ref(uint flags, app_loc_t *loc, byte *addr, size_t sz, dr_mcontext_t *mc)
{
    byte *ptr;
    /* We're piggybacking on Dr. Memory syscall, etc. code.  For reads
     * and writes we want to mark the shadow byte to indicate the
     * memory was accessed.  For an addressability check we do
     * nothing.
     */
    if (TEST(MEMREF_CHECK_ADDRESSABLE, flags))
        return true;
    /* We ignore MEMREF_MOVS, etc.: we don't propagate anything */
    for (ptr = (byte *) ALIGN_BACKWARD(addr, SHADOW_GRANULARITY);
         ptr < (byte *) ALIGN_FORWARD(addr + sz, SHADOW_GRANULARITY);
         ptr += SHADOW_GRANULARITY) {
        shadow_set_byte(ptr, 1);
    }
    return true;
}
Exemple #13
0
void *CDECL mon_page_alloc(uint64_t pages)
{
	uint64_t address;
	uint64_t size = pages * PAGE_SIZE;

	address = ALIGN_FORWARD(heap_current, PAGE_SIZE);

	if (address + size > heap_tops) {
		PRINT_STRING("Allocation request exceeds heap's size\r\n");
		PRINT_STRING_AND_VALUE("Page aligned heap current = 0x", address);
		PRINT_STRING_AND_VALUE("Requested size = 0x", size);
		PRINT_STRING_AND_VALUE("Heap tops = 0x", heap_tops);
		return NULL;
	}

	heap_current = address + size;
	zero_mem((void *)address, size);
	return (void *)address;
}
Exemple #14
0
/* pass non-NULL for thandle if you want this routine to use
 *   Get/SetThreadContext to get the context -- you must still pass
 *   in a pointer to a cxt
 */
BOOL
inject_into_thread(HANDLE phandle, CONTEXT *cxt, HANDLE thandle,
                   char *dynamo_path)
{
    size_t              nbytes;
    BOOL                success = FALSE;
    ptr_uint_t          dynamo_entry_esp;
    ptr_uint_t          dynamo_path_esp;
    LPVOID              load_dynamo_code = NULL; /* = base of code allocation */
    ptr_uint_t          addr;
    reg_t               *bufptr;
    char                buf[MAX_PATH];
    uint                old_prot;

    ASSERT(cxt != NULL);

#ifndef NOT_DYNAMORIO_CORE_PROPER
    /* FIXME - if we were early injected we couldn't call inject_init during
     * startup because kernel32 wasn't loaded yet, so we call it here which
     * isn't safe because it uses app locks. If we want to support a mix
     * of early and late follow children injection we should change load_dynamo
     * to use Nt functions (which we can link) rather then kernel32 functions
     * (which we have to look up).  We could also use module.c code to safely
     * walk the exports of kernel32.dll (we can cache its mod handle when it
     * is loaded). */ 
    if (!inject_initialized) {
        SYSLOG_INTERNAL_WARNING("Using late inject follow children from early injected process, unsafe LdrLock usage");
        SELF_UNPROTECT_DATASEC(DATASEC_RARELY_PROT);
        inject_init();
        SELF_PROTECT_DATASEC(DATASEC_RARELY_PROT);
    }
#else
    ASSERT(inject_initialized);
#endif

    /* soon we'll start using alternative injection with case 102 - leaving block */
    {
        reg_t app_xsp;
        if (thandle != NULL) {
            /* grab the context of the app's main thread */                 
            cxt->ContextFlags = CONTEXT_DR_STATE;
            if (!NT_SUCCESS(nt_get_context(thandle, cxt))) {
                display_error("GetThreadContext failed");
                goto error;
            }
        }
        app_xsp = cxt->CXT_XSP;

        /* copy load_dynamo() into the address space of the new process */
        ASSERT(BUFFER_SIZE_BYTES(buf) > SIZE_OF_LOAD_DYNAMO);
        memcpy(buf, (char*)load_dynamo, SIZE_OF_LOAD_DYNAMO);
        /* R-X protection is adequate for our non-self modifying code,
         * and we'll update that after we're done with
         * nt_write_virtual_memory() calls */

        /* get allocation, this will be freed by os_heap_free, so make sure
         * is compatible allocation method */
        if (!NT_SUCCESS(nt_remote_allocate_virtual_memory(phandle, &load_dynamo_code, 
                                                          SIZE_OF_LOAD_DYNAMO,
                                                          PAGE_EXECUTE_READWRITE,
                                                          MEMORY_COMMIT))) {
            display_error("Failed to allocate memory for injection code");
            goto error;
        }
        if (!nt_write_virtual_memory(phandle, load_dynamo_code, buf,
                                     SIZE_OF_LOAD_DYNAMO, &nbytes)) {
            display_error("WriteMemory failed");
            goto error;
        }

        /* Xref PR 252745 & PR 252008 - we can use the app's stack to hold our data
         * even on WOW64 and 64-bit since we're using set context to set xsp. */
   
        /* copy the DYNAMORIO_ENTRY string to the app's stack */
        _snprintf(buf, BUFFER_SIZE_ELEMENTS(buf), "%s", DYNAMORIO_ENTRY);
        NULL_TERMINATE_BUFFER(buf);
        nbytes = strlen(buf) + 1; // include the trailing '\0'
        /* keep esp at pointer-sized alignment */
        cxt->CXT_XSP -= ALIGN_FORWARD(nbytes, XSP_SZ);
        dynamo_entry_esp = cxt->CXT_XSP;
        if (!nt_write_virtual_memory(phandle, (LPVOID)cxt->CXT_XSP, 
                                     buf, nbytes, &nbytes)) {
            display_error("WriteMemory failed");
            goto error;
        }

        /* copy the dynamorio_path string to the app's stack */
        _snprintf(buf, BUFFER_SIZE_ELEMENTS(buf), "%s", dynamo_path);
        NULL_TERMINATE_BUFFER(buf);
        nbytes = strlen(buf) + 1; // include the trailing '\0'
        /* keep esp at pointer-sized byte alignment */
        cxt->CXT_XSP -= ALIGN_FORWARD(nbytes, XSP_SZ);
        dynamo_path_esp = cxt->CXT_XSP;
        if (!nt_write_virtual_memory(phandle, (LPVOID)cxt->CXT_XSP, 
                                     buf, nbytes, &nbytes)) {
            display_error("WriteMemory failed");
            goto error;
        }

        /* copy the current context to the app's stack. Only need the
         * control registers, so we use a dr_mcontext_t layout.
         */
        bufptr = (reg_t*) buf;
        *bufptr++ = cxt->CXT_XDI;
        *bufptr++ = cxt->CXT_XSI;
        *bufptr++ = cxt->CXT_XBP;
        *bufptr++ = app_xsp;
        *bufptr++ = cxt->CXT_XBX;
        *bufptr++ = cxt->CXT_XDX;
        *bufptr++ = cxt->CXT_XCX;
        *bufptr++ = cxt->CXT_XAX;
#ifdef X64
        *bufptr++ = cxt->R8;
        *bufptr++ = cxt->R9;
        *bufptr++ = cxt->R10;
        *bufptr++ = cxt->R11;
        *bufptr++ = cxt->R12;
        *bufptr++ = cxt->R13;
        *bufptr++ = cxt->R14;
        *bufptr++ = cxt->R15;
#endif
        /* It would be nice to use preserve_xmm_caller_saved(), but we'd need to
         * link proc.c and deal w/ messy dependencies to get it into arch_exports.h,
         * so we do our own check.  We go ahead and put in the xmm slots even
         * if the underlying processor has no xmm support: no harm done.
         */
        if (IF_X64_ELSE(true, is_wow64_process(NT_CURRENT_PROCESS))) {
            /* PR 264138: preserve xmm0-5.  We fill in all slots even though
             * for 32-bit we don't use them (PR 306394).
             */
            int i, j;
            for (i = 0; i < NUM_XMM_SLOTS; i++) {
                for (j = 0; j < IF_X64_ELSE(2,4); j++) {
                    *bufptr++ = CXT_XMM(cxt, i)->reg[j];
                }
            }
        } else {
            /* skip xmm slots */
            bufptr += XMM_SLOTS_SIZE/sizeof(*bufptr);
        }
        *bufptr++ = cxt->CXT_XFLAGS;
        *bufptr++ = cxt->CXT_XIP;
        ASSERT((char *)bufptr - (char *)buf == sizeof(dr_mcontext_t));
        *bufptr++ = (ptr_uint_t)load_dynamo_code;
        *bufptr++ = SIZE_OF_LOAD_DYNAMO;
        nbytes = sizeof(dr_mcontext_t) + 2*sizeof(reg_t);
        cxt->CXT_XSP -= nbytes;
#ifdef X64
        /* We need xsp to be aligned prior to each call, but we can only pad
         * before the context as all later users assume the info they need is
         * at TOS.
         */
        cxt->CXT_XSP = ALIGN_BACKWARD(cxt->CXT_XSP, XMM_ALIGN);
#endif
        if (!nt_write_virtual_memory(phandle, (LPVOID)cxt->CXT_XSP,
                                     buf, nbytes, &nbytes)) {
            display_error("WriteMemory failed");
            goto error;
        }

        /* push the address of the DYNAMORIO_ENTRY string on the app's stack */
        cxt->CXT_XSP -= XSP_SZ;
        if (!nt_write_virtual_memory(phandle, (LPVOID)cxt->CXT_XSP, 
                                     &dynamo_entry_esp, sizeof(dynamo_entry_esp),
                                     &nbytes)) {
            display_error("WriteMemory failed");
            goto error;
        }

        /* push the address of GetProcAddress on the app's stack */
        ASSERT(addr_getprocaddr);
        addr = addr_getprocaddr;
        cxt->CXT_XSP -= XSP_SZ;
        if (!nt_write_virtual_memory(phandle, (LPVOID)cxt->CXT_XSP, 
                                     &addr, sizeof(addr), &nbytes)) {
            display_error("WriteMemory failed");
            goto error;
        }

        /* push the address of the dynamorio_path string on the app's stack */
        cxt->CXT_XSP -= XSP_SZ;
        if (!nt_write_virtual_memory(phandle, (LPVOID)cxt->CXT_XSP, 
                                     &dynamo_path_esp, sizeof(dynamo_path_esp),
                                     &nbytes)) {
            display_error("WriteMemory failed");
            goto error;
        }

        /* push the address of LoadLibraryA on the app's stack */
        ASSERT(addr_loadlibrarya);
        addr = addr_loadlibrarya;
        cxt->CXT_XSP -= XSP_SZ;
        if (!nt_write_virtual_memory(phandle, (LPVOID)cxt->CXT_XSP, 
                                     &addr, sizeof(addr), &nbytes)) {
            display_error("WriteMemory failed");
            goto error;
        }

#ifdef LOAD_DYNAMO_DEBUGBREAK
        /* push the address of DebugBreak on the app's stack */
        ASSERT(addr_debugbreak);
        addr = addr_debugbreak;
        cxt->CXT_XSP -= XSP_SZ;
        if (!nt_write_virtual_memory(phandle, (LPVOID)cxt->CXT_XSP, 
                                     &addr, sizeof(addr), &nbytes)) {
            display_error("WriteMemory failed");
            goto error;
        }
#endif

        /* make the code R-X now */
        if (!nt_remote_protect_virtual_memory(phandle, load_dynamo_code, 
                                              SIZE_OF_LOAD_DYNAMO,
                                              PAGE_EXECUTE_READ, &old_prot)) {
            display_error("Failed to make injection code R-X");
            goto error;
        }
        ASSERT(old_prot == PAGE_EXECUTE_READWRITE);

        /* now change Eip to point to the entry point of load_dynamo(), so that
           when we resume, load_dynamo is invoked automatically */
        cxt->CXT_XIP = (ptr_uint_t)load_dynamo_code;
        cxt->CXT_XFLAGS = 0;
        if (thandle != NULL) {
            if (!NT_SUCCESS(nt_set_context(thandle, cxt))) {
                display_error("SetThreadContext failed");
                goto error;
            }
        }

        success = TRUE;
    }
    error:
        /* we do not recover any changes in the child's address space */

    return success;
}
Exemple #15
0
static UINT32 ipc_get_message_array_list_size(UINT32 number_of_host_processors) 
{
    return (UINT32) ALIGN_FORWARD(array_list_memory_size( NULL, sizeof(IPC_MESSAGE), 
                        ipc_get_max_pending_messages(number_of_host_processors), 
                        IPC_ALIGNMENT), IPC_ALIGNMENT);
}
Exemple #16
0
bool
compare_pages(void *drcontext, byte *start1, byte *start2, uint start_offset)
{
    static byte copy_buf1_i[2*PAGE_SIZE+100];
    static byte copy_buf2_i[2*PAGE_SIZE+100];
    static byte buf1_i[2*PAGE_SIZE+100];
    static byte buf2_i[2*PAGE_SIZE+100];
    
    byte *copy1 = (byte *)ALIGN_FORWARD(copy_buf1_i, PAGE_SIZE);
    byte *copy2 = (byte *)ALIGN_FORWARD(copy_buf2_i, PAGE_SIZE);
    byte *buf1 = (byte *)ALIGN_FORWARD(buf1_i, PAGE_SIZE);
    byte *buf2 = (byte *)ALIGN_FORWARD(buf2_i, PAGE_SIZE);

    byte *p1 = copy1+start_offset, *p2 = copy2+start_offset;
    byte *b1 = buf1, *c1 = buf1, *b2 = buf2, *c2 = buf2;

    int skipped_bytes1 = 0, skipped_identical_bytes1 = 0;
    int skipped_bytes2 = 0, skipped_identical_bytes2 = 0;

    /* we make a copy (zero extend the page) for decode to avoid walking to next,
     * potentially invalid page */
    memcpy(copy1, start1, PAGE_SIZE);
    memcpy(copy2, start2, PAGE_SIZE);

    /* Note - we do the compare ~1 instruction at a time, would be more effiecient
     * to do the whole page and compare, but this makes it easier to track down where
     * the differences originate from. */

    while (p1 < copy1 + PAGE_SIZE) {
        /* The idea is to do a lightweight decoding of the page and eliminate likely
         * relocations from the instruction stream.  I expect that relocations within
         * the stream to be 4-byte immeds or 4-byte displacements with pointer like
         * values.  For now just using decode_sizeof to get the size of the instuction
         * and based on that determine how much to chop off the end (instruction format
         * is [...][disp][imm]) to remove the potential relocation.  With better 
         * information from decode_sizeof (it knows whether an immed/disp is present or
         * not and what offset it would be etc.) we could keep more of the bytes but
         * this works for testing. What we'll miss unless we get really lucky is 
         * relocs in read only data (const string arrays, for dr the const decode
         * tables full of pointers for ex.). */

        /* How the assumptions work out.  The assumption that we quickly get to the
         * appropriate instruction frame seems valid.  Most cases we synchronize very
         * quickly, usually just a couple of bytes and very rarely more then 20. 
         * I Haven't seen any relocations in instructions that weren't caught
         * below.  However, so far only matching ~60% of sibling pages because of
         * read only data relocations interspersed in the text sections. Instruction
         * frame alignment isn't an issue that often and the second pass is catching
         * most of those. */

        while (p1 - copy1 <= p2 - copy2) {
            uint num_bytes, i, num_prefix = 0;
            uint size = decode_sizeof(drcontext, p1, &num_prefix);
            size -= num_prefix;
            num_bytes = num_prefix;
            if (size == 0) {
                size = 1; /* treat invalid as size == 1 */
                num_bytes += 1;
            } else if (size <= 4) {
                num_bytes += size; /* no 4-byte disp or imm */
            } else if (size <= 6 ) {
                num_bytes += size - 4; /* could have 4-byte disp or immed */ 
            } else if (size <= 7) {
                num_bytes += size - 5; /* could have 4-byte disp and upto 1-byte immed
                                        * or 4-byte immed */
            } else if (size <= 9) {
                num_bytes += size - 6; /* could have 4-byte disp and upto 2-byte immed
                                        * or 4-byte immed */
            } else {
                num_bytes += size - 8; /* could have 4-byte disp and 4-byte immed */
            }
            for (i = 0; i < num_bytes; i++)
                *b1++ = *p1++;
            skipped_bytes1 += size - (num_bytes - num_prefix);
            for (i = 0; i < size - (num_bytes - num_prefix); i++) {
                if (*p1 == *(copy2+(p1-copy1)))
                    skipped_identical_bytes1++;
                p1++;
            }
        }

        while (p2 - copy2 < p1 - copy1) {
            uint num_bytes, i, num_prefix = 0;
            uint size = decode_sizeof(drcontext, p2, &num_prefix);
            size -= num_prefix;
            num_bytes = num_prefix;
            if (size == 0) {
                size = 1; /* treat invalid as size == 1 */
                num_bytes += 1;
            } else if (size <= 4) {
                num_bytes += size;
            } else if (size <=6 ) {
                num_bytes += size - 4;
            } else if (size <= 7) {
                num_bytes += size - 5;
            } else if (size <= 9) {
                num_bytes += size - 6;
            } else {
                num_bytes += size - 8;
            }
            for (i = 0; i < num_bytes; i++)
                *b2++ = *p2++;
            skipped_bytes2 += size - (num_bytes - num_prefix);
            for (i = 0; i < size - (num_bytes - num_prefix); i++) {
                if (*p2 == *(copy1+(p2-copy2)))
                    skipped_identical_bytes2++;
                p2++;
            }
        }

        /* Do check */
        while (c1 < b1 && c2 < b2) {
            if (*c1++ != *c2++) {
                VVERBOSE_PRINT("Mismatch found near offset 0x%04x of page %08x\n",
                               p1 - copy1, start1);
                return false;
            }
        }
    }
    ASSERT(skipped_bytes1 == skipped_bytes2);
    ASSERT(skipped_identical_bytes1 == skipped_identical_bytes2);
    VVERBOSE_PRINT("Match found! skipped=%d skipped_identical=%d\n",
                   skipped_bytes1, skipped_identical_bytes1);
    return true;
}
void *
privload_tls_init(void *app_tls)
{
    void *res;
    /* We have to exactly duplicate the offset of key fields in Android's
     * pthread_internal_t struct.
     */
    ASSERT(PTHREAD_TLS_OFFS == offsetof(android_pthread_internal_t, tls));
    ASSERT(DR_TLS_BASE_OFFSET == offsetof(android_pthread_internal_t, dr_tls_base) -
           PTHREAD_TLS_OFFS /* the self slot */);

    if (!dynamo_initialized) {
        char **e;
        /* We have to duplicate the pthread setup that the Android loader does.
         * We expect app_tls to be either NULL or garbage, as we have early injection.
         */
        init_thread.tid = dynamorio_syscall(SYS_set_tid_address, 1, &init_thread.tid);
        init_thread.cached_pid_ = init_thread.tid;

        /* init_thread.attr is set to all 0 (sched is SCHED_NORMAL==0, and sizes are
         * zeroed out)
         */

        /* init_thread.join_state is set to 0 (THREAD_NOT_JOINED) */

        init_thread.tls[ANDROID_TLS_SLOT_SELF] = init_thread.tls;
        init_thread.tls[ANDROID_TLS_SLOT_THREAD_ID] = &init_thread;
        /* tls[TLS_SLOT_STACK_GUARD] is set to 0 */

        /* Set up the data struct pointing at kernel args that Bionic expects */
        kernel_args.argc = *(int *)kernel_init_sp;
        kernel_args.argv = (char **)kernel_init_sp + 1;
        kernel_args.envp = kernel_args.argv + kernel_args.argc + 1;
        /* The aux vector is after the last environment pointer. */
        for (e = kernel_args.envp; *e != NULL; e++)
            ; /* nothing */
        kernel_args.auxv = (ELF_AUXV_TYPE *)(e + 1);
        init_thread.tls[ANDROID_TLS_SLOT_BIONIC_PREINIT] = &kernel_args;

        /* We use our own alternate signal stack */

        LOG(GLOBAL, LOG_LOADER, 2, "%s: kernel sp is "PFX"; TLS set to "PFX"\n",
            __FUNCTION__, init_thread.tls[ANDROID_TLS_SLOT_BIONIC_PREINIT],
            init_thread.tls[ANDROID_TLS_SLOT_SELF]);

        res = init_thread.tls[ANDROID_TLS_SLOT_SELF];
    } else {
        android_pthread_internal_t *thrd;
        res = heap_mmap(ALIGN_FORWARD(sizeof(android_pthread_internal_t), PAGE_SIZE));
        LOG(GLOBAL, LOG_LOADER, 2, "%s: allocated new TLS at "PFX"; copying from "PFX"\n",
            __FUNCTION__, res, app_tls);
        if (app_tls != NULL)
            memcpy(res, app_tls, sizeof(android_pthread_internal_t));
        thrd = (android_pthread_internal_t *) res;
        thrd->tls[ANDROID_TLS_SLOT_SELF] = thrd->tls;
        thrd->tls[ANDROID_TLS_SLOT_THREAD_ID] = thrd;
        thrd->tid = get_thread_id();
        thrd->dr_tls_base = NULL;
        res = thrd->tls[ANDROID_TLS_SLOT_SELF];
        LOG(GLOBAL, LOG_LOADER, 2, "%s: TLS set to "PFX"\n",
            __FUNCTION__, thrd->tls[ANDROID_TLS_SLOT_SELF]);
    }

    /* Android does not yet support per-module TLS */

    return res;
}
Exemple #18
0
/* callback for dl_iterate_phdr() for adding existing modules to our lists */
static int
dl_iterate_get_areas_cb(struct dl_phdr_info *info, size_t size, void *data)
{
    int *count = (int *)data;
    uint i;
    /* see comments in dl_iterate_get_path_cb() */
    app_pc modend;
    app_pc min_vaddr = module_vaddr_from_prog_header((app_pc)info->dlpi_phdr,
                                                     info->dlpi_phnum, NULL, &modend);
    app_pc modbase = info->dlpi_addr + min_vaddr;
    size_t modsize = modend - min_vaddr;
    LOG(GLOBAL, LOG_VMAREAS, 2,
        "dl_iterate_get_areas_cb: addr=" PFX " hdrs=" PFX " base=" PFX " name=%s\n",
        info->dlpi_addr, info->dlpi_phdr, modbase, info->dlpi_name);
    ASSERT(info->dlpi_phnum == module_num_program_headers(modbase));

    ASSERT(count != NULL);
    if (*count == 0) {
        /* since we don't get a name for the executable, for now we
         * assume that the first iter is the executable itself.
         * XXX: this seems to hold, but there's no guarantee: can we do better?
         */
        executable_start = modbase;
    }

#ifndef X64
    if (modsize == PAGE_SIZE && info->dlpi_name[0] == '\0') {
        /* Candidate for VDSO.  Xref PR 289138 on using AT_SYSINFO to locate. */
        /* Xref VSYSCALL_PAGE_START_HARDCODED but later linuxes randomize */
        char *soname;
        if (module_walk_program_headers(modbase, modsize, false,
                                        true, /* i#1589: ld.so relocated .dynamic */
                                        NULL, NULL, NULL, &soname, NULL) &&
            strncmp(soname, VSYSCALL_PAGE_SO_NAME, strlen(VSYSCALL_PAGE_SO_NAME)) == 0) {
            ASSERT(!dynamo_initialized); /* .data should be +w */
            ASSERT(vsyscall_page_start == NULL);
            vsyscall_page_start = modbase;
            LOG(GLOBAL, LOG_VMAREAS, 1, "found vsyscall page @ " PFX "\n",
                vsyscall_page_start);
        }
    }
#endif
    if (modbase != vsyscall_page_start)
        module_list_add(modbase, modsize, false, info->dlpi_name, 0 /*don't have inode*/);

    for (i = 0; i < info->dlpi_phnum; i++) {
        app_pc start, end;
        uint prot;
        size_t align;
        if (module_read_program_header(modbase, i, &start, &end, &prot, &align)) {
            start += info->dlpi_addr;
            end += info->dlpi_addr;
            LOG(GLOBAL, LOG_VMAREAS, 2, "\tsegment %d: " PFX "-" PFX " %s align=%d\n", i,
                start, end, memprot_string(prot), align);
            start = (app_pc)ALIGN_BACKWARD(start, PAGE_SIZE);
            end = (app_pc)ALIGN_FORWARD(end, PAGE_SIZE);
            LOG(GLOBAL, LOG_VMAREAS, 4,
                "find_executable_vm_areas: adding: " PFX "-" PFX " prot=%d\n", start, end,
                prot);
            all_memory_areas_lock();
            update_all_memory_areas(start, end, prot, DR_MEMTYPE_IMAGE);
            all_memory_areas_unlock();
            if (app_memory_allocation(NULL, start, end - start, prot,
                                      true /*image*/
                                      _IF_DEBUG("ELF SO")))
                (*count)++;
        }
    }
    return 0; /* keep iterating */
}
// init memory layout
// This function should perform init of "memory layout object" and
// init the primary guest memory layout.
// In the case of no secondary guests, memory layout object is not required
//
// For primary guest:
//   - All memory upto 4G is mapped, except for VMM and secondary guest areas
//   - Only specified memory above 4G is mapped. Mapping in the >4G region for primary
//     guest should be added by demand
//
// For secondary guests:
//   - All secondary guests are loaded lower than 4G
BOOLEAN init_memory_layout_from_mbr(
#if 0
                    // JLM(FIX)
                    int num_excluded
#endif
                    const VMM_MEMORY_LAYOUT* vmm_memory_layout,
                    GPM_HANDLE primary_guest_gpm, BOOLEAN are_secondary_guests_exist,
                    const VMM_APPLICATION_PARAMS_STRUCT* application_params)
{
    E820_ABSTRACTION_RANGE_ITERATOR         e820_iter;
    const INT15_E820_MEMORY_MAP_ENTRY_EXT*  e820_entry = NULL;
    BOOLEAN                                 ok;
    UINT64                                  range_start;
    UINT64                                  range_end;
    INT15_E820_RANGE_TYPE                   range_type;
    INT15_E820_MEMORY_MAP_EXT_ATTRIBUTES    range_attr;
    UINT64                                  page_index;
    UINT64                                 *entry_list;

    // BEFORE_VMLAUNCH. CRITICAL check that should not fail.
    VMM_ASSERT(e820_abstraction_is_initialized());

    if (global_policy_uses_vtlb()) {
        mam_rwx_attrs.uint32 = 0x5;
        mam_rw_attrs.uint32 = 0x1;
        mam_ro_attrs.uint32= 0x0;
     }

    // 1. first map 0-4G host region to primary guest
    ok = gpm_add_mapping( primary_guest_gpm, 0, 0, FOUR_GIGABYTE, mam_rwx_attrs );
    VMM_LOG(mask_anonymous, level_trace,"Primary guest GPM: add 0-4G region\r\n");
    // BEFORE_VMLAUNCH. CRITICAL check that should not fail.
    VMM_ASSERT( ok == TRUE );

    // 2. Add real memory to "memory layout object" and to the primary guest
    //    if this memory range is above 4G
    // if in the post launch mode skip it
    for (e820_iter = e820_abstraction_iterator_get_first(E820_ORIGINAL_MAP);
        e820_iter != E820_ABSTRACTION_NULL_ITERATOR;
        e820_iter = e820_abstraction_iterator_get_next(E820_ORIGINAL_MAP, e820_iter)) {
        e820_entry = e820_abstraction_iterator_get_range_details(e820_iter);

        range_start = e820_entry->basic_entry.base_address;
        range_end   = range_start + e820_entry->basic_entry.length;
        range_type  = e820_entry->basic_entry.address_range_type;
        range_attr  = e820_entry->extended_attributes;

        // align ranges and sizes on 4K boundaries
        range_start = ALIGN_FORWARD(range_start, PAGE_4KB_SIZE);
        range_end   = ALIGN_BACKWARD(range_end, PAGE_4KB_SIZE);

        VMM_DEBUG_CODE({
            if (range_start != e820_entry->basic_entry.base_address) {
                VMM_LOG(mask_anonymous, level_trace,"init_memory_layout_from_mbr WARNING: aligning E820 range start from %P to %P\n",
                    e820_entry->basic_entry.base_address, range_start);
                }

            if (range_end != e820_entry->basic_entry.base_address + e820_entry->basic_entry.length) {
                    VMM_LOG(mask_anonymous, level_trace,"init_memory_layout_from_mbr WARNING: aligning E820 range end from %P to %P\n",
                        e820_entry->basic_entry.base_address+e820_entry->basic_entry.length,
                        range_end);
                    }
            })

        if (range_end <= range_start) {
            // after alignment the range became invalid
            VMM_LOG(mask_anonymous, level_trace,"init_memory_layout_from_mbr WARNING: skipping invalid E820 memory range FROM %P to %P\n",
                 range_start, range_end);
            continue;
        }

        // add memory to the "memory layout object" if this is a real memory
        // lower 4G
        if (are_secondary_guests_exist && (range_start < FOUR_GIGABYTE) &&
            range_attr.Bits.enabled && (!range_attr.Bits.non_volatile)) {
            UINT64 top = (range_end < FOUR_GIGABYTE) ? range_end : FOUR_GIGABYTE;
	    (void)top;
            if ((range_type == INT15_E820_ADDRESS_RANGE_TYPE_MEMORY) ||
                (range_type == INT15_E820_ADDRESS_RANGE_TYPE_ACPI)) {
                // here we need to all a call to the "memory layout object"
                // to fill is with the range_start-top range
                // to make compiler happy
                top = 0;
            }
        }

        // add memory to the primary guest if this is a memory above 4G
        if (range_end > FOUR_GIGABYTE) {
            UINT64 bottom = (range_start < FOUR_GIGABYTE) ? FOUR_GIGABYTE : range_start;

            if (bottom < range_end) {
                VMM_LOG(mask_anonymous, level_trace,"Primary guest GPM: add memory above 4GB base %p size %p\r\n",
                        bottom, range_end - bottom);
                ok = gpm_add_mapping( primary_guest_gpm, bottom, bottom, range_end - bottom, mam_rwx_attrs );
                // BEFORE_VMLAUNCH. CRITICAL check that should not fail.
                VMM_ASSERT( ok == TRUE );
            }
        }
    }