219 lines
5.0 KiB
C
219 lines
5.0 KiB
C
|
|
#ifndef DYNSO_INTERNAL_H_
|
|
#define DYNSO_INTERNAL_H_
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
|
|
#include <elf.h>
|
|
#include <link.h>
|
|
|
|
#include <sys/auxv.h>
|
|
#include <sys/stat.h>
|
|
|
|
// glibc stuff...
|
|
|
|
struct link_map_priv1 {
|
|
// SVR4
|
|
ElfW(Addr) l_addr;
|
|
char* l_name;
|
|
ElfW(Dyn)* l_ld;
|
|
struct link_map_priv1* l_next, *l_prev;
|
|
|
|
// glibc-specific
|
|
struct link_map_priv1* l_real;
|
|
Lmid_t l_ns;
|
|
struct libname_list* l_libname;
|
|
ElfW(Dyn)* l_info[];
|
|
};
|
|
|
|
struct libname_list;
|
|
struct r_found_version;
|
|
struct r_search_path_elem;
|
|
struct r_file_id {
|
|
dev_t dev;
|
|
ino64_t ino;
|
|
};
|
|
struct r_scope_elem {
|
|
struct link_map_priv1** r_list;
|
|
unsigned int r_nlist;
|
|
};
|
|
struct r_search_path_struct {
|
|
struct r_search_path_elem** dirs;
|
|
int malloced;
|
|
};
|
|
struct link_map_priv2 {
|
|
const ElfW(Phdr)* l_phdr;
|
|
ElfW(Addr) l_entry;
|
|
ElfW(Half) l_phnum;
|
|
ElfW(Half) l_ldnum;
|
|
|
|
struct r_scope_elem l_searchlist, l_symbolic_searchlist;
|
|
|
|
struct link_map* l_loader;
|
|
|
|
struct r_found_version* l_versions;
|
|
unsigned int l_nversions;
|
|
|
|
Elf_Symndx l_nbuckets;
|
|
Elf32_Word l_gnu_bitmask_idxbits;
|
|
Elf32_Word l_gnu_shift;
|
|
const ElfW(Addr)* l_gnu_bitmask;
|
|
union {
|
|
const Elf32_Word* l_gnu_buckets;
|
|
const Elf_Symndx* l_chain;
|
|
};
|
|
union {
|
|
const Elf32_Word* l_gnu_chain_zero;
|
|
const Elf_Symndx* l_buckets;
|
|
};
|
|
|
|
unsigned int l_direct_opencount;
|
|
enum {
|
|
lt_executable,
|
|
lt_library,
|
|
lt_loaded
|
|
} l_type : 2;
|
|
unsigned int l_relocated : 1;
|
|
unsigned int l_init_called : 1;
|
|
unsigned int l_global : 1;
|
|
unsigned int l_reserved : 2;
|
|
unsigned int l_phdr_allocated : 1;
|
|
unsigned int l_soname_added : 1;
|
|
unsigned int l_faked : 1;
|
|
unsigned int l_need_tls_init : 1;
|
|
unsigned int l_auditing : 1;
|
|
unsigned int l_audit_any_plt : 1;
|
|
unsigned int l_removed : 1;
|
|
unsigned int l_contiguous : 1;
|
|
unsigned int l_symbolic_in_local_scope : 1;
|
|
unsigned int l_free_initfini : 1;
|
|
|
|
//bool l_nodelete_active, l_nodelete_pending; // FIXME
|
|
// ^ these two are added somewhere between glibc 2.30 (the one on my
|
|
// system) and now (current master), I should probably add a priv3 thing
|
|
// to accomodate for this, but EFFORT
|
|
|
|
/*#if defined(__i386__) || defined(__x86_64__)
|
|
enum {
|
|
lc_unknown = 0,
|
|
lc_none = 1<<0,
|
|
lc_ibt = 1<<1,
|
|
lc_shstk = 1<<2,
|
|
lc_ibt_and_shstk = lc_ibt | lc_shstk
|
|
} l_cet : 3;
|
|
#endif*/
|
|
};
|
|
|
|
struct link_map_priv3 {
|
|
struct r_search_path_struct l_rpath_dirs;
|
|
|
|
struct reloc_result {
|
|
ElfW(Addr) addr;
|
|
struct link_map_priv1* bound;
|
|
unsigned int boundndx;
|
|
uint32_t enterexit;
|
|
unsigned int flags;
|
|
unsigned int init;
|
|
} *l_reloc_result;
|
|
|
|
ElfW(Versym)* l_versyms;
|
|
const char* l_origin;
|
|
ElfW(Addr) l_map_start, l_map_end;
|
|
ElfW(Addr) l_text_end;
|
|
struct r_scope_elem* l_scope_mem[4];
|
|
size_t l_scope_max;
|
|
struct r_scope_elem** l_scope;
|
|
struct r_scope_elem* l_local_scope[2];
|
|
struct r_file_id l_file_id;
|
|
struct r_search_path_struct l_runpath_dirs;
|
|
struct link_map** l_initfini;
|
|
struct link_map_reldeps {
|
|
unsigned int act;
|
|
struct link_map* list[];
|
|
} *l_reldeps;
|
|
unsigned int l_reldepsmax;
|
|
|
|
unsigned int l_used;
|
|
ElfW(Word) l_feature_1, l_flags_1, l_flags;
|
|
int l_idx;
|
|
|
|
// more stuff...
|
|
};
|
|
|
|
typedef struct link_map_priv1* (*dl_new_object_f)(char* realname, const char* libname,
|
|
int type, struct link_map* loader, int mode, Lmid_t nsid);
|
|
|
|
typedef void (*dl_add_to_namespace_list_f)(struct link_map_priv1 *new, Lmid_t nsid);
|
|
|
|
typedef void (*dl_setup_hash_f)(struct link_map_priv1* map);
|
|
|
|
// actual stuff internal for this lib now
|
|
|
|
struct rtldinfo {
|
|
ElfW(Addr) base;
|
|
ElfW(Sym)* symtab;
|
|
char* strtab;
|
|
size_t strsz;
|
|
size_t shsz;
|
|
ptrdiff_t syment;
|
|
bool sym_malloc, str_malloc;
|
|
};
|
|
|
|
struct inject_undo_info {
|
|
struct r_scope_elem** dest;
|
|
struct r_scope_elem* old;
|
|
struct r_scope_elem* alloced;
|
|
//struct link_map_priv1** rlist;
|
|
};
|
|
|
|
struct dynso_sym {
|
|
const char* name;
|
|
void* value;
|
|
size_t size;
|
|
int type;
|
|
};
|
|
struct dynso_lib {
|
|
struct inject_undo_info undoinf;
|
|
dl_new_object_f _dl_new_object;
|
|
dl_add_to_namespace_list_f _dl_add_to_namespace_list;
|
|
dl_setup_hash_f _dl_setup_hash;
|
|
ElfW(Dyn)* dyn;
|
|
ElfW(Sym)* sym;
|
|
Elf_Symndx* idx;
|
|
char* str;
|
|
struct link_map_priv1* caller;
|
|
struct link_map_priv1* fake1;
|
|
struct link_map_priv2* fake2;
|
|
struct link_map_priv3* fake3;
|
|
struct dynso_sym* syms;
|
|
size_t address;
|
|
size_t nsyms;
|
|
size_t syms_cap;
|
|
Lmid_t ns;
|
|
bool added;
|
|
bool removed;
|
|
bool alloc_syms;
|
|
};
|
|
//extern void _start(void) __attribute__((__noreturn__));
|
|
|
|
static ptrdiff_t get_priv1_priv2_offset(void);
|
|
static ptrdiff_t get_priv2_priv3_offset(void);
|
|
|
|
static struct link_map_priv2* priv1_to_priv2(struct link_map_priv1* lm);
|
|
static struct link_map_priv3* priv2_to_priv3(struct link_map_priv2* l2);
|
|
inline static struct link_map_priv3* priv1_to_priv3(struct link_map_priv1* lm) {
|
|
return priv2_to_priv3(priv1_to_priv2(lm));
|
|
}
|
|
|
|
static enum dynso_err get_rtld_symtab(struct rtldinfo* inf);
|
|
static enum dynso_err link_private_rtld_syms(struct dynso_lib* l);
|
|
|
|
static enum dynso_err inject_in_scope_of(struct inject_undo_info* r,
|
|
struct link_map_priv3* victim, struct link_map_priv1* add);
|
|
static void inject_undo(const struct inject_undo_info* inf);
|
|
|
|
#endif
|
|
|