Fix elf/tst-env-setuid[-static] if test needs to be rerun.

If /tmp is mounted nosuid and make xcheck is run,
then tst-env-setuid fails UNSUPPORTED with "SGID failed: GID and EGID match"
and /var/tmp/tst-sonamemove-runmod1.so.profile is created.

If you then try to rerun the test with a suid mounted test-dir
(the SGID binary is created in test-dir which defaults to /tmp)
with something like that:
make tst-env-setuid-ENV="TMPDIR=..." t=elf/tst-env-setuid test
the test fails as the LD_PROFILE output file is still available
from the previous run.

Thus this patch removes the LD_PROFILE output file in parent
before spawning the SGID binary.

Even if LD_PROFILE is not supported anymore in static binaries,
use a different library and thus output file for tst-env-setuid
and tst-env-setuid-static in order to not interfere if both
tests are run in parallel.

Furthermore the checks in test_child are now more verbose.
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
This commit is contained in:
Stefan Liebler 2023-12-13 12:44:50 +01:00
parent 50bef9bd63
commit 3150cc0c90
3 changed files with 42 additions and 6 deletions

View File

@ -3015,6 +3015,7 @@ tst-env-setuid-ARGS = -- $(host-test-program-cmd)
# Reuse a module with a SONAME, to specific as the LD_PROFILE. # Reuse a module with a SONAME, to specific as the LD_PROFILE.
$(objpfx)tst-env-setuid: $(objpfx)tst-sonamemove-runmod2.so $(objpfx)tst-env-setuid: $(objpfx)tst-sonamemove-runmod2.so
$(objpfx)tst-env-setuid-static.out: $(objpfx)tst-sonamemove-runmod1.so
# The object tst-nodeps1-mod.so has no explicit dependencies on libc.so. # The object tst-nodeps1-mod.so has no explicit dependencies on libc.so.
$(objpfx)tst-nodeps1-mod.so: $(objpfx)tst-nodeps1-mod.os $(objpfx)tst-nodeps1-mod.so: $(objpfx)tst-nodeps1-mod.os

View File

@ -1 +1,2 @@
#define PROFILE_LIB "tst-sonamemove-runmod1.so"
#include "tst-env-setuid.c" #include "tst-env-setuid.c"

View File

@ -36,7 +36,9 @@ static char SETGID_CHILD[] = "setgid-child";
#define UNFILTERED_VALUE "some-unfiltered-value" #define UNFILTERED_VALUE "some-unfiltered-value"
/* It assumes no other programs is being profile with a library with same /* It assumes no other programs is being profile with a library with same
SONAME using the default folder. */ SONAME using the default folder. */
#define PROFILE_LIB "tst-sonamemove-runmod2.so" #ifndef PROFILE_LIB
# define PROFILE_LIB "tst-sonamemove-runmod2.so"
#endif
struct envvar_t struct envvar_t
{ {
@ -53,7 +55,7 @@ static const struct envvar_t filtered_envvars[] =
{ "LD_HWCAP_MASK", FILTERED_VALUE }, { "LD_HWCAP_MASK", FILTERED_VALUE },
{ "LD_LIBRARY_PATH", FILTERED_VALUE }, { "LD_LIBRARY_PATH", FILTERED_VALUE },
{ "LD_PRELOAD", FILTERED_VALUE }, { "LD_PRELOAD", FILTERED_VALUE },
{ "LD_PROFILE", "tst-sonamemove-runmod2.so" }, { "LD_PROFILE", PROFILE_LIB },
{ "MALLOC_ARENA_MAX", FILTERED_VALUE }, { "MALLOC_ARENA_MAX", FILTERED_VALUE },
{ "MALLOC_PERTURB_", FILTERED_VALUE }, { "MALLOC_PERTURB_", FILTERED_VALUE },
{ "MALLOC_TRACE", FILTERED_VALUE }, { "MALLOC_TRACE", FILTERED_VALUE },
@ -83,7 +85,12 @@ test_child (void)
e++) e++)
{ {
const char *env = getenv (e->env); const char *env = getenv (e->env);
ret |= env != NULL; if (env != NULL)
{
printf ("FAIL: filtered environment variable is not NULL: %s=%s\n",
e->env, env);
ret = 1;
}
} }
for (const struct envvar_t *e = unfiltered_envvars; for (const struct envvar_t *e = unfiltered_envvars;
@ -91,13 +98,30 @@ test_child (void)
e++) e++)
{ {
const char *env = getenv (e->env); const char *env = getenv (e->env);
ret |= !(env != NULL && strcmp (env, e->value) == 0); if (!(env != NULL && strcmp (env, e->value) == 0))
{
if (env == NULL)
printf ("FAIL: unfiltered environment variable %s is NULL\n",
e->env);
else
printf ("FAIL: unfiltered environment variable %s=%s != %s\n",
e->env, env, e->value);
ret = 1;
}
} }
/* Also check if no profile file was created. */ /* Also check if no profile file was created.
The parent sets LD_DEBUG_OUTPUT="/tmp/some-file"
which should be filtered. Then it falls back to "/var/tmp".
Note: LD_PROFILE is not supported for static binaries. */
{ {
char *profilepath = xasprintf ("/var/tmp/%s.profile", PROFILE_LIB); char *profilepath = xasprintf ("/var/tmp/%s.profile", PROFILE_LIB);
ret |= !access (profilepath, R_OK); if (!access (profilepath, R_OK))
{
printf ("FAIL: LD_PROFILE file at %s was created!\n", profilepath);
ret = 1;
}
free (profilepath); free (profilepath);
} }
@ -141,6 +165,16 @@ do_test (int argc, char **argv)
e++) e++)
setenv (e->env, e->value, 1); setenv (e->env, e->value, 1);
/* Ensure that the profile output does not exist from a previous run
(e.g. if test_dir, which defaults to /tmp, is mounted nosuid.)
Note: support_capture_subprogram_self_sgid creates the SGID binary
in test_dir. */
{
char *profilepath = xasprintf ("/var/tmp/%s.profile", PROFILE_LIB);
unlink (profilepath);
free (profilepath);
}
int status = support_capture_subprogram_self_sgid (SETGID_CHILD); int status = support_capture_subprogram_self_sgid (SETGID_CHILD);
if (WEXITSTATUS (status) == EXIT_UNSUPPORTED) if (WEXITSTATUS (status) == EXIT_UNSUPPORTED)