Changeset View
Changeset View
Standalone View
Standalone View
libexec/rtld-elf/rtld.c
Show First 20 Lines • Show All 82 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* Function declarations. | * Function declarations. | ||||
*/ | */ | ||||
static const char *basename(const char *); | static const char *basename(const char *); | ||||
static void digest_dynamic1(Obj_Entry *, int, const Elf_Dyn **, | static void digest_dynamic1(Obj_Entry *, int, const Elf_Dyn **, | ||||
const Elf_Dyn **, const Elf_Dyn **); | const Elf_Dyn **, const Elf_Dyn **); | ||||
static void digest_dynamic2(Obj_Entry *, const Elf_Dyn *, const Elf_Dyn *, | static bool digest_dynamic2(Obj_Entry *, const Elf_Dyn *, const Elf_Dyn *, | ||||
const Elf_Dyn *); | const Elf_Dyn *); | ||||
static void digest_dynamic(Obj_Entry *, int); | static bool digest_dynamic(Obj_Entry *, int); | ||||
static Obj_Entry *digest_phdr(const Elf_Phdr *, int, caddr_t, const char *); | static Obj_Entry *digest_phdr(const Elf_Phdr *, int, caddr_t, const char *); | ||||
static void distribute_static_tls(Objlist *, RtldLockState *); | static void distribute_static_tls(Objlist *, RtldLockState *); | ||||
static Obj_Entry *dlcheck(void *); | static Obj_Entry *dlcheck(void *); | ||||
static int dlclose_locked(void *, RtldLockState *); | static int dlclose_locked(void *, RtldLockState *); | ||||
static Obj_Entry *dlopen_object(const char *name, int fd, Obj_Entry *refobj, | static Obj_Entry *dlopen_object(const char *name, int fd, Obj_Entry *refobj, | ||||
int lo_flags, int mode, RtldLockState *lockstate); | int lo_flags, int mode, RtldLockState *lockstate); | ||||
static Obj_Entry *do_load_object(int, const char *, char *, struct stat *, int); | static Obj_Entry *do_load_object(int, const char *, char *, struct stat *, int); | ||||
static int do_search_info(const Obj_Entry *obj, int, struct dl_serinfo *); | static int do_search_info(const Obj_Entry *obj, int, struct dl_serinfo *); | ||||
▲ Show 20 Lines • Show All 563 Lines • ▼ Show 20 Lines | #ifndef COMPAT_32BIT | ||||
if (obj_main->interp != NULL && | if (obj_main->interp != NULL && | ||||
strcmp(obj_main->interp, obj_rtld.path) != 0) { | strcmp(obj_main->interp, obj_rtld.path) != 0) { | ||||
free(obj_rtld.path); | free(obj_rtld.path); | ||||
obj_rtld.path = xstrdup(obj_main->interp); | obj_rtld.path = xstrdup(obj_main->interp); | ||||
__progname = obj_rtld.path; | __progname = obj_rtld.path; | ||||
} | } | ||||
#endif | #endif | ||||
digest_dynamic(obj_main, 0); | if (!digest_dynamic(obj_main, 0)) | ||||
rtld_die(); | |||||
dbg("%s valid_hash_sysv %d valid_hash_gnu %d dynsymcount %d", | dbg("%s valid_hash_sysv %d valid_hash_gnu %d dynsymcount %d", | ||||
obj_main->path, obj_main->valid_hash_sysv, obj_main->valid_hash_gnu, | obj_main->path, obj_main->valid_hash_sysv, obj_main->valid_hash_gnu, | ||||
obj_main->dynsymcount); | obj_main->dynsymcount); | ||||
linkmap_add(obj_main); | linkmap_add(obj_main); | ||||
linkmap_add(&obj_rtld); | linkmap_add(&obj_rtld); | ||||
/* Link the main program into the list of objects. */ | /* Link the main program into the list of objects. */ | ||||
▲ Show 20 Lines • Show All 720 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
if (obj->origin_path != NULL) | if (obj->origin_path != NULL) | ||||
return (true); | return (true); | ||||
obj->origin_path = xmalloc(PATH_MAX); | obj->origin_path = xmalloc(PATH_MAX); | ||||
return (rtld_dirname_abs(obj->path, obj->origin_path) != -1); | return (rtld_dirname_abs(obj->path, obj->origin_path) != -1); | ||||
} | } | ||||
static void | static bool | ||||
digest_dynamic2(Obj_Entry *obj, const Elf_Dyn *dyn_rpath, | digest_dynamic2(Obj_Entry *obj, const Elf_Dyn *dyn_rpath, | ||||
const Elf_Dyn *dyn_soname, const Elf_Dyn *dyn_runpath) | const Elf_Dyn *dyn_soname, const Elf_Dyn *dyn_runpath) | ||||
{ | { | ||||
if (obj->z_origin && !obj_resolve_origin(obj)) | if (obj->z_origin && !obj_resolve_origin(obj)) | ||||
rtld_die(); | return (false); | ||||
if (dyn_runpath != NULL) { | if (dyn_runpath != NULL) { | ||||
obj->runpath = (const char *)obj->strtab + dyn_runpath->d_un.d_val; | obj->runpath = (const char *)obj->strtab + dyn_runpath->d_un.d_val; | ||||
obj->runpath = origin_subst(obj, obj->runpath); | obj->runpath = origin_subst(obj, obj->runpath); | ||||
} else if (dyn_rpath != NULL) { | } else if (dyn_rpath != NULL) { | ||||
obj->rpath = (const char *)obj->strtab + dyn_rpath->d_un.d_val; | obj->rpath = (const char *)obj->strtab + dyn_rpath->d_un.d_val; | ||||
obj->rpath = origin_subst(obj, obj->rpath); | obj->rpath = origin_subst(obj, obj->rpath); | ||||
} | } | ||||
if (dyn_soname != NULL) | if (dyn_soname != NULL) | ||||
object_add_name(obj, obj->strtab + dyn_soname->d_un.d_val); | object_add_name(obj, obj->strtab + dyn_soname->d_un.d_val); | ||||
return (true); | |||||
} | } | ||||
static void | static bool | ||||
digest_dynamic(Obj_Entry *obj, int early) | digest_dynamic(Obj_Entry *obj, int early) | ||||
{ | { | ||||
const Elf_Dyn *dyn_rpath; | const Elf_Dyn *dyn_rpath; | ||||
const Elf_Dyn *dyn_soname; | const Elf_Dyn *dyn_soname; | ||||
const Elf_Dyn *dyn_runpath; | const Elf_Dyn *dyn_runpath; | ||||
digest_dynamic1(obj, early, &dyn_rpath, &dyn_soname, &dyn_runpath); | digest_dynamic1(obj, early, &dyn_rpath, &dyn_soname, &dyn_runpath); | ||||
digest_dynamic2(obj, dyn_rpath, dyn_soname, dyn_runpath); | return (digest_dynamic2(obj, dyn_rpath, dyn_soname, dyn_runpath)); | ||||
} | } | ||||
/* | /* | ||||
* Process a shared object's program header. This is used only for the | * Process a shared object's program header. This is used only for the | ||||
* main program, when the kernel has already loaded the main program | * main program, when the kernel has already loaded the main program | ||||
* into memory before calling the dynamic linker. It creates and | * into memory before calling the dynamic linker. It creates and | ||||
* returns an Obj_Entry structure. | * returns an Obj_Entry structure. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 1,111 Lines • ▼ Show 20 Lines | if (fs.f_flags & MNT_NOEXEC) { | ||||
/* | /* | ||||
* If DT_SONAME is present in the object, digest_dynamic2 already | * If DT_SONAME is present in the object, digest_dynamic2 already | ||||
* added it to the object names. | * added it to the object names. | ||||
*/ | */ | ||||
if (name != NULL) | if (name != NULL) | ||||
object_add_name(obj, name); | object_add_name(obj, name); | ||||
obj->path = path; | obj->path = path; | ||||
digest_dynamic(obj, 0); | if (!digest_dynamic(obj, 0)) | ||||
goto errp; | |||||
dbg("%s valid_hash_sysv %d valid_hash_gnu %d dynsymcount %d", obj->path, | dbg("%s valid_hash_sysv %d valid_hash_gnu %d dynsymcount %d", obj->path, | ||||
obj->valid_hash_sysv, obj->valid_hash_gnu, obj->dynsymcount); | obj->valid_hash_sysv, obj->valid_hash_gnu, obj->dynsymcount); | ||||
if (obj->z_noopen && (flags & (RTLD_LO_DLOPEN | RTLD_LO_TRACE)) == | if (obj->z_noopen && (flags & (RTLD_LO_DLOPEN | RTLD_LO_TRACE)) == | ||||
RTLD_LO_DLOPEN) { | RTLD_LO_DLOPEN) { | ||||
dbg("refusing to load non-loadable \"%s\"", obj->path); | dbg("refusing to load non-loadable \"%s\"", obj->path); | ||||
_rtld_error("Cannot dlopen non-loadable %s", obj->path); | _rtld_error("Cannot dlopen non-loadable %s", obj->path); | ||||
munmap(obj->mapbase, obj->mapsize); | goto errp; | ||||
obj_free(obj); | |||||
return (NULL); | |||||
} | } | ||||
obj->dlopened = (flags & RTLD_LO_DLOPEN) != 0; | obj->dlopened = (flags & RTLD_LO_DLOPEN) != 0; | ||||
TAILQ_INSERT_TAIL(&obj_list, obj, next); | TAILQ_INSERT_TAIL(&obj_list, obj, next); | ||||
obj_count++; | obj_count++; | ||||
obj_loads++; | obj_loads++; | ||||
linkmap_add(obj); /* for GDB & dlinfo() */ | linkmap_add(obj); /* for GDB & dlinfo() */ | ||||
max_stack_flags |= obj->stack_flags; | max_stack_flags |= obj->stack_flags; | ||||
dbg(" %p .. %p: %s", obj->mapbase, | dbg(" %p .. %p: %s", obj->mapbase, | ||||
obj->mapbase + obj->mapsize - 1, obj->path); | obj->mapbase + obj->mapsize - 1, obj->path); | ||||
if (obj->textrel) | if (obj->textrel) | ||||
dbg(" WARNING: %s has impure text", obj->path); | dbg(" WARNING: %s has impure text", obj->path); | ||||
LD_UTRACE(UTRACE_LOAD_OBJECT, obj, obj->mapbase, obj->mapsize, 0, | LD_UTRACE(UTRACE_LOAD_OBJECT, obj, obj->mapbase, obj->mapsize, 0, | ||||
obj->path); | obj->path); | ||||
return obj; | return (obj); | ||||
errp: | |||||
munmap(obj->mapbase, obj->mapsize); | |||||
obj_free(obj); | |||||
return (NULL); | |||||
} | } | ||||
static Obj_Entry * | static Obj_Entry * | ||||
obj_from_addr(const void *addr) | obj_from_addr(const void *addr) | ||||
{ | { | ||||
Obj_Entry *obj; | Obj_Entry *obj; | ||||
TAILQ_FOREACH(obj, &obj_list, next) { | TAILQ_FOREACH(obj, &obj_list, next) { | ||||
▲ Show 20 Lines • Show All 1,384 Lines • ▼ Show 20 Lines | return(-1); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
rtld_dirname_abs(const char *path, char *base) | rtld_dirname_abs(const char *path, char *base) | ||||
{ | { | ||||
char *last; | char *last; | ||||
if (realpath(path, base) == NULL) | if (realpath(path, base) == NULL) { | ||||
_rtld_error("realpath \"%s\" failed (%s)", path, | |||||
rtld_strerror(errno)); | |||||
return (-1); | return (-1); | ||||
} | |||||
dbg("%s -> %s", path, base); | dbg("%s -> %s", path, base); | ||||
last = strrchr(base, '/'); | last = strrchr(base, '/'); | ||||
if (last == NULL) | if (last == NULL) { | ||||
_rtld_error("non-abs result from realpath \"%s\"", path); | |||||
return (-1); | return (-1); | ||||
} | |||||
if (last != base) | if (last != base) | ||||
*last = '\0'; | *last = '\0'; | ||||
return (0); | return (0); | ||||
} | } | ||||
static void | static void | ||||
linkmap_add(Obj_Entry *obj) | linkmap_add(Obj_Entry *obj) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 1,754 Lines • Show Last 20 Lines |