rtld: rework how environment variables are named

Instead of specifying the main name part of the environment variable as the
string literal, create array of the var names and access them by symbolic
index.  Convert main name parts into complete names by prefixing with
ABI-specific ld_env_vars.

This way the name is not repeated, and also it can carry additional
proporties explicitly.  For instance, cleanup of the environment for
the setuid image does not require retyping all names.

Reviewed by:	arichardson, markj
MFC after:	1 week
Sponsored by:	The FreeBSD Foundation
Differential revision:	https://reviews.freebsd.org/D31545
This commit is contained in:
Konstantin Belousov 2021-08-15 21:57:42 +03:00
parent 5469a99530
commit 451dc2b7cc
2 changed files with 132 additions and 49 deletions

View File

@ -80,7 +80,6 @@ extern void arm_abi_variant_hook(Elf_Auxinfo **);
#ifdef __ARM_FP
#define md_abi_variant_hook(x) arm_abi_variant_hook(x)
#define RTLD_VARIANT_ENV_NAMES
#else
#define md_abi_variant_hook(x)
#endif

View File

@ -342,23 +342,106 @@ ld_utrace_log(int event, void *handle, void *mapbase, size_t mapsize,
utrace(&ut, sizeof(ut));
}
#ifdef RTLD_VARIANT_ENV_NAMES
/*
* construct the env variable based on the type of binary that's
* running.
*/
static inline const char *
_LD(const char *var)
{
static char buffer[128];
enum {
LD_BIND_NOW = 0,
LD_PRELOAD,
LD_LIBMAP,
LD_LIBRARY_PATH,
LD_LIBRARY_PATH_FDS,
LD_LIBMAP_DISABLE,
LD_BIND_NOT,
LD_DEBUG,
LD_ELF_HINTS_PATH,
LD_LOADFLTR,
LD_LIBRARY_PATH_RPATH,
LD_PRELOAD_FDS,
LD_DYNAMIC_WEAK,
LD_TRACE_LOADED_OBJECTS,
LD_UTRACE,
LD_DUMP_REL_PRE,
LD_DUMP_REL_POST,
LD_TRACE_LOADED_OBJECTS_PROGNAME,
LD_TRACE_LOADED_OBJECTS_FMT1,
LD_TRACE_LOADED_OBJECTS_FMT2,
LD_TRACE_LOADED_OBJECTS_ALL,
};
strlcpy(buffer, ld_env_prefix, sizeof(buffer));
strlcat(buffer, var, sizeof(buffer));
return (buffer);
struct ld_env_var_desc {
char n[64];
bool unsecure;
};
static struct ld_env_var_desc ld_env_vars[] = {
[LD_BIND_NOW] =
{ .n = "BIND_NOW", .unsecure = false },
[LD_PRELOAD] =
{ .n = "PRELOAD", .unsecure = true },
[LD_LIBMAP] =
{ .n = "LIBMAP", .unsecure = true },
[LD_LIBRARY_PATH] =
{ .n = "LIBRARY_PATH", .unsecure = true },
[LD_LIBRARY_PATH_FDS] =
{ .n = "LIBRARY_PATH_FDS", .unsecure = true },
[LD_LIBMAP_DISABLE] =
{ .n = "LIBMAP_DISABLE", .unsecure = true },
[LD_BIND_NOT] =
{ .n = "BIND_NOT", .unsecure = true },
[LD_DEBUG] =
{ .n = "DEBUG", .unsecure = true },
[LD_ELF_HINTS_PATH] =
{ .n = "ELF_HINTS_PATH", .unsecure = true },
[LD_LOADFLTR] =
{ .n = "LOADFLTR", .unsecure = true },
[LD_LIBRARY_PATH_RPATH] =
{ .n = "LIBRARY_PATH_RPATH", .unsecure = true },
[LD_PRELOAD_FDS] =
{ .n = "PRELOAD_FDS", .unsecure = true },
[LD_DYNAMIC_WEAK] =
{ .n = "DYNAMIC_WEAK", .unsecure = true },
[LD_TRACE_LOADED_OBJECTS] =
{ .n = "TRACE_LOADED_OBJECTS", .unsecure = false },
[LD_UTRACE] =
{ .n = "UTRACE", .unsecure = false },
[LD_DUMP_REL_PRE] =
{ .n = "DUMP_REL_PRE", .unsecure = false },
[LD_DUMP_REL_POST] =
{ .n = "DUMP_REL_POST", .unsecure = false },
[LD_TRACE_LOADED_OBJECTS_PROGNAME] =
{ .n = "TRACE_LOADED_OBJECTS_PROGNAME", .unsecure = false},
[LD_TRACE_LOADED_OBJECTS_FMT1] =
{ .n = "TRACE_LOADED_OBJECTS_FMT1", .unsecure = false},
[LD_TRACE_LOADED_OBJECTS_FMT2] =
{ .n = "TRACE_LOADED_OBJECTS_FMT2", .unsecure = false},
[LD_TRACE_LOADED_OBJECTS_ALL] =
{ .n = "TRACE_LOADED_OBJECTS_ALL", .unsecure = false},
};
static const char *
ld_var(int idx)
{
return (ld_env_vars[idx].n);
}
static char *
ld_get_env_var(int idx)
{
return (getenv(ld_var(idx)));
}
static void
rtld_init_env_vars(void)
{
struct ld_env_var_desc *lvd;
size_t sz;
int i;
sz = strlen(ld_env_prefix);
for (i = 0; i < (int)nitems(ld_env_vars); i++) {
lvd = &ld_env_vars[i];
memmove(lvd->n + sz, lvd->n, strlen(lvd->n) + 1);
memcpy(lvd->n, ld_env_prefix, sz);
}
}
#else
#define _LD(x) LD_ x
#endif
/*
* Main entry point for dynamic linking. The first argument is the
@ -389,6 +472,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
Elf_Addr *argcp;
char **argv, **env, **envp, *kexecpath, *library_path_rpath;
const char *argv0, *binpath;
struct ld_env_var_desc *lvd;
caddr_t imgentry;
char buf[MAXPATHLEN];
int argc, fd, i, mib[4], old_osrel, osrel, phnum, rtld_argc;
@ -464,6 +548,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
direct_exec = false;
md_abi_variant_hook(aux_info);
rtld_init_env_vars();
fd = -1;
if (aux_info[AT_EXECFD] != NULL) {
@ -571,7 +656,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
}
}
ld_bind_now = getenv(_LD("BIND_NOW"));
ld_bind_now = ld_get_env_var(LD_BIND_NOW);
/*
* If the process is tainted, then we un-set the dangerous environment
@ -580,29 +665,27 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
* future processes to honor the potentially un-safe variables.
*/
if (!trust) {
if (unsetenv(_LD("PRELOAD")) || unsetenv(_LD("LIBMAP")) ||
unsetenv(_LD("LIBRARY_PATH")) || unsetenv(_LD("LIBRARY_PATH_FDS")) ||
unsetenv(_LD("LIBMAP_DISABLE")) || unsetenv(_LD("BIND_NOT")) ||
unsetenv(_LD("DEBUG")) || unsetenv(_LD("ELF_HINTS_PATH")) ||
unsetenv(_LD("LOADFLTR")) || unsetenv(_LD("LIBRARY_PATH_RPATH")) ||
unsetenv(_LD("PRELOAD_FDS")) || unsetenv(_LD("DYNAMIC_WEAK"))) {
_rtld_error("environment corrupt; aborting");
rtld_die();
}
for (i = 0; i < (int)nitems(ld_env_vars); i++) {
lvd = &ld_env_vars[i];
if (lvd->unsecure && unsetenv(lvd->n)) {
_rtld_error("environment corrupt; aborting");
rtld_die();
}
}
}
ld_debug = getenv(_LD("DEBUG"));
ld_debug = ld_get_env_var(LD_DEBUG);
if (ld_bind_now == NULL)
ld_bind_not = getenv(_LD("BIND_NOT")) != NULL;
ld_dynamic_weak = getenv(_LD("DYNAMIC_WEAK")) == NULL;
libmap_disable = getenv(_LD("LIBMAP_DISABLE")) != NULL;
libmap_override = getenv(_LD("LIBMAP"));
ld_library_path = getenv(_LD("LIBRARY_PATH"));
ld_library_dirs = getenv(_LD("LIBRARY_PATH_FDS"));
ld_preload = getenv(_LD("PRELOAD"));
ld_preload_fds = getenv(_LD("PRELOAD_FDS"));
ld_elf_hints_path = getenv(_LD("ELF_HINTS_PATH"));
ld_loadfltr = getenv(_LD("LOADFLTR")) != NULL;
library_path_rpath = getenv(_LD("LIBRARY_PATH_RPATH"));
ld_bind_not = ld_get_env_var(LD_BIND_NOT) != NULL;
ld_dynamic_weak = ld_get_env_var(LD_DYNAMIC_WEAK) == NULL;
libmap_disable = ld_get_env_var(LD_LIBMAP_DISABLE) != NULL;
libmap_override = ld_get_env_var(LD_LIBMAP);
ld_library_path = ld_get_env_var(LD_LIBRARY_PATH);
ld_library_dirs = ld_get_env_var(LD_LIBRARY_PATH_FDS);
ld_preload = ld_get_env_var(LD_PRELOAD);
ld_preload_fds = ld_get_env_var(LD_PRELOAD_FDS);
ld_elf_hints_path = ld_get_env_var(LD_ELF_HINTS_PATH);
ld_loadfltr = ld_get_env_var(LD_LOADFLTR) != NULL;
library_path_rpath = ld_get_env_var(LD_LIBRARY_PATH_RPATH);
if (library_path_rpath != NULL) {
if (library_path_rpath[0] == 'y' ||
library_path_rpath[0] == 'Y' ||
@ -611,11 +694,11 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
else
ld_library_path_rpath = false;
}
dangerous_ld_env = libmap_disable || (libmap_override != NULL) ||
(ld_library_path != NULL) || (ld_preload != NULL) ||
(ld_elf_hints_path != NULL) || ld_loadfltr || ld_dynamic_weak;
ld_tracing = getenv(_LD("TRACE_LOADED_OBJECTS"));
ld_utrace = getenv(_LD("UTRACE"));
dangerous_ld_env = libmap_disable || libmap_override != NULL ||
ld_library_path != NULL || ld_preload != NULL ||
ld_elf_hints_path != NULL || ld_loadfltr || ld_dynamic_weak;
ld_tracing = ld_get_env_var(LD_TRACE_LOADED_OBJECTS);
ld_utrace = ld_get_env_var(LD_UTRACE);
if ((ld_elf_hints_path == NULL) || strlen(ld_elf_hints_path) == 0)
ld_elf_hints_path = ld_elf_hints_default;
@ -751,7 +834,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
exit(0);
}
if (getenv(_LD("DUMP_REL_PRE")) != NULL) {
if (ld_get_env_var(LD_DUMP_REL_PRE) != NULL) {
dump_relocations(obj_main);
exit (0);
}
@ -779,7 +862,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
if (do_copy_relocations(obj_main) == -1)
rtld_die();
if (getenv(_LD("DUMP_REL_POST")) != NULL) {
if (ld_get_env_var(LD_DUMP_REL_POST) != NULL) {
dump_relocations(obj_main);
exit (0);
}
@ -4715,16 +4798,17 @@ trace_loaded_objects(Obj_Entry *obj)
const char *fmt1, *fmt2, *fmt, *main_local, *list_containers;
int c;
if ((main_local = getenv(_LD("TRACE_LOADED_OBJECTS_PROGNAME"))) == NULL)
if ((main_local = ld_get_env_var(LD_TRACE_LOADED_OBJECTS_PROGNAME)) ==
NULL)
main_local = "";
if ((fmt1 = getenv(_LD("TRACE_LOADED_OBJECTS_FMT1"))) == NULL)
if ((fmt1 = ld_get_env_var(LD_TRACE_LOADED_OBJECTS_FMT1)) == NULL)
fmt1 = "\t%o => %p (%x)\n";
if ((fmt2 = getenv(_LD("TRACE_LOADED_OBJECTS_FMT2"))) == NULL)
if ((fmt2 = ld_get_env_var(LD_TRACE_LOADED_OBJECTS_FMT2)) == NULL)
fmt2 = "\t%o (%x)\n";
list_containers = getenv(_LD("TRACE_LOADED_OBJECTS_ALL"));
list_containers = ld_get_env_var(LD_TRACE_LOADED_OBJECTS_ALL);
for (; obj != NULL; obj = TAILQ_NEXT(obj, next)) {
Needed_Entry *needed;