elf: Make glibc.rtld.enable_secure ignore alias environment variables

Tunable with environment variables aliases are also ignored if
glibc.rtld.enable_secure is enabled.  The tunable parsing is also
optimized a bit, where the loop that checks each environment variable
only checks for the tunables with aliases instead of all tables.

Checked on aarch64-linux-gnu and x86_64-linux-gnu.
Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
This commit is contained in:
Adhemerval Zanella 2024-05-06 13:18:48 -03:00
parent 1e1ad714ee
commit eb59c7b43d
3 changed files with 165 additions and 25 deletions

View File

@ -300,6 +300,9 @@ __tunables_init (char **envp)
if (__libc_enable_secure) if (__libc_enable_secure)
return; return;
enum { tunable_num_env_alias = array_length (tunable_env_alias_list) };
struct tunable_toset_t tunables_env_alias[tunable_num_env_alias] = { 0 };
while ((envp = get_next_env (envp, &envname, &envval, &prev_envp)) != NULL) while ((envp = get_next_env (envp, &envname, &envval, &prev_envp)) != NULL)
{ {
/* The environment variable is allocated on the stack by the kernel, so /* The environment variable is allocated on the stack by the kernel, so
@ -311,29 +314,44 @@ __tunables_init (char **envp)
continue; continue;
} }
for (int i = 0; i < tunables_list_size; i++) for (int i = 0; i < tunable_num_env_alias; i++)
{ {
tunable_t *cur = &tunable_list[i]; tunable_t *cur = &tunable_list[tunable_env_alias_list[i]];
/* Skip over tunables that have either been set already or should be
skipped. */
if (cur->initialized || cur->env_alias[0] == '\0')
continue;
const char *name = cur->env_alias; const char *name = cur->env_alias;
/* We have a match. Initialize and move on to the next line. */ if (name[0] == '\0')
continue;
if (tunable_is_name (name, envname)) if (tunable_is_name (name, envname))
{ {
size_t envvallen = 0; size_t envvallen = 0;
/* The environment variable is always null-terminated. */ /* The environment variable is always null-terminated. */
for (const char *p = envval; *p != '\0'; p++, envvallen++); for (const char *p = envval; *p != '\0'; p++, envvallen++);
tunable_initialize (cur, envval, envvallen); tunables_env_alias[i] =
(struct tunable_toset_t) { cur, envval, envvallen };
break; break;
} }
} }
} }
/* Check if glibc.rtld.enable_secure was set and skip over the environment
variables aliases. */
if (__libc_enable_secure)
return;
for (int i = 0; i < tunable_num_env_alias; i++)
{
/* Skip over tunables that have either been set or already initialized. */
if (tunables_env_alias[i].t == NULL
|| tunables_env_alias[i].t->initialized)
continue;
if (!tunable_initialize (tunables_env_alias[i].t,
tunables_env_alias[i].value,
tunables_env_alias[i].len))
parse_tunable_print_error (&tunables_env_alias[i]);
}
} }
void void

View File

