|
@@ -1,12 +1,11 @@
|
|
/* vi: set sw=4 ts=4: */
|
|
/* vi: set sw=4 ts=4: */
|
|
-/* Program to load an ELF binary on a linux system, and run it
|
|
|
|
|
|
+/*
|
|
|
|
+ * Program to load an ELF binary on a linux system, and run it
|
|
* after resolving ELF shared library symbols
|
|
* after resolving ELF shared library symbols
|
|
*
|
|
*
|
|
- * Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald,
|
|
|
|
|
|
+ * Copyright (C) 2000-2004 by Erik Andersen <andersen@codpoet.org>
|
|
|
|
+ * Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald,
|
|
* David Engel, Hongjiu Lu and Mitch D'Souza
|
|
* David Engel, Hongjiu Lu and Mitch D'Souza
|
|
- * Copyright (C) 2001-2002, Erik Andersen
|
|
|
|
- *
|
|
|
|
- * All rights reserved.
|
|
|
|
*
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* modification, are permitted provided that the following conditions
|
|
@@ -30,621 +29,67 @@
|
|
* SUCH DAMAGE.
|
|
* SUCH DAMAGE.
|
|
*/
|
|
*/
|
|
|
|
|
|
-// Support a list of library preloads in /etc/ld.so.preload
|
|
|
|
-//#define SUPPORT_LDSO_PRELOAD_FILE
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-/* Disclaimer: I have never seen any AT&T source code for SVr4, nor have
|
|
|
|
- I ever taken any courses on internals. This program was developed using
|
|
|
|
- information available through the book "UNIX SYSTEM V RELEASE 4,
|
|
|
|
- Programmers guide: Ansi C and Programming Support Tools", which did
|
|
|
|
- a more than adequate job of explaining everything required to get this
|
|
|
|
- working. */
|
|
|
|
-
|
|
|
|
-/*
|
|
|
|
- * The main trick with this program is that initially, we ourselves are
|
|
|
|
- * not dynamicly linked. This means that we cannot access any global
|
|
|
|
- * variables or call any functions. No globals initially, since the
|
|
|
|
- * Global Offset Table (GOT) is initialized by the linker assuming a
|
|
|
|
- * virtual address of 0, and no function calls initially since the
|
|
|
|
- * Procedure Linkage Table (PLT) is not yet initialized.
|
|
|
|
- *
|
|
|
|
- * There are additional initial restrictions - we cannot use large
|
|
|
|
- * switch statements, since the compiler generates tables of addresses
|
|
|
|
- * and jumps through them. We can use inline functions, because these
|
|
|
|
- * do not transfer control to a new address, but they must be static so
|
|
|
|
- * that they are not exported from the modules. We cannot use normal
|
|
|
|
- * syscall stubs, because these all reference the errno global variable
|
|
|
|
- * which is not yet initialized. We can use all of the local stack
|
|
|
|
- * variables that we want.
|
|
|
|
- *
|
|
|
|
- * Life is further complicated by the fact that initially we do not
|
|
|
|
- * want to do a complete dynamic linking. We want to allow the user to
|
|
|
|
- * supply new functions to override symbols (i.e. weak symbols and/or
|
|
|
|
- * LD_PRELOAD). So initially, we only perform relocations for
|
|
|
|
- * variables that start with "_dl_" since ANSI specifies that the user
|
|
|
|
- * is not supposed to redefine any of these variables.
|
|
|
|
- *
|
|
|
|
- * Fortunately, the linker itself leaves a few clues lying around, and
|
|
|
|
- * when the kernel starts the image, there are a few further clues.
|
|
|
|
- * First of all, there is Auxiliary Vector Table information sitting on
|
|
|
|
- * which is provided to us by the kernel, and which includes
|
|
|
|
- * information about the load address that the program interpreter was
|
|
|
|
- * loaded at, the number of sections, the address the application was
|
|
|
|
- * loaded at and so forth. Here this information is stored in the
|
|
|
|
- * array auxvt. For details see linux/fs/binfmt_elf.c where it calls
|
|
|
|
- * NEW_AUX_ENT() a bunch of time....
|
|
|
|
- *
|
|
|
|
- * Next, we need to find the GOT. On most arches there is a register
|
|
|
|
- * pointing to the GOT, but just in case (and for new ports) I've added
|
|
|
|
- * some (slow) C code to locate the GOT for you.
|
|
|
|
- *
|
|
|
|
- * This code was originally written for SVr4, and there the kernel
|
|
|
|
- * would load all text pages R/O, so they needed to call mprotect a
|
|
|
|
- * zillion times to mark all text pages as writable so dynamic linking
|
|
|
|
- * would succeed. Then when they were done, they would change the
|
|
|
|
- * protections for all the pages back again. Well, under Linux
|
|
|
|
- * everything is loaded writable (since Linux does copy on write
|
|
|
|
- * anyways) so all the mprotect stuff has been disabled.
|
|
|
|
- *
|
|
|
|
- * Initially, we do not have access to _dl_malloc since we can't yet
|
|
|
|
- * make function calls, so we mmap one page to use as scratch space.
|
|
|
|
- * Later on, when we can call _dl_malloc we reuse this this memory.
|
|
|
|
- * This is also beneficial, since we do not want to use the same memory
|
|
|
|
- * pool as malloc anyway - esp if the user redefines malloc to do
|
|
|
|
- * something funky.
|
|
|
|
- *
|
|
|
|
- * Our first task is to perform a minimal linking so that we can call
|
|
|
|
- * other portions of the dynamic linker. Once we have done this, we
|
|
|
|
- * then build the list of modules that the application requires, using
|
|
|
|
- * LD_LIBRARY_PATH if this is not a suid program (/usr/lib otherwise).
|
|
|
|
- * Once this is done, we can do the dynamic linking as required, and we
|
|
|
|
- * must omit the things we did to get the dynamic linker up and running
|
|
|
|
- * in the first place. After we have done this, we just have a few
|
|
|
|
- * housekeeping chores and we can transfer control to the user's
|
|
|
|
- * application.
|
|
|
|
- */
|
|
|
|
|
|
|
|
#include "ldso.h"
|
|
#include "ldso.h"
|
|
|
|
|
|
-
|
|
|
|
#define ALLOW_ZERO_PLTGOT
|
|
#define ALLOW_ZERO_PLTGOT
|
|
|
|
|
|
-/* Some arches may need to override this in boot1_arch.h */
|
|
|
|
-#define ELFMAGIC ELFMAG
|
|
|
|
|
|
+/* Pull in the value of _dl_progname */
|
|
|
|
+#include "_dl_progname.h"
|
|
|
|
+
|
|
|
|
+/* Global variables used within the shared library loader */
|
|
|
|
+char *_dl_library_path = 0; /* Where we look for libraries */
|
|
|
|
+char *_dl_preload = 0; /* Things to be loaded before the libs */
|
|
|
|
+char *_dl_ldsopath = 0; /* Location of the shared lib loader */
|
|
|
|
+unsigned char *_dl_malloc_addr = 0; /* Lets _dl_malloc use the already allocated memory page */
|
|
|
|
+unsigned char *_dl_mmap_zero = 0; /* Also used by _dl_malloc */
|
|
|
|
+unsigned long *_dl_brkp = 0; /* The end of the data segment for brk and sbrk */
|
|
|
|
+unsigned long *_dl_envp = 0; /* The environment address */
|
|
|
|
+int _dl_secure = 1; /* Are we dealing with setuid stuff? */
|
|
|
|
+
|
|
|
|
|
|
-/* This is a poor man's malloc, used prior to resolving our internal poor man's malloc */
|
|
|
|
-#define LD_MALLOC(SIZE) ((void *) (malloc_buffer += SIZE, malloc_buffer - SIZE)) ; REALIGN();
|
|
|
|
-/*
|
|
|
|
- * Make sure that the malloc buffer is aligned on 4 byte boundary. For 64 bit
|
|
|
|
- * platforms we may need to increase this to 8, but this is good enough for
|
|
|
|
- * now. This is typically called after LD_MALLOC.
|
|
|
|
- */
|
|
|
|
-#define REALIGN() malloc_buffer = (unsigned char *) (((unsigned long) malloc_buffer + 3) & ~(3))
|
|
|
|
|
|
|
|
-char *_dl_library_path = 0; /* Where we look for libraries */
|
|
|
|
-char *_dl_preload = 0; /* Things to be loaded before the libs. */
|
|
|
|
-char *_dl_ldsopath = 0;
|
|
|
|
#ifdef __SUPPORT_LD_DEBUG__
|
|
#ifdef __SUPPORT_LD_DEBUG__
|
|
-char *_dl_debug = 0;
|
|
|
|
-char *_dl_debug_symbols = 0;
|
|
|
|
-char *_dl_debug_move = 0;
|
|
|
|
-char *_dl_debug_reloc = 0;
|
|
|
|
-char *_dl_debug_detail = 0;
|
|
|
|
|
|
+char *_dl_debug = 0;
|
|
|
|
+char *_dl_debug_symbols = 0;
|
|
|
|
+char *_dl_debug_move = 0;
|
|
|
|
+char *_dl_debug_reloc = 0;
|
|
|
|
+char *_dl_debug_detail = 0;
|
|
char *_dl_debug_nofixups = 0;
|
|
char *_dl_debug_nofixups = 0;
|
|
char *_dl_debug_bindings = 0;
|
|
char *_dl_debug_bindings = 0;
|
|
-int _dl_debug_file = 2;
|
|
|
|
-#else
|
|
|
|
-#define _dl_debug_file 2
|
|
|
|
-#endif
|
|
|
|
-static unsigned char *_dl_malloc_addr, *_dl_mmap_zero;
|
|
|
|
-
|
|
|
|
-static int _dl_secure = 0;
|
|
|
|
-static int (*_dl_elf_main) (int, char **, char **);
|
|
|
|
-struct r_debug *_dl_debug_addr = NULL;
|
|
|
|
-unsigned long *_dl_brkp;
|
|
|
|
-unsigned long *_dl_envp;
|
|
|
|
-int _dl_fixup(struct dyn_elf *rpnt, int flag);
|
|
|
|
-void _dl_debug_state(void);
|
|
|
|
-char *_dl_get_last_path_component(char *path);
|
|
|
|
-
|
|
|
|
-#include "boot1_arch.h"
|
|
|
|
-#include "_dl_progname.h" /* Pull in the value of _dl_progname */
|
|
|
|
-
|
|
|
|
-/* When we enter this piece of code, the program stack looks like this:
|
|
|
|
- argc argument counter (integer)
|
|
|
|
- argv[0] program name (pointer)
|
|
|
|
- argv[1...N] program args (pointers)
|
|
|
|
- argv[argc-1] end of args (integer)
|
|
|
|
- NULL
|
|
|
|
- env[0...N] environment variables (pointers)
|
|
|
|
- NULL
|
|
|
|
- auxvt[0...N] Auxiliary Vector Table elements (mixed types)
|
|
|
|
-*/
|
|
|
|
-
|
|
|
|
-LD_BOOT(unsigned long args) __attribute__ ((unused));
|
|
|
|
-LD_BOOT(unsigned long args)
|
|
|
|
-{
|
|
|
|
- unsigned int argc;
|
|
|
|
- char **argv, **envp;
|
|
|
|
- unsigned long load_addr;
|
|
|
|
- unsigned long *got;
|
|
|
|
- unsigned long *aux_dat;
|
|
|
|
- int goof = 0;
|
|
|
|
- ElfW(Ehdr) *header;
|
|
|
|
- struct elf_resolve *tpnt;
|
|
|
|
- struct elf_resolve *app_tpnt;
|
|
|
|
- Elf32_auxv_t auxvt[AT_EGID + 1];
|
|
|
|
- unsigned char *malloc_buffer, *mmap_zero;
|
|
|
|
- Elf32_Dyn *dpnt;
|
|
|
|
- unsigned long *hash_addr;
|
|
|
|
- struct r_debug *debug_addr = NULL;
|
|
|
|
- int indx;
|
|
|
|
- int status;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- /* WARNING! -- we cannot make _any_ funtion calls until we have
|
|
|
|
- * taken care of fixing up our own relocations. Making static
|
|
|
|
- * inline calls is ok, but _no_ function calls. Not yet
|
|
|
|
- * anyways. */
|
|
|
|
-
|
|
|
|
- /* First obtain the information on the stack that tells us more about
|
|
|
|
- what binary is loaded, where it is loaded, etc, etc */
|
|
|
|
- GET_ARGV(aux_dat, args);
|
|
|
|
-#if defined (__arm__) || defined (__mips__) || defined (__cris__)
|
|
|
|
- aux_dat += 1;
|
|
|
|
-#endif
|
|
|
|
- argc = *(aux_dat - 1);
|
|
|
|
- argv = (char **) aux_dat;
|
|
|
|
- aux_dat += argc; /* Skip over the argv pointers */
|
|
|
|
- aux_dat++; /* Skip over NULL at end of argv */
|
|
|
|
- envp = (char **) aux_dat;
|
|
|
|
- while (*aux_dat)
|
|
|
|
- aux_dat++; /* Skip over the envp pointers */
|
|
|
|
- aux_dat++; /* Skip over NULL at end of envp */
|
|
|
|
-
|
|
|
|
- /* Place -1 here as a checkpoint. We later check if it was changed
|
|
|
|
- * when we read in the auxvt */
|
|
|
|
- auxvt[AT_UID].a_type = -1;
|
|
|
|
-
|
|
|
|
- /* The junk on the stack immediately following the environment is
|
|
|
|
- * the Auxiliary Vector Table. Read out the elements of the auxvt,
|
|
|
|
- * sort and store them in auxvt for later use. */
|
|
|
|
- while (*aux_dat) {
|
|
|
|
- Elf32_auxv_t *auxv_entry = (Elf32_auxv_t *) aux_dat;
|
|
|
|
-
|
|
|
|
- if (auxv_entry->a_type <= AT_EGID) {
|
|
|
|
- _dl_memcpy(&(auxvt[auxv_entry->a_type]), auxv_entry, sizeof(Elf32_auxv_t));
|
|
|
|
- }
|
|
|
|
- aux_dat += 2;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /* locate the ELF header. We need this done as soon as possible
|
|
|
|
- * (esp since SEND_STDERR() needs this on some platforms... */
|
|
|
|
- load_addr = auxvt[AT_BASE].a_un.a_val;
|
|
|
|
- header = (ElfW(Ehdr) *) auxvt[AT_BASE].a_un.a_ptr;
|
|
|
|
-
|
|
|
|
- /* Check the ELF header to make sure everything looks ok. */
|
|
|
|
- if (!header || header->e_ident[EI_CLASS] != ELFCLASS32 ||
|
|
|
|
- header->e_ident[EI_VERSION] != EV_CURRENT
|
|
|
|
-#if !defined(__powerpc__) && !defined(__mips__) && !defined(__sh__)
|
|
|
|
- || _dl_strncmp((void *) header, ELFMAGIC, SELFMAG) != 0
|
|
|
|
-#else
|
|
|
|
- || header->e_ident[EI_MAG0] != ELFMAG0
|
|
|
|
- || header->e_ident[EI_MAG1] != ELFMAG1
|
|
|
|
- || header->e_ident[EI_MAG2] != ELFMAG2
|
|
|
|
- || header->e_ident[EI_MAG3] != ELFMAG3
|
|
|
|
-#endif
|
|
|
|
- ) {
|
|
|
|
- SEND_STDERR("Invalid ELF header\n");
|
|
|
|
- _dl_exit(0);
|
|
|
|
- }
|
|
|
|
-#ifdef __SUPPORT_LD_DEBUG_EARLY__
|
|
|
|
- SEND_STDERR("ELF header=");
|
|
|
|
- SEND_ADDRESS_STDERR(load_addr, 1);
|
|
|
|
-#endif
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- /* Locate the global offset table. Since this code must be PIC
|
|
|
|
- * we can take advantage of the magic offset register, if we
|
|
|
|
- * happen to know what that is for this architecture. If not,
|
|
|
|
- * we can always read stuff out of the ELF file to find it... */
|
|
|
|
-#if defined(__i386__)
|
|
|
|
- __asm__("\tmovl %%ebx,%0\n\t":"=a"(got));
|
|
|
|
-#elif defined(__m68k__)
|
|
|
|
- __asm__("movel %%a5,%0":"=g"(got));
|
|
|
|
-#elif defined(__sparc__)
|
|
|
|
- __asm__("\tmov %%l7,%0\n\t":"=r"(got));
|
|
|
|
-#elif defined(__arm__)
|
|
|
|
- __asm__("\tmov %0, r10\n\t":"=r"(got));
|
|
|
|
-#elif defined(__powerpc__)
|
|
|
|
- __asm__("\tbl _GLOBAL_OFFSET_TABLE_-4@local\n\t":"=l"(got));
|
|
|
|
-#elif defined(__mips__)
|
|
|
|
- __asm__("\tmove %0, $28\n\tsubu %0,%0,0x7ff0\n\t":"=r"(got));
|
|
|
|
-#elif defined(__sh__) && !defined(__SH5__)
|
|
|
|
- __asm__(
|
|
|
|
-" mov.l 1f, %0\n"
|
|
|
|
-" mova 1f, r0\n"
|
|
|
|
-" bra 2f\n"
|
|
|
|
-" add r0, %0\n"
|
|
|
|
-" .balign 4\n"
|
|
|
|
-"1: .long _GLOBAL_OFFSET_TABLE_\n"
|
|
|
|
-"2:" : "=r" (got) : : "r0");
|
|
|
|
-#elif defined(__cris__)
|
|
|
|
- __asm__("\tmove.d $pc,%0\n\tsub.d .:GOTOFF,%0\n\t":"=r"(got));
|
|
|
|
-#else
|
|
|
|
- /* Do things the slow way in C */
|
|
|
|
- {
|
|
|
|
- unsigned long tx_reloc;
|
|
|
|
- Elf32_Dyn *dynamic = NULL;
|
|
|
|
- Elf32_Shdr *shdr;
|
|
|
|
- Elf32_Phdr *pt_load;
|
|
|
|
-
|
|
|
|
-#ifdef __SUPPORT_LD_DEBUG_EARLY__
|
|
|
|
- SEND_STDERR("Finding the GOT using C code to read the ELF file\n");
|
|
|
|
-#endif
|
|
|
|
- /* Find where the dynamic linking information section is hiding */
|
|
|
|
- shdr = (Elf32_Shdr *) (header->e_shoff + (char *) header);
|
|
|
|
- for (indx = header->e_shnum; --indx >= 0; ++shdr) {
|
|
|
|
- if (shdr->sh_type == SHT_DYNAMIC) {
|
|
|
|
- goto found_dynamic;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- SEND_STDERR("missing dynamic linking information section \n");
|
|
|
|
- _dl_exit(0);
|
|
|
|
-
|
|
|
|
- found_dynamic:
|
|
|
|
- dynamic = (Elf32_Dyn *) (shdr->sh_offset + (char *) header);
|
|
|
|
-
|
|
|
|
- /* Find where PT_LOAD is hiding */
|
|
|
|
- pt_load = (Elf32_Phdr *) (header->e_phoff + (char *) header);
|
|
|
|
- for (indx = header->e_phnum; --indx >= 0; ++pt_load) {
|
|
|
|
- if (pt_load->p_type == PT_LOAD) {
|
|
|
|
- goto found_pt_load;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- SEND_STDERR("missing loadable program segment\n");
|
|
|
|
- _dl_exit(0);
|
|
|
|
-
|
|
|
|
- found_pt_load:
|
|
|
|
- /* Now (finally) find where DT_PLTGOT is hiding */
|
|
|
|
- tx_reloc = pt_load->p_vaddr - pt_load->p_offset;
|
|
|
|
- for (; DT_NULL != dynamic->d_tag; ++dynamic) {
|
|
|
|
- if (dynamic->d_tag == DT_PLTGOT) {
|
|
|
|
- goto found_got;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- SEND_STDERR("missing global offset table\n");
|
|
|
|
- _dl_exit(0);
|
|
|
|
-
|
|
|
|
- found_got:
|
|
|
|
- got = (unsigned long *) (dynamic->d_un.d_val - tx_reloc +
|
|
|
|
- (char *) header);
|
|
|
|
- }
|
|
|
|
-#endif
|
|
|
|
-
|
|
|
|
- /* Now, finally, fix up the location of the dynamic stuff */
|
|
|
|
- dpnt = (Elf32_Dyn *) (*got + load_addr);
|
|
|
|
-#ifdef __SUPPORT_LD_DEBUG_EARLY__
|
|
|
|
- SEND_STDERR("First Dynamic section entry=");
|
|
|
|
- SEND_ADDRESS_STDERR(dpnt, 1);
|
|
|
|
-#endif
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- /* Call mmap to get a page of writable memory that can be used
|
|
|
|
- * for _dl_malloc throughout the shared lib loader. */
|
|
|
|
- mmap_zero = malloc_buffer = _dl_mmap((void *) 0, PAGE_SIZE,
|
|
|
|
- PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
|
|
|
|
- if (_dl_mmap_check_error(mmap_zero)) {
|
|
|
|
- SEND_STDERR("dl_boot: mmap of a spare page failed!\n");
|
|
|
|
- _dl_exit(13);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- tpnt = LD_MALLOC(sizeof(struct elf_resolve));
|
|
|
|
- _dl_memset(tpnt, 0, sizeof(struct elf_resolve));
|
|
|
|
- app_tpnt = LD_MALLOC(sizeof(struct elf_resolve));
|
|
|
|
- _dl_memset(app_tpnt, 0, sizeof(struct elf_resolve));
|
|
|
|
-
|
|
|
|
-#ifdef __UCLIBC_PIE_SUPPORT__
|
|
|
|
- /* Find the runtime load address of the main executable, this may be
|
|
|
|
- * different from what the ELF header says for ET_DYN/PIE executables.
|
|
|
|
- */
|
|
|
|
- {
|
|
|
|
- ElfW(Phdr) *ppnt;
|
|
|
|
- int i;
|
|
|
|
-
|
|
|
|
- ppnt = (ElfW(Phdr) *) auxvt[AT_PHDR].a_un.a_ptr;
|
|
|
|
- for (i = 0; i < auxvt[AT_PHNUM].a_un.a_val; i++, ppnt++)
|
|
|
|
- if (ppnt->p_type == PT_PHDR) {
|
|
|
|
- app_tpnt->loadaddr = (ElfW(Addr)) (auxvt[AT_PHDR].a_un.a_val - ppnt->p_vaddr);
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-#ifdef __SUPPORT_LD_DEBUG_EARLY__
|
|
|
|
- SEND_STDERR("app_tpnt->loadaddr=");
|
|
|
|
- SEND_ADDRESS_STDERR(app_tpnt->loadaddr, 1);
|
|
|
|
-#endif
|
|
|
|
-#endif
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * This is used by gdb to locate the chain of shared libraries that are currently loaded.
|
|
|
|
- */
|
|
|
|
- debug_addr = LD_MALLOC(sizeof(struct r_debug));
|
|
|
|
- _dl_memset(debug_addr, 0, sizeof(struct r_debug));
|
|
|
|
-
|
|
|
|
- /* OK, that was easy. Next scan the DYNAMIC section of the image.
|
|
|
|
- We are only doing ourself right now - we will have to do the rest later */
|
|
|
|
-#ifdef __SUPPORT_LD_DEBUG_EARLY__
|
|
|
|
- SEND_STDERR("scanning DYNAMIC section\n");
|
|
|
|
-#endif
|
|
|
|
- while (dpnt->d_tag) {
|
|
|
|
-#if defined(__mips__)
|
|
|
|
- if (dpnt->d_tag == DT_MIPS_GOTSYM)
|
|
|
|
- tpnt->mips_gotsym = (unsigned long) dpnt->d_un.d_val;
|
|
|
|
- if (dpnt->d_tag == DT_MIPS_LOCAL_GOTNO)
|
|
|
|
- tpnt->mips_local_gotno = (unsigned long) dpnt->d_un.d_val;
|
|
|
|
- if (dpnt->d_tag == DT_MIPS_SYMTABNO)
|
|
|
|
- tpnt->mips_symtabno = (unsigned long) dpnt->d_un.d_val;
|
|
|
|
-#endif
|
|
|
|
- if (dpnt->d_tag < 24) {
|
|
|
|
- tpnt->dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
|
|
|
|
- if (dpnt->d_tag == DT_TEXTREL) {
|
|
|
|
- tpnt->dynamic_info[DT_TEXTREL] = 1;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- dpnt++;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- {
|
|
|
|
- ElfW(Phdr) *ppnt;
|
|
|
|
- int i;
|
|
|
|
-
|
|
|
|
- ppnt = (ElfW(Phdr) *) auxvt[AT_PHDR].a_un.a_ptr;
|
|
|
|
- for (i = 0; i < auxvt[AT_PHNUM].a_un.a_val; i++, ppnt++)
|
|
|
|
- if (ppnt->p_type == PT_DYNAMIC) {
|
|
|
|
-#ifndef __UCLIBC_PIE_SUPPORT__
|
|
|
|
- dpnt = (Elf32_Dyn *) ppnt->p_vaddr;
|
|
|
|
-#else
|
|
|
|
- dpnt = (Elf32_Dyn *) (ppnt->p_vaddr + app_tpnt->loadaddr);
|
|
|
|
-#endif
|
|
|
|
- while (dpnt->d_tag) {
|
|
|
|
-#if defined(__mips__)
|
|
|
|
- if (dpnt->d_tag == DT_MIPS_GOTSYM)
|
|
|
|
- app_tpnt->mips_gotsym =
|
|
|
|
- (unsigned long) dpnt->d_un.d_val;
|
|
|
|
- if (dpnt->d_tag == DT_MIPS_LOCAL_GOTNO)
|
|
|
|
- app_tpnt->mips_local_gotno =
|
|
|
|
- (unsigned long) dpnt->d_un.d_val;
|
|
|
|
- if (dpnt->d_tag == DT_MIPS_SYMTABNO)
|
|
|
|
- app_tpnt->mips_symtabno =
|
|
|
|
- (unsigned long) dpnt->d_un.d_val;
|
|
|
|
- if (dpnt->d_tag > DT_JMPREL) {
|
|
|
|
- dpnt++;
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
- app_tpnt->dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
|
|
|
|
-
|
|
|
|
-#warning "Debugging threads on mips won't work till someone fixes this..."
|
|
|
|
-#if 0
|
|
|
|
- if (dpnt->d_tag == DT_DEBUG) {
|
|
|
|
- dpnt->d_un.d_val = (unsigned long) debug_addr;
|
|
|
|
- }
|
|
|
|
-#endif
|
|
|
|
-
|
|
|
|
-#else
|
|
|
|
- if (dpnt->d_tag > DT_JMPREL) {
|
|
|
|
- dpnt++;
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
- app_tpnt->dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
|
|
|
|
- if (dpnt->d_tag == DT_DEBUG) {
|
|
|
|
- dpnt->d_un.d_val = (unsigned long) debug_addr;
|
|
|
|
- }
|
|
|
|
-#endif
|
|
|
|
- if (dpnt->d_tag == DT_TEXTREL)
|
|
|
|
- app_tpnt->dynamic_info[DT_TEXTREL] = 1;
|
|
|
|
- dpnt++;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-#ifdef __SUPPORT_LD_DEBUG_EARLY__
|
|
|
|
- SEND_STDERR("done scanning DYNAMIC section\n");
|
|
|
|
-#endif
|
|
|
|
-
|
|
|
|
- /* Get some more of the information that we will need to dynamicly link
|
|
|
|
- this module to itself */
|
|
|
|
-
|
|
|
|
- hash_addr = (unsigned long *) (tpnt->dynamic_info[DT_HASH] + load_addr);
|
|
|
|
- tpnt->nbucket = *hash_addr++;
|
|
|
|
- tpnt->nchain = *hash_addr++;
|
|
|
|
- tpnt->elf_buckets = hash_addr;
|
|
|
|
- hash_addr += tpnt->nbucket;
|
|
|
|
-
|
|
|
|
-#ifdef __SUPPORT_LD_DEBUG_EARLY__
|
|
|
|
- SEND_STDERR("done grabbing link information\n");
|
|
|
|
-#endif
|
|
|
|
-
|
|
|
|
-#ifndef FORCE_SHAREABLE_TEXT_SEGMENTS
|
|
|
|
- /* Ugly, ugly. We need to call mprotect to change the protection of
|
|
|
|
- the text pages so that we can do the dynamic linking. We can set the
|
|
|
|
- protection back again once we are done */
|
|
|
|
-
|
|
|
|
- {
|
|
|
|
- ElfW(Phdr) *ppnt;
|
|
|
|
- int i;
|
|
|
|
-
|
|
|
|
-#ifdef __SUPPORT_LD_DEBUG_EARLY__
|
|
|
|
- SEND_STDERR("calling mprotect on the shared library/dynamic linker\n");
|
|
|
|
-#endif
|
|
|
|
-
|
|
|
|
- /* First cover the shared library/dynamic linker. */
|
|
|
|
- if (tpnt->dynamic_info[DT_TEXTREL]) {
|
|
|
|
- header = (ElfW(Ehdr) *) auxvt[AT_BASE].a_un.a_ptr;
|
|
|
|
- ppnt = (ElfW(Phdr) *) ((int)auxvt[AT_BASE].a_un.a_ptr +
|
|
|
|
- header->e_phoff);
|
|
|
|
- for (i = 0; i < header->e_phnum; i++, ppnt++) {
|
|
|
|
- if (ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W)) {
|
|
|
|
- _dl_mprotect((void *) (load_addr + (ppnt->p_vaddr & PAGE_ALIGN)),
|
|
|
|
- (ppnt->p_vaddr & ADDR_ALIGN) + (unsigned long) ppnt->p_filesz,
|
|
|
|
- PROT_READ | PROT_WRITE | PROT_EXEC);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-#ifdef __SUPPORT_LD_DEBUG_EARLY__
|
|
|
|
- SEND_STDERR("calling mprotect on the application program\n");
|
|
|
|
-#endif
|
|
|
|
- /* Now cover the application program. */
|
|
|
|
- if (app_tpnt->dynamic_info[DT_TEXTREL]) {
|
|
|
|
- ppnt = (ElfW(Phdr) *) auxvt[AT_PHDR].a_un.a_ptr;
|
|
|
|
- for (i = 0; i < auxvt[AT_PHNUM].a_un.a_val; i++, ppnt++) {
|
|
|
|
- if (ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W))
|
|
|
|
-#ifndef __UCLIBC_PIE_SUPPORT__
|
|
|
|
- _dl_mprotect((void *) (ppnt->p_vaddr & PAGE_ALIGN),
|
|
|
|
- (ppnt->p_vaddr & ADDR_ALIGN) +
|
|
|
|
-#else
|
|
|
|
- _dl_mprotect((void *) ((ppnt->p_vaddr + app_tpnt->loadaddr) & PAGE_ALIGN),
|
|
|
|
- ((ppnt->p_vaddr + app_tpnt->loadaddr) & ADDR_ALIGN) +
|
|
|
|
-#endif
|
|
|
|
- (unsigned long) ppnt->p_filesz,
|
|
|
|
- PROT_READ | PROT_WRITE | PROT_EXEC);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-#endif
|
|
|
|
-
|
|
|
|
-#if defined(__mips__)
|
|
|
|
-#ifdef __SUPPORT_LD_DEBUG_EARLY__
|
|
|
|
- SEND_STDERR("About to do MIPS specific GOT bootstrap\n");
|
|
|
|
-#endif
|
|
|
|
- /* For MIPS we have to do stuff to the GOT before we do relocations. */
|
|
|
|
- PERFORM_BOOTSTRAP_GOT(got);
|
|
|
|
-#endif
|
|
|
|
-
|
|
|
|
- /* OK, now do the relocations. We do not do a lazy binding here, so
|
|
|
|
- that once we are done, we have considerably more flexibility. */
|
|
|
|
-#ifdef __SUPPORT_LD_DEBUG_EARLY__
|
|
|
|
- SEND_STDERR("About to do library loader relocations\n");
|
|
|
|
-#endif
|
|
|
|
-
|
|
|
|
- goof = 0;
|
|
|
|
- for (indx = 0; indx < 2; indx++) {
|
|
|
|
- unsigned int i;
|
|
|
|
- ELF_RELOC *rpnt;
|
|
|
|
- unsigned long *reloc_addr;
|
|
|
|
- unsigned long symbol_addr;
|
|
|
|
- int symtab_index;
|
|
|
|
- unsigned long rel_addr, rel_size;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- rel_addr = (indx ? tpnt->dynamic_info[DT_JMPREL] : tpnt->
|
|
|
|
- dynamic_info[DT_RELOC_TABLE_ADDR]);
|
|
|
|
- rel_size = (indx ? tpnt->dynamic_info[DT_PLTRELSZ] : tpnt->
|
|
|
|
- dynamic_info[DT_RELOC_TABLE_SIZE]);
|
|
|
|
-
|
|
|
|
- if (!rel_addr)
|
|
|
|
- continue;
|
|
|
|
-
|
|
|
|
- /* Now parse the relocation information */
|
|
|
|
- rpnt = (ELF_RELOC *) (rel_addr + load_addr);
|
|
|
|
- for (i = 0; i < rel_size; i += sizeof(ELF_RELOC), rpnt++) {
|
|
|
|
- reloc_addr = (unsigned long *) (load_addr + (unsigned long) rpnt->r_offset);
|
|
|
|
- symtab_index = ELF32_R_SYM(rpnt->r_info);
|
|
|
|
- symbol_addr = 0;
|
|
|
|
- if (symtab_index) {
|
|
|
|
- char *strtab;
|
|
|
|
- Elf32_Sym *symtab;
|
|
|
|
-
|
|
|
|
- symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + load_addr);
|
|
|
|
- strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + load_addr);
|
|
|
|
-
|
|
|
|
- /* We only do a partial dynamic linking right now. The user
|
|
|
|
- is not supposed to redefine any symbols that start with
|
|
|
|
- a '_', so we can do this with confidence. */
|
|
|
|
- if (!_dl_symbol(strtab + symtab[symtab_index].st_name))
|
|
|
|
- continue;
|
|
|
|
- symbol_addr = load_addr + symtab[symtab_index].st_value;
|
|
|
|
-
|
|
|
|
- if (!symbol_addr) {
|
|
|
|
- /* This will segfault - you cannot call a function until
|
|
|
|
- * we have finished the relocations.
|
|
|
|
- */
|
|
|
|
- SEND_STDERR("ELF dynamic loader - unable to self-bootstrap - symbol ");
|
|
|
|
- SEND_STDERR(strtab + symtab[symtab_index].st_name);
|
|
|
|
- SEND_STDERR(" undefined.\n");
|
|
|
|
- goof++;
|
|
|
|
- }
|
|
|
|
-#ifdef __SUPPORT_LD_DEBUG_EARLY__
|
|
|
|
- SEND_STDERR("About to fixup symbol: ");
|
|
|
|
- SEND_STDERR(strtab + symtab[symtab_index].st_name);
|
|
|
|
- SEND_STDERR("\n");
|
|
|
|
-#endif
|
|
|
|
- PERFORM_BOOTSTRAP_RELOC(rpnt, reloc_addr, symbol_addr, load_addr, &symtab[symtab_index]);
|
|
|
|
- } else {
|
|
|
|
- /*
|
|
|
|
- * Use this machine-specific macro to perform the actual relocation.
|
|
|
|
- */
|
|
|
|
- PERFORM_BOOTSTRAP_RELOC(rpnt, reloc_addr, symbol_addr, load_addr, NULL);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (goof) {
|
|
|
|
- _dl_exit(14);
|
|
|
|
- }
|
|
|
|
-#ifdef __SUPPORT_LD_DEBUG_EARLY__
|
|
|
|
- /* Wahoo!!! */
|
|
|
|
- _dl_dprintf(_dl_debug_file, "Done relocating library loader, so we can now\n\tuse globals and make function calls!\n");
|
|
|
|
|
|
+int _dl_debug_file = 2;
|
|
#endif
|
|
#endif
|
|
|
|
|
|
- if (argv[0]) {
|
|
|
|
- _dl_progname = argv[0];
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /* Start to build the tables of the modules that are required for
|
|
|
|
- * this beast to run. We start with the basic executable, and then
|
|
|
|
- * go from there. Eventually we will run across ourself, and we
|
|
|
|
- * will need to properly deal with that as well. */
|
|
|
|
-
|
|
|
|
- /* Make it so _dl_malloc can use the page of memory we have already
|
|
|
|
- * allocated, so we shouldn't need to grab any more memory */
|
|
|
|
- _dl_malloc_addr = malloc_buffer;
|
|
|
|
- _dl_mmap_zero = mmap_zero;
|
|
|
|
|
|
+/* Forward function declarations */
|
|
|
|
+static void debug_fini (int status, void *arg);
|
|
|
|
+static int _dl_suid_ok(void);
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * This stub function is used by some debuggers. The idea is that they
|
|
|
|
+ * can set an internal breakpoint on it, so that we are notified when the
|
|
|
|
+ * address mapping is changed in some way.
|
|
|
|
+ */
|
|
|
|
+void _dl_debug_state(void)
|
|
|
|
+{
|
|
|
|
+}
|
|
|
|
|
|
|
|
+/* This global variable is also to communicate with debuggers such as gdb. */
|
|
|
|
+struct r_debug *_dl_debug_addr = NULL;
|
|
|
|
|
|
- /* Now we have done the mandatory linking of some things. We are now
|
|
|
|
- free to start using global variables, since these things have all been
|
|
|
|
- fixed up by now. Still no function calls outside of this library ,
|
|
|
|
- since the dynamic resolver is not yet ready. */
|
|
|
|
- _dl_get_ready_to_run(tpnt, app_tpnt, load_addr, hash_addr,
|
|
|
|
- auxvt, envp, debug_addr, malloc_buffer, mmap_zero, argv);
|
|
|
|
|
|
|
|
|
|
|
|
- /* Transfer control to the application. */
|
|
|
|
- status = 0; /* Used on x86, but not on other arches */
|
|
|
|
-#if defined (__SUPPORT_LD_DEBUG__)
|
|
|
|
- if(_dl_debug) _dl_dprintf(_dl_debug_file,"\ntransfering control: %s\n\n", _dl_progname);
|
|
|
|
-#endif
|
|
|
|
- _dl_elf_main = (int (*)(int, char **, char **)) auxvt[AT_ENTRY].a_un.a_fcn;
|
|
|
|
- START();
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
#if defined (__SUPPORT_LD_DEBUG__)
|
|
#if defined (__SUPPORT_LD_DEBUG__)
|
|
static void debug_fini (int status, void *arg)
|
|
static void debug_fini (int status, void *arg)
|
|
{
|
|
{
|
|
(void)status;
|
|
(void)status;
|
|
_dl_dprintf(_dl_debug_file,"\ncalling fini: %s\n\n", (const char*)arg);
|
|
_dl_dprintf(_dl_debug_file,"\ncalling fini: %s\n\n", (const char*)arg);
|
|
}
|
|
}
|
|
-#endif
|
|
|
|
|
|
+#endif
|
|
|
|
|
|
void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *app_tpnt,
|
|
void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *app_tpnt,
|
|
unsigned long load_addr, unsigned long *hash_addr,
|
|
unsigned long load_addr, unsigned long *hash_addr,
|
|
Elf32_auxv_t auxvt[AT_EGID + 1], char **envp, struct r_debug *debug_addr,
|
|
Elf32_auxv_t auxvt[AT_EGID + 1], char **envp, struct r_debug *debug_addr,
|
|
unsigned char *malloc_buffer, unsigned char *mmap_zero, char **argv)
|
|
unsigned char *malloc_buffer, unsigned char *mmap_zero, char **argv)
|
|
-
|
|
|
|
{
|
|
{
|
|
ElfW(Phdr) *ppnt;
|
|
ElfW(Phdr) *ppnt;
|
|
char *lpntstr;
|
|
char *lpntstr;
|
|
@@ -658,6 +103,7 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *app_tpnt
|
|
int (*_dl_on_exit) (void (*FUNCTION)(int STATUS, void *ARG),void*);
|
|
int (*_dl_on_exit) (void (*FUNCTION)(int STATUS, void *ARG),void*);
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
+
|
|
#ifdef __SUPPORT_LD_DEBUG_EARLY__
|
|
#ifdef __SUPPORT_LD_DEBUG_EARLY__
|
|
/* Wahoo!!! */
|
|
/* Wahoo!!! */
|
|
SEND_STDERR("Cool, we managed to make a function call.\n");
|
|
SEND_STDERR("Cool, we managed to make a function call.\n");
|
|
@@ -673,7 +119,6 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *app_tpnt
|
|
* free to start using global variables, since these things have all been
|
|
* free to start using global variables, since these things have all been
|
|
* fixed up by now. Still no function calls outside of this library ,
|
|
* fixed up by now. Still no function calls outside of this library ,
|
|
* since the dynamic resolver is not yet ready. */
|
|
* since the dynamic resolver is not yet ready. */
|
|
-
|
|
|
|
if (argv[0]) {
|
|
if (argv[0]) {
|
|
_dl_progname = argv[0];
|
|
_dl_progname = argv[0];
|
|
}
|
|
}
|
|
@@ -702,7 +147,6 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *app_tpnt
|
|
|
|
|
|
/* OK, this was a big step, now we need to scan all of the user images
|
|
/* OK, this was a big step, now we need to scan all of the user images
|
|
and load them properly. */
|
|
and load them properly. */
|
|
-
|
|
|
|
{
|
|
{
|
|
ElfW(Ehdr) *epnt;
|
|
ElfW(Ehdr) *epnt;
|
|
ElfW(Phdr) *myppnt;
|
|
ElfW(Phdr) *myppnt;
|
|
@@ -1275,15 +719,6 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *app_tpnt
|
|
_dl_debug_state();
|
|
_dl_debug_state();
|
|
}
|
|
}
|
|
|
|
|
|
-/*
|
|
|
|
- * This stub function is used by some debuggers. The idea is that they
|
|
|
|
- * can set an internal breakpoint on it, so that we are notified when the
|
|
|
|
- * address mapping is changed in some way.
|
|
|
|
- */
|
|
|
|
-void _dl_debug_state(void)
|
|
|
|
-{
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
char *_dl_getenv(const char *symbol, char **envp)
|
|
char *_dl_getenv(const char *symbol, char **envp)
|
|
{
|
|
{
|
|
char *pnt;
|
|
char *pnt;
|
|
@@ -1317,5 +752,21 @@ void _dl_unsetenv(const char *symbol, char **envp)
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int _dl_suid_ok(void)
|
|
|
|
+{
|
|
|
|
+ __kernel_uid_t uid, euid;
|
|
|
|
+ __kernel_gid_t gid, egid;
|
|
|
|
+
|
|
|
|
+ uid = _dl_getuid();
|
|
|
|
+ euid = _dl_geteuid();
|
|
|
|
+ gid = _dl_getgid();
|
|
|
|
+ egid = _dl_getegid();
|
|
|
|
+
|
|
|
|
+ if(uid == euid && gid == egid) {
|
|
|
|
+ return 1;
|
|
|
|
+ }
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
#include "hash.c"
|
|
#include "hash.c"
|
|
#include "readelflib1.c"
|
|
#include "readelflib1.c"
|