Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
glibc: patch CVE-2017-1000366 (stack clash)
(cherry picked from commit 2296bf3)
- Loading branch information
Showing
4 changed files
with
362 additions
and
0 deletions.
There are no files selected for viewing
209 changes: 209 additions & 0 deletions
209
pkgs/development/libraries/glibc/CVE-2017-1000366-rtld-LD_AUDIT.patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,209 @@ | ||
From ba67ba3275d47e0080f0e5f09d9f5102c000c97e Mon Sep 17 00:00:00 2001 | ||
Message-Id: <ba67ba3275d47e0080f0e5f09d9f5102c000c97e.1495998948.git.fweimer@redhat.com> | ||
In-Reply-To: <cover.1495998948.git.fweimer@redhat.com> | ||
References: <cover.1495998948.git.fweimer@redhat.com> | ||
From: Florian Weimer <fweimer@redhat.com> | ||
Date: Sun, 28 May 2017 20:44:52 +0200 | ||
Subject: [PATCH 3/3] rtld: Reject overly long LD_AUDIT path elements | ||
To: libc-alpha@sourceware.org | ||
|
||
Also only process the last LD_AUDIT entry. | ||
--- | ||
elf/rtld.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++--------- | ||
1 file changed, 95 insertions(+), 15 deletions(-) | ||
|
||
diff --git a/elf/rtld.c b/elf/rtld.c | ||
index 30f0cae..89d8573 100644 | ||
--- a/elf/rtld.c | ||
+++ b/elf/rtld.c | ||
@@ -116,13 +116,95 @@ dso_name_valid_for_suid (const char *p) | ||
return *p != '\0'; | ||
} | ||
|
||
-/* List of auditing DSOs. */ | ||
+/* LD_AUDIT variable contents. Must be processed before the | ||
+ audit_list below. */ | ||
+const char *audit_list_string; | ||
+ | ||
+/* Cyclic list of auditing DSOs. audit_list->next is the first | ||
+ element. */ | ||
static struct audit_list | ||
{ | ||
const char *name; | ||
struct audit_list *next; | ||
} *audit_list; | ||
|
||
+/* Iterator for audit_list_string followed by audit_list. */ | ||
+struct audit_list_iter | ||
+{ | ||
+ /* Tail of audit_list_string still needing processing, or NULL. */ | ||
+ const char *audit_list_tail; | ||
+ | ||
+ /* The list element returned in the previous iteration. NULL before | ||
+ the first element. */ | ||
+ struct audit_list *previous; | ||
+ | ||
+ /* Scratch buffer for returning a name which is part of | ||
+ audit_list_string. */ | ||
+#ifdef PATH_MAX | ||
+ char fname[PATH_MAX]; | ||
+#else | ||
+ char fname[4096]; | ||
+#endif | ||
+}; | ||
+ | ||
+/* Initialize an audit list iterator. */ | ||
+static void | ||
+audit_list_iter_init (struct audit_list_iter *iter) | ||
+{ | ||
+ iter->audit_list_tail = audit_list_string; | ||
+ iter->previous = NULL; | ||
+} | ||
+ | ||
+/* Iterate through both audit_list_string and audit_list. */ | ||
+static const char * | ||
+audit_list_iter_next (struct audit_list_iter *iter) | ||
+{ | ||
+ if (iter->audit_list_tail != NULL) | ||
+ { | ||
+ /* First iterate over audit_list_string. */ | ||
+ while (*iter->audit_list_tail != '\0') | ||
+ { | ||
+ /* Split audit list at colon. */ | ||
+ size_t len = strcspn (iter->audit_list_tail, ":"); | ||
+ if (len > 0 && len < sizeof(iter->fname)) | ||
+ { | ||
+ memcpy (iter->fname, iter->audit_list_tail, len); | ||
+ iter->fname[len] = '\0'; | ||
+ } | ||
+ else | ||
+ /* Do not return this name to the caller. */ | ||
+ iter->fname[0] = '\0'; | ||
+ | ||
+ /* Skip over the substring and the following delimiter. */ | ||
+ iter->audit_list_tail += len; | ||
+ if (*iter->audit_list_tail == ':') | ||
+ ++iter->audit_list_tail; | ||
+ | ||
+ /* If the name is valid, return it. */ | ||
+ if (dso_name_valid_for_suid (iter->fname)) | ||
+ return iter->fname; | ||
+ /* Otherwise, wrap around and try the next name. */ | ||
+ } | ||
+ /* Fall through to the procesing of audit_list. */ | ||
+ } | ||
+ | ||
+ if (iter->previous == NULL) | ||
+ { | ||
+ if (audit_list == NULL) | ||
+ /* No pre-parsed audit list. */ | ||
+ return NULL; | ||
+ /* Start of audit list. The first list element is at | ||
+ audit_list->next (cyclic list). */ | ||
+ iter->previous = audit_list->next; | ||
+ return iter->previous->name; | ||
+ } | ||
+ if (iter->previous == audit_list) | ||
+ /* Cyclic list wrap-around. */ | ||
+ return NULL; | ||
+ iter->previous = iter->previous->next; | ||
+ return iter->previous->name; | ||
+} | ||
+ | ||
#ifndef HAVE_INLINED_SYSCALLS | ||
/* Set nonzero during loading and initialization of executable and | ||
libraries, cleared before the executable's entry point runs. This | ||
@@ -1290,11 +1368,13 @@ of this helper program; chances are you did not intend to run this program.\n\ | ||
GL(dl_rtld_map).l_tls_modid = _dl_next_tls_modid (); | ||
|
||
/* If we have auditing DSOs to load, do it now. */ | ||
- if (__glibc_unlikely (audit_list != NULL)) | ||
+ bool need_security_init = true; | ||
+ if (__glibc_unlikely (audit_list != NULL) | ||
+ || __glibc_unlikely (audit_list_string != NULL)) | ||
{ | ||
- /* Iterate over all entries in the list. The order is important. */ | ||
struct audit_ifaces *last_audit = NULL; | ||
- struct audit_list *al = audit_list->next; | ||
+ struct audit_list_iter al_iter; | ||
+ audit_list_iter_init (&al_iter); | ||
|
||
/* Since we start using the auditing DSOs right away we need to | ||
initialize the data structures now. */ | ||
@@ -1305,9 +1385,14 @@ of this helper program; chances are you did not intend to run this program.\n\ | ||
use different values (especially the pointer guard) and will | ||
fail later on. */ | ||
security_init (); | ||
+ need_security_init = false; | ||
|
||
- do | ||
+ while (true) | ||
{ | ||
+ const char *name = audit_list_iter_next (&al_iter); | ||
+ if (name == NULL) | ||
+ break; | ||
+ | ||
int tls_idx = GL(dl_tls_max_dtv_idx); | ||
|
||
/* Now it is time to determine the layout of the static TLS | ||
@@ -1316,7 +1401,7 @@ of this helper program; chances are you did not intend to run this program.\n\ | ||
no DF_STATIC_TLS bit is set. The reason is that we know | ||
glibc will use the static model. */ | ||
struct dlmopen_args dlmargs; | ||
- dlmargs.fname = al->name; | ||
+ dlmargs.fname = name; | ||
dlmargs.map = NULL; | ||
|
||
const char *objname; | ||
@@ -1329,7 +1414,7 @@ of this helper program; chances are you did not intend to run this program.\n\ | ||
not_loaded: | ||
_dl_error_printf ("\ | ||
ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", | ||
- al->name, err_str); | ||
+ name, err_str); | ||
if (malloced) | ||
free ((char *) err_str); | ||
} | ||
@@ -1433,10 +1518,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", | ||
goto not_loaded; | ||
} | ||
} | ||
- | ||
- al = al->next; | ||
} | ||
- while (al != audit_list->next); | ||
|
||
/* If we have any auditing modules, announce that we already | ||
have two objects loaded. */ | ||
@@ -1700,7 +1782,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", | ||
if (tcbp == NULL) | ||
tcbp = init_tls (); | ||
|
||
- if (__glibc_likely (audit_list == NULL)) | ||
+ if (__glibc_likely (need_security_init)) | ||
/* Initialize security features. But only if we have not done it | ||
earlier. */ | ||
security_init (); | ||
@@ -2331,9 +2413,7 @@ process_dl_audit (char *str) | ||
char *p; | ||
|
||
while ((p = (strsep) (&str, ":")) != NULL) | ||
- if (p[0] != '\0' | ||
- && (__builtin_expect (! __libc_enable_secure, 1) | ||
- || strchr (p, '/') == NULL)) | ||
+ if (dso_name_valid_for_suid (p)) | ||
{ | ||
/* This is using the local malloc, not the system malloc. The | ||
memory can never be freed. */ | ||
@@ -2397,7 +2477,7 @@ process_envvars (enum mode *modep) | ||
break; | ||
} | ||
if (memcmp (envline, "AUDIT", 5) == 0) | ||
- process_dl_audit (&envline[6]); | ||
+ audit_list_string = &envline[6]; | ||
break; | ||
|
||
case 7: | ||
-- | ||
2.9.4 | ||
|
33 changes: 33 additions & 0 deletions
33
pkgs/development/libraries/glibc/CVE-2017-1000366-rtld-LD_LIBRARY_PATH.patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
From 4d009d39ac9ede0369e268554a181b428f177a80 Mon Sep 17 00:00:00 2001 | ||
Message-Id: <4d009d39ac9ede0369e268554a181b428f177a80.1495998948.git.fweimer@redhat.com> | ||
In-Reply-To: <cover.1495998948.git.fweimer@redhat.com> | ||
References: <cover.1495998948.git.fweimer@redhat.com> | ||
From: Florian Weimer <fweimer@redhat.com> | ||
Date: Sun, 28 May 2017 20:37:40 +0200 | ||
Subject: [PATCH 1/3] rtld: Completely ignore LD_LIBRARY_PATH for AT_SECURE=1 | ||
programs | ||
To: libc-alpha@sourceware.org | ||
|
||
LD_LIBRARY_PATH can only be used to reorder system search paths, which | ||
is not useful functionality. | ||
--- | ||
elf/rtld.c | 3 ++- | ||
1 file changed, 2 insertions(+), 1 deletion(-) | ||
|
||
diff --git a/elf/rtld.c b/elf/rtld.c | ||
index 319ef06..824b6cf 100644 | ||
--- a/elf/rtld.c | ||
+++ b/elf/rtld.c | ||
@@ -2419,7 +2419,8 @@ process_envvars (enum mode *modep) | ||
|
||
case 12: | ||
/* The library search path. */ | ||
- if (memcmp (envline, "LIBRARY_PATH", 12) == 0) | ||
+ if (!__libc_enable_secure | ||
+ && memcmp (envline, "LIBRARY_PATH", 12) == 0) | ||
{ | ||
library_path = &envline[13]; | ||
break; | ||
-- | ||
2.9.4 | ||
|
115 changes: 115 additions & 0 deletions
115
pkgs/development/libraries/glibc/CVE-2017-1000366-rtld-LD_PRELOAD.patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
From 65ff0b7a085b85271ec8fde99f542281b495e3bc Mon Sep 17 00:00:00 2001 | ||
Message-Id: <65ff0b7a085b85271ec8fde99f542281b495e3bc.1495998948.git.fweimer@redhat.com> | ||
In-Reply-To: <cover.1495998948.git.fweimer@redhat.com> | ||
References: <cover.1495998948.git.fweimer@redhat.com> | ||
From: Florian Weimer <fweimer@redhat.com> | ||
Date: Sun, 28 May 2017 20:57:40 +0200 | ||
Subject: [PATCH 2/3] rtld: Reject overly long LD_PRELOAD path elements | ||
To: libc-alpha@sourceware.org | ||
|
||
--- | ||
elf/rtld.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++--------------- | ||
1 file changed, 53 insertions(+), 16 deletions(-) | ||
|
||
diff --git a/elf/rtld.c b/elf/rtld.c | ||
index 824b6cf..30f0cae 100644 | ||
--- a/elf/rtld.c | ||
+++ b/elf/rtld.c | ||
@@ -99,6 +99,22 @@ uintptr_t __pointer_chk_guard_local | ||
strong_alias (__pointer_chk_guard_local, __pointer_chk_guard) | ||
#endif | ||
|
||
+/* Check that AT_SECURE=0, or that the passed name does not contain | ||
+ directories and is not overly long. Reject empty names | ||
+ unconditionally. */ | ||
+static bool | ||
+dso_name_valid_for_suid (const char *p) | ||
+{ | ||
+ if (__glibc_unlikely (__libc_enable_secure)) | ||
+ { | ||
+ /* Ignore pathnames with directories for AT_SECURE=1 | ||
+ programs, and also skip overlong names. */ | ||
+ size_t len = strlen (p); | ||
+ if (len >= NAME_MAX || memchr (p, '/', len) != NULL) | ||
+ return false; | ||
+ } | ||
+ return *p != '\0'; | ||
+} | ||
|
||
/* List of auditing DSOs. */ | ||
static struct audit_list | ||
@@ -716,6 +732,46 @@ static const char *preloadlist attribute_relro; | ||
/* Nonzero if information about versions has to be printed. */ | ||
static int version_info attribute_relro; | ||
|
||
+/* The LD_PRELOAD environment variable gives list of libraries | ||
+ separated by white space or colons that are loaded before the | ||
+ executable's dependencies and prepended to the global scope list. | ||
+ (If the binary is running setuid all elements containing a '/' are | ||
+ ignored since it is insecure.) Return the number of preloads | ||
+ performed. */ | ||
+unsigned int | ||
+handle_ld_preload (const char *preloadlist, struct link_map *main_map) | ||
+{ | ||
+ unsigned int npreloads = 0; | ||
+ const char *p = preloadlist; | ||
+#ifdef PATH_MAX | ||
+ char fname[PATH_MAX]; | ||
+#else | ||
+ char fname[4096]; | ||
+#endif | ||
+ | ||
+ while (*p != '\0') | ||
+ { | ||
+ /* Split preload list at space/colon. */ | ||
+ size_t len = strcspn (p, " :"); | ||
+ if (len > 0 && len < sizeof(fname)) | ||
+ { | ||
+ memcpy (fname, p, len); | ||
+ fname[len] = '\0'; | ||
+ } | ||
+ else | ||
+ fname[0] = '\0'; | ||
+ | ||
+ /* Skip over the substring and the following delimiter. */ | ||
+ p += len; | ||
+ if (*p == ' ' || *p == ':') | ||
+ ++p; | ||
+ | ||
+ if (dso_name_valid_for_suid (fname)) | ||
+ npreloads += do_preload (fname, main_map, "LD_PRELOAD"); | ||
+ } | ||
+ return npreloads; | ||
+} | ||
+ | ||
static void | ||
dl_main (const ElfW(Phdr) *phdr, | ||
ElfW(Word) phnum, | ||
@@ -1462,23 +1514,8 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", | ||
|
||
if (__glibc_unlikely (preloadlist != NULL)) | ||
{ | ||
- /* The LD_PRELOAD environment variable gives list of libraries | ||
- separated by white space or colons that are loaded before the | ||
- executable's dependencies and prepended to the global scope | ||
- list. If the binary is running setuid all elements | ||
- containing a '/' are ignored since it is insecure. */ | ||
- char *list = strdupa (preloadlist); | ||
- char *p; | ||
- | ||
HP_TIMING_NOW (start); | ||
- | ||
- /* Prevent optimizing strsep. Speed is not important here. */ | ||
- while ((p = (strsep) (&list, " :")) != NULL) | ||
- if (p[0] != '\0' | ||
- && (__builtin_expect (! __libc_enable_secure, 1) | ||
- || strchr (p, '/') == NULL)) | ||
- npreloads += do_preload (p, main_map, "LD_PRELOAD"); | ||
- | ||
+ npreloads += handle_ld_preload (preloadlist, main_map); | ||
HP_TIMING_NOW (stop); | ||
HP_TIMING_DIFF (diff, start, stop); | ||
HP_TIMING_ACCUM_NT (load_time, diff); | ||
-- | ||
2.9.4 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters