aboutsummaryrefslogtreecommitdiff
path: root/stdlib/setenv.h
diff options
context:
space:
mode:
authorFlorian Weimer <fweimer@redhat.com>2025-01-24 10:40:28 +0100
committerFlorian Weimer <fweimer@redhat.com>2025-01-24 22:37:49 +0100
commit12b4a1fc6ecfc278a87159164bdf1d682deb18e2 (patch)
tree58c18725571c1c62a98d8798f44f61ac278a03f7 /stdlib/setenv.h
parent36fcdfbbc5463e55581fec67141df3493fb81f7e (diff)
downloadglibc-12b4a1fc6ecfc278a87159164bdf1d682deb18e2.tar.xz
glibc-12b4a1fc6ecfc278a87159164bdf1d682deb18e2.zip
stdlib: Re-implement free (environ) compatibility kludge for setenv
For the originally failing application (userhelper from usermode), it is not actually necessary to call realloc on the environ pointer. Yes, there will be a memory leak because the application assigns a heap-allocated pointer to environ that it never frees, but this leak was always there: the old realloc-based setenv had a hidden internal variable, last_environ, that was used in a similar way to __environ_array_list. The application is not impacted by the leak anyway because the relevant operations do not happen in a loop. The change here just uses a separte heap allocation and points environ to that. This means that if an application calls free (environ) and restores the environ pointer to the value at process start, and does not modify the environment further, nothing bad happens. This change should not invalidate any previous testing that went into the original getenv thread safety change, commit 7a61e7f557a97ab597d6 ("stdlib: Make getenv thread-safe in more cases"). The new test cases are modeled in part on the env -i use case from bug 32588 (with !DO_MALLOC && !DO_EARLY_SETENV), and the previous stdlib/tst-setenv-malloc test. The DO_MALLOC && !DO_EARLY_SETENV case in the new test should approximate what userhelper from the usermode package does. Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Diffstat (limited to 'stdlib/setenv.h')
-rw-r--r--stdlib/setenv.h15
1 files changed, 12 insertions, 3 deletions
diff --git a/stdlib/setenv.h b/stdlib/setenv.h
index e4433f5f84..7cbf9f2059 100644
--- a/stdlib/setenv.h
+++ b/stdlib/setenv.h
@@ -29,9 +29,18 @@
of environment values used before. */
struct environ_array
{
- struct environ_array *next; /* Previously used environment array. */
+ /* The actual environment array. Use a separate allocation (and not
+ a flexible array member) so that calls like free (environ) that
+ have been encountered in some applications do not crash
+ immediately. With such a call, if the application restores the
+ original environ pointer at process start and does not modify the
+ environment again, a use-after-free situation only occurs during
+ __libc_freeres, which is only called during memory debugging.
+ With subsequent setenv calls, there is still heap corruption, but
+ that happened with the old realloc-based implementation, too. */
+ char **array;
size_t allocated; /* Number of allocated array elments. */
- char *array[]; /* The actual environment array. */
+ struct environ_array *next; /* Previously used environment array. */
};
/* After initialization, and until the user resets environ (perhaps by
@@ -44,7 +53,7 @@ static inline bool
__environ_is_from_array_list (char **ep)
{
struct environ_array *eal = atomic_load_relaxed (&__environ_array_list);
- return eal != NULL && &eal->array[0] == ep;
+ return eal != NULL && eal->array == ep;
}
/* Counter for detecting concurrent modification in unsetenv.