glibc/elf/tst-tunables-enable_secure-env.c

155 lines
4.1 KiB
C
Raw Normal View History

/* Check enable_secure tunable handles removed ENV variables without
assertions.
Copyright (C) 2024 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
elf/rtld: Fix auxiliary vector for enable_secure Starting with commit 59974938fe1f4add843f5325f78e2a7ccd8db853 elf/rtld: Count skipped environment variables for enable_secure The new testcase elf/tst-tunables-enable_secure-env segfaults on s390 (31bit). There _start parses the auxiliary vector for some additional checks. Therefore it skips over the zeros after the environment variables ... 0x7fffac20: 0x7fffbd17 0x7fffbd32 0x7fffbd69 0x00000000 ------------------------------------------------^^^last environment variable ... and then it parses the auxiliary vector and stops at AT_NULL. 0x7fffac30: 0x00000000 0x00000021 0x00000000 0x00000000 --------------------------------^^^AT_SYSINFO_EHDR--------------^^^AT_NULL ----------------^^^newp-----------------------------------------^^^oldp Afterwards it tries to access AT_PHDR which points to somewhere and segfaults. Due to not incorporating the skip_env variable in the computation of oldp when shuffling down the auxv in rtld.c, it just copies one entry with AT_NULL and value 0x00000021 and stops the loop. In reality we have skipped GLIBC_TUNABLES environment variable (=> skip_env=1). Thus we should copy from here: 0x7fffac40: 0x00000021 0x7ffff000 0x00000010 0x007fffff ----------------^^^fixed-oldp This patch fixes the computation of oldp when shuffling down auxiliary vector. It also adds some checks in the testcase. Those checks also fail on s390x (64bit) and x86_64 without the fix. Co-authored-by: Adhemerval Zanella <adhemerval.zanella@linaro.org> Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
2024-07-02 21:25:20 +08:00
#include <array_length.h>
#include <errno.h>
#include <getopt.h>
#include <intprops.h>
#include <stdlib.h>
#include <support/capture_subprocess.h>
#include <support/check.h>
elf/rtld: Fix auxiliary vector for enable_secure Starting with commit 59974938fe1f4add843f5325f78e2a7ccd8db853 elf/rtld: Count skipped environment variables for enable_secure The new testcase elf/tst-tunables-enable_secure-env segfaults on s390 (31bit). There _start parses the auxiliary vector for some additional checks. Therefore it skips over the zeros after the environment variables ... 0x7fffac20: 0x7fffbd17 0x7fffbd32 0x7fffbd69 0x00000000 ------------------------------------------------^^^last environment variable ... and then it parses the auxiliary vector and stops at AT_NULL. 0x7fffac30: 0x00000000 0x00000021 0x00000000 0x00000000 --------------------------------^^^AT_SYSINFO_EHDR--------------^^^AT_NULL ----------------^^^newp-----------------------------------------^^^oldp Afterwards it tries to access AT_PHDR which points to somewhere and segfaults. Due to not incorporating the skip_env variable in the computation of oldp when shuffling down the auxv in rtld.c, it just copies one entry with AT_NULL and value 0x00000021 and stops the loop. In reality we have skipped GLIBC_TUNABLES environment variable (=> skip_env=1). Thus we should copy from here: 0x7fffac40: 0x00000021 0x7ffff000 0x00000010 0x007fffff ----------------^^^fixed-oldp This patch fixes the computation of oldp when shuffling down auxiliary vector. It also adds some checks in the testcase. Those checks also fail on s390x (64bit) and x86_64 without the fix. Co-authored-by: Adhemerval Zanella <adhemerval.zanella@linaro.org> Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
2024-07-02 21:25:20 +08:00
#ifdef __linux__
# define HAVE_AUXV 1
# include <sys/auxv.h>
#else
# define HAVE_AUXV 0
#endif
/* Nonzero if the program gets called via `exec'. */
#define CMDLINE_OPTIONS \
{ "restart", no_argument, &restart, 1 },
static int restart;
/* Hold the four initial argument used to respawn the process, plus the extra
'--direct', '--restart', auxiliary vector values, and final NULL. */
static char *spargs[11];
#if HAVE_AUXV
static void
check_auxv (unsigned long type, char *argv)
{
char *endptr;
errno = 0;
unsigned long int varg = strtoul (argv, &endptr, 10);
elf/rtld: Fix auxiliary vector for enable_secure Starting with commit 59974938fe1f4add843f5325f78e2a7ccd8db853 elf/rtld: Count skipped environment variables for enable_secure The new testcase elf/tst-tunables-enable_secure-env segfaults on s390 (31bit). There _start parses the auxiliary vector for some additional checks. Therefore it skips over the zeros after the environment variables ... 0x7fffac20: 0x7fffbd17 0x7fffbd32 0x7fffbd69 0x00000000 ------------------------------------------------^^^last environment variable ... and then it parses the auxiliary vector and stops at AT_NULL. 0x7fffac30: 0x00000000 0x00000021 0x00000000 0x00000000 --------------------------------^^^AT_SYSINFO_EHDR--------------^^^AT_NULL ----------------^^^newp-----------------------------------------^^^oldp Afterwards it tries to access AT_PHDR which points to somewhere and segfaults. Due to not incorporating the skip_env variable in the computation of oldp when shuffling down the auxv in rtld.c, it just copies one entry with AT_NULL and value 0x00000021 and stops the loop. In reality we have skipped GLIBC_TUNABLES environment variable (=> skip_env=1). Thus we should copy from here: 0x7fffac40: 0x00000021 0x7ffff000 0x00000010 0x007fffff ----------------^^^fixed-oldp This patch fixes the computation of oldp when shuffling down auxiliary vector. It also adds some checks in the testcase. Those checks also fail on s390x (64bit) and x86_64 without the fix. Co-authored-by: Adhemerval Zanella <adhemerval.zanella@linaro.org> Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
2024-07-02 21:25:20 +08:00
TEST_VERIFY_EXIT (errno == 0);
TEST_VERIFY_EXIT (*endptr == '\0');
errno = 0;
unsigned long int v = getauxval (type);
TEST_COMPARE (errno, 0);
TEST_COMPARE (varg, v);
}
#endif
/* Called on process re-execution. */
_Noreturn static void
handle_restart (int argc, char *argv[])
{
TEST_VERIFY (getenv ("GLIBC_TUNABLES") == NULL);
TEST_VERIFY (getenv ("LD_BIND_NOW") == NULL);
#if HAVE_AUXV
TEST_VERIFY_EXIT (argc == 4);
check_auxv (AT_PHENT, argv[0]);
check_auxv (AT_PHNUM, argv[1]);
check_auxv (AT_PAGESZ, argv[2]);
check_auxv (AT_HWCAP, argv[3]);
#endif
exit (EXIT_SUCCESS);
}
static int
do_test (int argc, char *argv[])
{
elf/rtld: Fix auxiliary vector for enable_secure Starting with commit 59974938fe1f4add843f5325f78e2a7ccd8db853 elf/rtld: Count skipped environment variables for enable_secure The new testcase elf/tst-tunables-enable_secure-env segfaults on s390 (31bit). There _start parses the auxiliary vector for some additional checks. Therefore it skips over the zeros after the environment variables ... 0x7fffac20: 0x7fffbd17 0x7fffbd32 0x7fffbd69 0x00000000 ------------------------------------------------^^^last environment variable ... and then it parses the auxiliary vector and stops at AT_NULL. 0x7fffac30: 0x00000000 0x00000021 0x00000000 0x00000000 --------------------------------^^^AT_SYSINFO_EHDR--------------^^^AT_NULL ----------------^^^newp-----------------------------------------^^^oldp Afterwards it tries to access AT_PHDR which points to somewhere and segfaults. Due to not incorporating the skip_env variable in the computation of oldp when shuffling down the auxv in rtld.c, it just copies one entry with AT_NULL and value 0x00000021 and stops the loop. In reality we have skipped GLIBC_TUNABLES environment variable (=> skip_env=1). Thus we should copy from here: 0x7fffac40: 0x00000021 0x7ffff000 0x00000010 0x007fffff ----------------^^^fixed-oldp This patch fixes the computation of oldp when shuffling down auxiliary vector. It also adds some checks in the testcase. Those checks also fail on s390x (64bit) and x86_64 without the fix. Co-authored-by: Adhemerval Zanella <adhemerval.zanella@linaro.org> Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
2024-07-02 21:25:20 +08:00
/* We must have either:
- four parameter if called initially:
+ path for ld.so [optional]
+ "--library-path" [optional]
+ the library path [optional]
+ the application name
- either parameters left if called through re-execution.
+ auxiliary vector value 1
+ auxiliary vector value 2
+ auxiliary vector value 3
+ auxiliary vector value 4
*/
if (restart)
handle_restart (argc - 1, &argv[1]);
TEST_VERIFY_EXIT (argc == 2 || argc == 5);
#if HAVE_AUXV
struct
{
unsigned long int type;
char str[INT_BUFSIZE_BOUND (unsigned long)];
} auxvals[] =
{
/* Check some auxiliary values that should be constant over process
re-execution. */
{ AT_PHENT },
{ AT_PHNUM },
{ AT_PAGESZ },
{ AT_HWCAP },
};
for (int i = 0; i < array_length (auxvals); i++)
{
unsigned long int v = getauxval (auxvals[i].type);
snprintf (auxvals[i].str, sizeof auxvals[i].str, "%lu", v);
}
#endif
{
int i;
for (i = 0; i < argc - 1; i++)
spargs[i] = argv[i + 1];
spargs[i++] = (char *) "--direct";
spargs[i++] = (char *) "--restart";
#if HAVE_AUXV
for (int j = 0; j < array_length (auxvals); j++)
spargs[i++] = auxvals[j].str;
#endif
spargs[i] = NULL;
}
{
char *envs[] =
{
/* Add some environment variable that should be filtered out. */
(char *) "GLIBC_TUNABLES=glibc.rtld.enable_secure=1",
(char* ) "LD_BIND_NOW=0",
NULL,
};
struct support_capture_subprocess result
= support_capture_subprogram (spargs[0], spargs, envs);
support_capture_subprocess_check (&result,
"tst-tunables-enable_secure-env",
0,
sc_allow_none);
support_capture_subprocess_free (&result);
}
return 0;
}
#define TEST_FUNCTION_ARGV do_test
#include <support/test-driver.c>