@ -17,6 +17,10 @@
<https://www.gnu.org/licenses/>. */ <https://www.gnu.org/licenses/>. */
#include <array_length.h> #include <array_length.h>
/* The test uses the tunable_env_alias_list size, which is only exported for
ld.so. This will result in a copy of tunable_list and
tunable_env_alias_list, which is ununsed by the test itself. */
#define TUNABLES_INTERNAL 1
#include <dl-tunables.h> #include <dl-tunables.h>
#include <getopt.h> #include <getopt.h>
#include <intprops.h> #include <intprops.h>
@ -34,6 +38,8 @@ static int restart;
static const struct test_t static const struct test_t
{ {
const char *env; const char *env;
const char *extraenv;
bool check_multiple;
int32_t expected_malloc_check; int32_t expected_malloc_check;
int32_t expected_enable_secure; int32_t expected_enable_secure;
} tests[] = } tests[] =
@ -41,39 +47,124 @@ static const struct test_t
/* Expected tunable format. */ /* Expected tunable format. */
/* Tunables should be ignored if enable_secure is set. */ /* Tunables should be ignored if enable_secure is set. */
{ {
"glibc.malloc.check=2:glibc.rtld.enable_secure=1", "GLIBC_TUNABLES=glibc.malloc.check=2:glibc.rtld.enable_secure=1",
NULL,
false,
0, 0,
1, 1,
}, },
/* Tunables should be ignored if enable_secure is set. */ /* Tunables should be ignored if enable_secure is set. */
{ {
"glibc.rtld.enable_secure=1:glibc.malloc.check=2", "GLIBC_TUNABLES=glibc.rtld.enable_secure=1:glibc.malloc.check=2",
NULL,
false,
0, 0,
1, 1,
}, },
/* Tunables should be set if enable_secure is unset. */ /* Tunables should be set if enable_secure is unset. */
{ {
"glibc.rtld.enable_secure=0:glibc.malloc.check=2", "GLIBC_TUNABLES=glibc.rtld.enable_secure=0:glibc.malloc.check=2",
NULL,
false,
2, 2,
0, 0,
}, },
/* Tunables should be ignored if enable_secure is set. */
{
"GLIBC_TUNABLES=glibc.malloc.check=2:glibc.rtld.enable_secure=1",
"MALLOC_CHECK_=2",
false,
0,
1,
},
/* Same as before, but with enviroment alias prior GLIBC_TUNABLES. */
{
"MALLOC_CHECK_=2",
"GLIBC_TUNABLES=glibc.malloc.check=2:glibc.rtld.enable_secure=1",
false,
0,
1,
},
/* Tunables should be ignored if enable_secure is set. */
{
"GLIBC_TUNABLES=glibc.rtld.enable_secure=1:glibc.malloc.check=2",
"MALLOC_CHECK_=2",
false,
0,
1,
},
{
"MALLOC_CHECK_=2",
"GLIBC_TUNABLES=glibc.rtld.enable_secure=1:glibc.malloc.check=2",
false,
0,
1,
},
/* Tunables should be set if enable_secure is unset. */
{
"GLIBC_TUNABLES=glibc.rtld.enable_secure=0:glibc.malloc.check=2",
/* Tunable have precedence over the environment variable. */
"MALLOC_CHECK_=1",
false,
2,
0,
},
{
"MALLOC_CHECK_=1",
"GLIBC_TUNABLES=glibc.rtld.enable_secure=0:glibc.malloc.check=2",
/* Tunable have precedence over the environment variable. */
false,
2,
0,
},
/* Tunables should be set if enable_secure is unset. */
{
"GLIBC_TUNABLES=glibc.rtld.enable_secure=0",
/* Tunable have precedence over the environment variable. */
"MALLOC_CHECK_=1",
false,
1,
0,
},
/* Tunables should be set if enable_secure is unset. */
{
"GLIBC_TUNABLES=glibc.rtld.enable_secure=0",
/* Tunable have precedence over the environment variable. */
"MALLOC_CHECK_=1",
false,
1,
0,
},
/* Check with tunables environment variable alias set multiple times. */
{
"GLIBC_TUNABLES=glibc.rtld.enable_secure=1:glibc.malloc.check=2",
"MALLOC_CHECK_=2",
true,
0,
1,
},
/* Tunables should be set if enable_secure is unset. */
{
"GLIBC_TUNABLES=glibc.rtld.enable_secure=0",
/* Tunable have precedence over the environment variable. */
"MALLOC_CHECK_=1",
true,
1,
0,
},
}; };
static int static int
handle_restart (int i) handle_restart (int i)
{ {
if (tests[i].expected_enable_secure == 1) if (tests[i].expected_enable_secure == 1)
{ TEST_COMPARE (1, __libc_enable_secure);
TEST_COMPARE (1, __libc_enable_secure);
}
else else
{ TEST_COMPARE (tests[i].expected_enable_secure,
TEST_COMPARE (tests[i].expected_malloc_check, TUNABLE_GET_FULL (glibc, rtld, enable_secure, int32_t,
TUNABLE_GET_FULL (glibc, malloc, check, int32_t, NULL)); NULL));
TEST_COMPARE (tests[i].expected_enable_secure, TEST_COMPARE (tests[i].expected_malloc_check,
TUNABLE_GET_FULL (glibc, rtld, enable_secure, int32_t, TUNABLE_GET_FULL (glibc, malloc, check, int32_t, NULL));
NULL));
}
return 0; return 0;
} }
@ -106,14 +197,31 @@ do_test (int argc, char *argv[])
spargv[i] = NULL; spargv[i] = NULL;
} }
enum { tunable_num_env_alias = array_length (tunable_env_alias_list) };
for (int i = 0; i < array_length (tests); i++) for (int i = 0; i < array_length (tests); i++)
{ {
snprintf (nteststr, sizeof nteststr, "%d", i); snprintf (nteststr, sizeof nteststr, "%d", i);
printf ("[%d] Spawned test for %s\n", i, tests[i].env); printf ("[%d] Spawned test for %s\n", i, tests[i].env);
setenv ("GLIBC_TUNABLES", tests[i].env, 1); setenv ("GLIBC_TUNABLES", tests[i].env, 1);
char *envp[2 + tunable_num_env_alias + 1] =
{
(char *) tests[i].env,
(char *) tests[i].extraenv,
NULL,
};
if (tests[i].check_multiple)
{
int j;
for (j=0; j < tunable_num_env_alias; j++)
envp[j + 2] = (char *) tests[i].extraenv;
envp[j + 2] = NULL;
}
struct support_capture_subprocess result struct support_capture_subprocess result
= support_capture_subprogram (spargv[0], spargv, NULL); = support_capture_subprogram (spargv[0], spargv, envp);
support_capture_subprocess_check (&result, "tst-tunables-enable_secure", support_capture_subprocess_check (&result, "tst-tunables-enable_secure",
0, sc_allow_stderr); 0, sc_allow_stderr);
support_capture_subprocess_free (&result); support_capture_subprocess_free (&result);

View File

@ -156,7 +156,7 @@ END {
print "# define TUNABLE_ALIAS_MAX " (max_alias_len + 1) print "# define TUNABLE_ALIAS_MAX " (max_alias_len + 1)
print "# include \"dl-tunable-types.h\"" print "# include \"dl-tunable-types.h\""
# Finally, the tunable list. # Finally, the tunable list.
print "static tunable_t tunable_list[] attribute_relro = {" print "static tunable_t tunable_list[] attribute_relro __attribute_used__ = {"
for (tnm in types) { for (tnm in types) {
split (tnm, indices, SUBSEP); split (tnm, indices, SUBSEP);
t = indices[1]; t = indices[1];
@ -168,5 +168,19 @@ END {
default_val[t,n,m], env_alias[t,n,m]); default_val[t,n,m], env_alias[t,n,m]);
} }
print "};" print "};"
# Map of tunable with environment variables aliases used during parsing. */
print "\nstatic const tunable_id_t tunable_env_alias_list[] ="
printf "{\n"
for (tnm in types) {
split (tnm, indices, SUBSEP);
t = indices[1];
n = indices[2];
m = indices[3];
if (env_alias[t,n,m] != "{0}") {
printf (" TUNABLE_ENUM_NAME(%s, %s, %s),\n", t, n, m);
}
}
printf "};\n"
print "#endif" print "#endif"
} }