dynamic-dso/dynso_internal.h

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