rtld: avoid use of of getenv(3) for evaluating rtld env vars (LD_XXX)
Scan through the set of environment variables during initialization and store values in the corresponding ld_env_var_desc structure, in the single pass at init time. This does not eliminate use of getenv(3) and unsetenv(3) completely, but provides a foundation to do that as the next step. Also organize the scan in a way that makes it easier to support aliases like LD_DEBUG vs. LD_64_DEBUG. Suggested by: arichardson Reviewed by: arichardson, markj Sponsored by: The FreeBSD Foundation MFC after: 1 week Differential revision: https://reviews.freebsd.org/D31545
This commit is contained in:
parent
451dc2b7cc
commit
bfd4c875a1
@ -367,82 +367,105 @@ enum {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct ld_env_var_desc {
|
struct ld_env_var_desc {
|
||||||
char n[64];
|
const char *n;
|
||||||
bool unsecure;
|
char *val;
|
||||||
|
const bool unsecure;
|
||||||
};
|
};
|
||||||
|
#define LD_ENV_DESC(var, unsec) \
|
||||||
|
[LD_##var] = { .n = #var, .unsecure = unsec }
|
||||||
|
|
||||||
static struct ld_env_var_desc ld_env_vars[] = {
|
static struct ld_env_var_desc ld_env_vars[] = {
|
||||||
[LD_BIND_NOW] =
|
LD_ENV_DESC(BIND_NOW, false),
|
||||||
{ .n = "BIND_NOW", .unsecure = false },
|
LD_ENV_DESC(PRELOAD, true),
|
||||||
[LD_PRELOAD] =
|
LD_ENV_DESC(LIBMAP, true),
|
||||||
{ .n = "PRELOAD", .unsecure = true },
|
LD_ENV_DESC(LIBRARY_PATH, true),
|
||||||
[LD_LIBMAP] =
|
LD_ENV_DESC(LIBRARY_PATH_FDS, true),
|
||||||
{ .n = "LIBMAP", .unsecure = true },
|
LD_ENV_DESC(LIBMAP_DISABLE, true),
|
||||||
[LD_LIBRARY_PATH] =
|
LD_ENV_DESC(BIND_NOT, true),
|
||||||
{ .n = "LIBRARY_PATH", .unsecure = true },
|
LD_ENV_DESC(DEBUG, true),
|
||||||
[LD_LIBRARY_PATH_FDS] =
|
LD_ENV_DESC(ELF_HINTS_PATH, true),
|
||||||
{ .n = "LIBRARY_PATH_FDS", .unsecure = true },
|
LD_ENV_DESC(LOADFLTR, true),
|
||||||
[LD_LIBMAP_DISABLE] =
|
LD_ENV_DESC(LIBRARY_PATH_RPATH, true),
|
||||||
{ .n = "LIBMAP_DISABLE", .unsecure = true },
|
LD_ENV_DESC(PRELOAD_FDS, true),
|
||||||
[LD_BIND_NOT] =
|
LD_ENV_DESC(DYNAMIC_WEAK, true),
|
||||||
{ .n = "BIND_NOT", .unsecure = true },
|
LD_ENV_DESC(TRACE_LOADED_OBJECTS, false),
|
||||||
[LD_DEBUG] =
|
LD_ENV_DESC(UTRACE, false),
|
||||||
{ .n = "DEBUG", .unsecure = true },
|
LD_ENV_DESC(DUMP_REL_PRE, false),
|
||||||
[LD_ELF_HINTS_PATH] =
|
LD_ENV_DESC(DUMP_REL_POST, false),
|
||||||
{ .n = "ELF_HINTS_PATH", .unsecure = true },
|
LD_ENV_DESC(TRACE_LOADED_OBJECTS_PROGNAME, false),
|
||||||
[LD_LOADFLTR] =
|
LD_ENV_DESC(TRACE_LOADED_OBJECTS_FMT1, false),
|
||||||
{ .n = "LOADFLTR", .unsecure = true },
|
LD_ENV_DESC(TRACE_LOADED_OBJECTS_FMT2, false),
|
||||||
[LD_LIBRARY_PATH_RPATH] =
|
LD_ENV_DESC(TRACE_LOADED_OBJECTS_ALL, false),
|
||||||
{ .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 *
|
static char *
|
||||||
ld_get_env_var(int idx)
|
ld_get_env_var(int idx)
|
||||||
{
|
{
|
||||||
return (getenv(ld_var(idx)));
|
return (ld_env_vars[idx].val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
rtld_get_env_val(char **env, const char *name, size_t name_len)
|
||||||
|
{
|
||||||
|
char **m, *n, *v;
|
||||||
|
|
||||||
|
for (m = env; *m != NULL; m++) {
|
||||||
|
n = *m;
|
||||||
|
v = strchr(n, '=');
|
||||||
|
if (v == NULL) {
|
||||||
|
/* corrupt environment? */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (v - n == (ptrdiff_t)name_len &&
|
||||||
|
strncmp(name, n, name_len) == 0)
|
||||||
|
return (v + 1);
|
||||||
|
}
|
||||||
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
rtld_init_env_vars(void)
|
rtld_init_env_vars_for_prefix(char **env, const char *env_prefix)
|
||||||
{
|
{
|
||||||
struct ld_env_var_desc *lvd;
|
struct ld_env_var_desc *lvd;
|
||||||
size_t sz;
|
size_t prefix_len, nlen;
|
||||||
|
char **m, *n, *v;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
sz = strlen(ld_env_prefix);
|
prefix_len = strlen(env_prefix);
|
||||||
for (i = 0; i < (int)nitems(ld_env_vars); i++) {
|
for (m = env; *m != NULL; m++) {
|
||||||
lvd = &ld_env_vars[i];
|
n = *m;
|
||||||
memmove(lvd->n + sz, lvd->n, strlen(lvd->n) + 1);
|
if (strncmp(env_prefix, n, prefix_len) != 0) {
|
||||||
memcpy(lvd->n, ld_env_prefix, sz);
|
/* Not a rtld environment variable. */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
n += prefix_len;
|
||||||
|
v = strchr(n, '=');
|
||||||
|
if (v == NULL) {
|
||||||
|
/* corrupt environment? */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (i = 0; i < (int)nitems(ld_env_vars); i++) {
|
||||||
|
lvd = &ld_env_vars[i];
|
||||||
|
if (lvd->val != NULL) {
|
||||||
|
/* Saw higher-priority variable name already. */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
nlen = strlen(lvd->n);
|
||||||
|
if (v - n == (ptrdiff_t)nlen &&
|
||||||
|
strncmp(lvd->n, n, nlen) == 0) {
|
||||||
|
lvd->val = v + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rtld_init_env_vars(char **env)
|
||||||
|
{
|
||||||
|
rtld_init_env_vars_for_prefix(env, ld_env_prefix);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Main entry point for dynamic linking. The first argument is the
|
* Main entry point for dynamic linking. The first argument is the
|
||||||
* stack pointer. The stack is expected to be laid out as described
|
* stack pointer. The stack is expected to be laid out as described
|
||||||
@ -548,7 +571,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
|
|||||||
direct_exec = false;
|
direct_exec = false;
|
||||||
|
|
||||||
md_abi_variant_hook(aux_info);
|
md_abi_variant_hook(aux_info);
|
||||||
rtld_init_env_vars();
|
rtld_init_env_vars(env);
|
||||||
|
|
||||||
fd = -1;
|
fd = -1;
|
||||||
if (aux_info[AT_EXECFD] != NULL) {
|
if (aux_info[AT_EXECFD] != NULL) {
|
||||||
@ -667,12 +690,11 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
|
|||||||
if (!trust) {
|
if (!trust) {
|
||||||
for (i = 0; i < (int)nitems(ld_env_vars); i++) {
|
for (i = 0; i < (int)nitems(ld_env_vars); i++) {
|
||||||
lvd = &ld_env_vars[i];
|
lvd = &ld_env_vars[i];
|
||||||
if (lvd->unsecure && unsetenv(lvd->n)) {
|
if (lvd->unsecure)
|
||||||
_rtld_error("environment corrupt; aborting");
|
lvd->val = NULL;
|
||||||
rtld_die();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ld_debug = ld_get_env_var(LD_DEBUG);
|
ld_debug = ld_get_env_var(LD_DEBUG);
|
||||||
if (ld_bind_now == NULL)
|
if (ld_bind_now == NULL)
|
||||||
ld_bind_not = ld_get_env_var(LD_BIND_NOT) != NULL;
|
ld_bind_not = ld_get_env_var(LD_BIND_NOT) != NULL;
|
||||||
|
Loading…
Reference in New Issue
Block a user