You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
164 lines
5.0 KiB
164 lines
5.0 KiB
This patch was developed under embargo and cannot reference an upstream |
|
commit. To find the associated commit please review the upstream git |
|
log for CVE-2023-4911 to identify the relevant commits. |
|
|
|
Author: Siddhesh Poyarekar <siddhesh@redhat.com> |
|
Date: Tue Sep 19 11:52:44 2023 -0400 |
|
|
|
tunables: Terminate if end of input is reached (CVE-2023-4911) |
|
|
|
The string parsing routine may end up writing beyond bounds of tunestr |
|
if the input tunable string is malformed, of the form name=name=val. |
|
This gets processed twice, first as name=name=val and next as name=val, |
|
resulting in tunestr being name=name=val:name=val, thus overflowing |
|
tunestr. |
|
|
|
Terminate the parsing loop at the first instance itself so that tunestr |
|
does not overflow. |
|
|
|
This also fixes up tst-env-setuid-tunables to actually handle failures |
|
correct and add new tests to validate the fix for this CVE. |
|
|
|
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org> |
|
Reviewed-by: Carlos O'Donell <carlos@redhat.com> |
|
--- |
|
Tested on x86_64. |
|
|
|
NEWS | 5 +++++ |
|
elf/dl-tunables.c | 17 ++++++++++------- |
|
elf/tst-env-setuid-tunables.c | 36 +++++++++++++++++++++++++++-------- |
|
3 files changed, 43 insertions(+), 15 deletions(-) |
|
|
|
Conflicts: |
|
NEWS |
|
(Dropped) |
|
elf/tst-env-setuid-tunables.c |
|
(Trivial HAVE_TUNABLES conflict) |
|
|
|
diff --git a/elf/dl-tunables.c b/elf/dl-tunables.c |
|
index 8009e54ee5db32be..837474b5044cb5d7 100644 |
|
--- a/elf/dl-tunables.c |
|
+++ b/elf/dl-tunables.c |
|
@@ -188,11 +188,7 @@ parse_tunables (char *tunestr, char *valstring) |
|
/* If we reach the end of the string before getting a valid name-value |
|
pair, bail out. */ |
|
if (p[len] == '\0') |
|
- { |
|
- if (__libc_enable_secure) |
|
- tunestr[off] = '\0'; |
|
- return; |
|
- } |
|
+ break; |
|
|
|
/* We did not find a valid name-value pair before encountering the |
|
colon. */ |
|
@@ -252,9 +248,16 @@ parse_tunables (char *tunestr, char *valstring) |
|
} |
|
} |
|
|
|
- if (p[len] != '\0') |
|
- p += len + 1; |
|
+ /* We reached the end while processing the tunable string. */ |
|
+ if (p[len] == '\0') |
|
+ break; |
|
+ |
|
+ p += len + 1; |
|
} |
|
+ |
|
+ /* Terminate tunestr before we leave. */ |
|
+ if (__libc_enable_secure) |
|
+ tunestr[off] = '\0'; |
|
} |
|
#endif |
|
|
|
diff --git a/elf/tst-env-setuid-tunables.c b/elf/tst-env-setuid-tunables.c |
|
index 05619c9adc8b2698..cd4e84364074c613 100644 |
|
--- a/elf/tst-env-setuid-tunables.c |
|
+++ b/elf/tst-env-setuid-tunables.c |
|
@@ -52,6 +52,8 @@ const char *teststrings[] = |
|
"glibc.malloc.perturb=0x800:not_valid.malloc.check=2:glibc.malloc.mmap_threshold=4096", |
|
"glibc.not_valid.check=2:glibc.malloc.mmap_threshold=4096", |
|
"not_valid.malloc.check=2:glibc.malloc.mmap_threshold=4096", |
|
+ "glibc.malloc.mmap_threshold=glibc.malloc.mmap_threshold=4096", |
|
+ "glibc.malloc.check=2", |
|
"glibc.malloc.garbage=2:glibc.maoc.mmap_threshold=4096:glibc.malloc.check=2", |
|
"glibc.malloc.check=4:glibc.malloc.garbage=2:glibc.maoc.mmap_threshold=4096", |
|
":glibc.malloc.garbage=2:glibc.malloc.check=1", |
|
@@ -70,6 +72,8 @@ const char *resultstrings[] = |
|
"glibc.malloc.perturb=0x800:glibc.malloc.mmap_threshold=4096", |
|
"glibc.malloc.mmap_threshold=4096", |
|
"glibc.malloc.mmap_threshold=4096", |
|
+ "glibc.malloc.mmap_threshold=glibc.malloc.mmap_threshold=4096", |
|
+ "", |
|
"", |
|
"", |
|
"", |
|
@@ -84,11 +88,18 @@ test_child (int off) |
|
const char *val = getenv ("GLIBC_TUNABLES"); |
|
|
|
#if HAVE_TUNABLES |
|
+ printf (" [%d] GLIBC_TUNABLES is %s\n", off, val); |
|
+ fflush (stdout); |
|
if (val != NULL && strcmp (val, resultstrings[off]) == 0) |
|
return 0; |
|
|
|
if (val != NULL) |
|
- printf ("[%d] Unexpected GLIBC_TUNABLES VALUE %s\n", off, val); |
|
+ printf (" [%d] Unexpected GLIBC_TUNABLES VALUE %s, expected %s\n", |
|
+ off, val, resultstrings[off]); |
|
+ else |
|
+ printf (" [%d] GLIBC_TUNABLES environment variable absent\n", off); |
|
+ |
|
+ fflush (stdout); |
|
|
|
return 1; |
|
#else |
|
@@ -117,21 +128,26 @@ do_test (int argc, char **argv) |
|
if (ret != 0) |
|
exit (1); |
|
|
|
- exit (EXIT_SUCCESS); |
|
+ /* Special return code to make sure that the child executed all the way |
|
+ through. */ |
|
+ exit (42); |
|
} |
|
else |
|
{ |
|
- int ret = 0; |
|
- |
|
/* Spawn tests. */ |
|
for (int i = 0; i < array_length (teststrings); i++) |
|
{ |
|
char buf[INT_BUFSIZE_BOUND (int)]; |
|
|
|
- printf ("Spawned test for %s (%d)\n", teststrings[i], i); |
|
+ printf ("[%d] Spawned test for %s\n", i, teststrings[i]); |
|
snprintf (buf, sizeof (buf), "%d\n", i); |
|
+ fflush (stdout); |
|
if (setenv ("GLIBC_TUNABLES", teststrings[i], 1) != 0) |
|
- exit (1); |
|
+ { |
|
+ printf (" [%d] Failed to set GLIBC_TUNABLES: %m", i); |
|
+ support_record_failure (); |
|
+ continue; |
|
+ } |
|
|
|
int status = support_capture_subprogram_self_sgid (buf); |
|
|
|
@@ -139,9 +155,14 @@ do_test (int argc, char **argv) |
|
if (WEXITSTATUS (status) == EXIT_UNSUPPORTED) |
|
return EXIT_UNSUPPORTED; |
|
|
|
- ret |= status; |
|
+ if (WEXITSTATUS (status) != 42) |
|
+ { |
|
+ printf (" [%d] child failed with status %d\n", i, |
|
+ WEXITSTATUS (status)); |
|
+ support_record_failure (); |
|
+ } |
|
} |
|
- return ret; |
|
+ return 0; |
|
} |
|
} |
|
|
|
|