glibc: patch CVE-2017-1000366 (stack clash)

+362
+209
pkgs/development/libraries/glibc/CVE-2017-1000366-rtld-LD_AUDIT.patch
···
··· 1 + From ba67ba3275d47e0080f0e5f09d9f5102c000c97e Mon Sep 17 00:00:00 2001 2 + Message-Id: <ba67ba3275d47e0080f0e5f09d9f5102c000c97e.1495998948.git.fweimer@redhat.com> 3 + In-Reply-To: <cover.1495998948.git.fweimer@redhat.com> 4 + References: <cover.1495998948.git.fweimer@redhat.com> 5 + From: Florian Weimer <fweimer@redhat.com> 6 + Date: Sun, 28 May 2017 20:44:52 +0200 7 + Subject: [PATCH 3/3] rtld: Reject overly long LD_AUDIT path elements 8 + To: libc-alpha@sourceware.org 9 + 10 + Also only process the last LD_AUDIT entry. 11 + --- 12 + elf/rtld.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++--------- 13 + 1 file changed, 95 insertions(+), 15 deletions(-) 14 + 15 + diff --git a/elf/rtld.c b/elf/rtld.c 16 + index 30f0cae..89d8573 100644 17 + --- a/elf/rtld.c 18 + +++ b/elf/rtld.c 19 + @@ -116,13 +116,95 @@ dso_name_valid_for_suid (const char *p) 20 + return *p != '\0'; 21 + } 22 + 23 + -/* List of auditing DSOs. */ 24 + +/* LD_AUDIT variable contents. Must be processed before the 25 + + audit_list below. */ 26 + +const char *audit_list_string; 27 + + 28 + +/* Cyclic list of auditing DSOs. audit_list->next is the first 29 + + element. */ 30 + static struct audit_list 31 + { 32 + const char *name; 33 + struct audit_list *next; 34 + } *audit_list; 35 + 36 + +/* Iterator for audit_list_string followed by audit_list. */ 37 + +struct audit_list_iter 38 + +{ 39 + + /* Tail of audit_list_string still needing processing, or NULL. */ 40 + + const char *audit_list_tail; 41 + + 42 + + /* The list element returned in the previous iteration. NULL before 43 + + the first element. */ 44 + + struct audit_list *previous; 45 + + 46 + + /* Scratch buffer for returning a name which is part of 47 + + audit_list_string. */ 48 + +#ifdef PATH_MAX 49 + + char fname[PATH_MAX]; 50 + +#else 51 + + char fname[4096]; 52 + +#endif 53 + +}; 54 + + 55 + +/* Initialize an audit list iterator. */ 56 + +static void 57 + +audit_list_iter_init (struct audit_list_iter *iter) 58 + +{ 59 + + iter->audit_list_tail = audit_list_string; 60 + + iter->previous = NULL; 61 + +} 62 + + 63 + +/* Iterate through both audit_list_string and audit_list. */ 64 + +static const char * 65 + +audit_list_iter_next (struct audit_list_iter *iter) 66 + +{ 67 + + if (iter->audit_list_tail != NULL) 68 + + { 69 + + /* First iterate over audit_list_string. */ 70 + + while (*iter->audit_list_tail != '\0') 71 + + { 72 + + /* Split audit list at colon. */ 73 + + size_t len = strcspn (iter->audit_list_tail, ":"); 74 + + if (len > 0 && len < sizeof(iter->fname)) 75 + + { 76 + + memcpy (iter->fname, iter->audit_list_tail, len); 77 + + iter->fname[len] = '\0'; 78 + + } 79 + + else 80 + + /* Do not return this name to the caller. */ 81 + + iter->fname[0] = '\0'; 82 + + 83 + + /* Skip over the substring and the following delimiter. */ 84 + + iter->audit_list_tail += len; 85 + + if (*iter->audit_list_tail == ':') 86 + + ++iter->audit_list_tail; 87 + + 88 + + /* If the name is valid, return it. */ 89 + + if (dso_name_valid_for_suid (iter->fname)) 90 + + return iter->fname; 91 + + /* Otherwise, wrap around and try the next name. */ 92 + + } 93 + + /* Fall through to the procesing of audit_list. */ 94 + + } 95 + + 96 + + if (iter->previous == NULL) 97 + + { 98 + + if (audit_list == NULL) 99 + + /* No pre-parsed audit list. */ 100 + + return NULL; 101 + + /* Start of audit list. The first list element is at 102 + + audit_list->next (cyclic list). */ 103 + + iter->previous = audit_list->next; 104 + + return iter->previous->name; 105 + + } 106 + + if (iter->previous == audit_list) 107 + + /* Cyclic list wrap-around. */ 108 + + return NULL; 109 + + iter->previous = iter->previous->next; 110 + + return iter->previous->name; 111 + +} 112 + + 113 + #ifndef HAVE_INLINED_SYSCALLS 114 + /* Set nonzero during loading and initialization of executable and 115 + libraries, cleared before the executable's entry point runs. This 116 + @@ -1290,11 +1368,13 @@ of this helper program; chances are you did not intend to run this program.\n\ 117 + GL(dl_rtld_map).l_tls_modid = _dl_next_tls_modid (); 118 + 119 + /* If we have auditing DSOs to load, do it now. */ 120 + - if (__glibc_unlikely (audit_list != NULL)) 121 + + bool need_security_init = true; 122 + + if (__glibc_unlikely (audit_list != NULL) 123 + + || __glibc_unlikely (audit_list_string != NULL)) 124 + { 125 + - /* Iterate over all entries in the list. The order is important. */ 126 + struct audit_ifaces *last_audit = NULL; 127 + - struct audit_list *al = audit_list->next; 128 + + struct audit_list_iter al_iter; 129 + + audit_list_iter_init (&al_iter); 130 + 131 + /* Since we start using the auditing DSOs right away we need to 132 + initialize the data structures now. */ 133 + @@ -1305,9 +1385,14 @@ of this helper program; chances are you did not intend to run this program.\n\ 134 + use different values (especially the pointer guard) and will 135 + fail later on. */ 136 + security_init (); 137 + + need_security_init = false; 138 + 139 + - do 140 + + while (true) 141 + { 142 + + const char *name = audit_list_iter_next (&al_iter); 143 + + if (name == NULL) 144 + + break; 145 + + 146 + int tls_idx = GL(dl_tls_max_dtv_idx); 147 + 148 + /* Now it is time to determine the layout of the static TLS 149 + @@ -1316,7 +1401,7 @@ of this helper program; chances are you did not intend to run this program.\n\ 150 + no DF_STATIC_TLS bit is set. The reason is that we know 151 + glibc will use the static model. */ 152 + struct dlmopen_args dlmargs; 153 + - dlmargs.fname = al->name; 154 + + dlmargs.fname = name; 155 + dlmargs.map = NULL; 156 + 157 + const char *objname; 158 + @@ -1329,7 +1414,7 @@ of this helper program; chances are you did not intend to run this program.\n\ 159 + not_loaded: 160 + _dl_error_printf ("\ 161 + ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", 162 + - al->name, err_str); 163 + + name, err_str); 164 + if (malloced) 165 + free ((char *) err_str); 166 + } 167 + @@ -1433,10 +1518,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", 168 + goto not_loaded; 169 + } 170 + } 171 + - 172 + - al = al->next; 173 + } 174 + - while (al != audit_list->next); 175 + 176 + /* If we have any auditing modules, announce that we already 177 + have two objects loaded. */ 178 + @@ -1700,7 +1782,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", 179 + if (tcbp == NULL) 180 + tcbp = init_tls (); 181 + 182 + - if (__glibc_likely (audit_list == NULL)) 183 + + if (__glibc_likely (need_security_init)) 184 + /* Initialize security features. But only if we have not done it 185 + earlier. */ 186 + security_init (); 187 + @@ -2331,9 +2413,7 @@ process_dl_audit (char *str) 188 + char *p; 189 + 190 + while ((p = (strsep) (&str, ":")) != NULL) 191 + - if (p[0] != '\0' 192 + - && (__builtin_expect (! __libc_enable_secure, 1) 193 + - || strchr (p, '/') == NULL)) 194 + + if (dso_name_valid_for_suid (p)) 195 + { 196 + /* This is using the local malloc, not the system malloc. The 197 + memory can never be freed. */ 198 + @@ -2397,7 +2477,7 @@ process_envvars (enum mode *modep) 199 + break; 200 + } 201 + if (memcmp (envline, "AUDIT", 5) == 0) 202 + - process_dl_audit (&envline[6]); 203 + + audit_list_string = &envline[6]; 204 + break; 205 + 206 + case 7: 207 + -- 208 + 2.9.4 209 +
+33
pkgs/development/libraries/glibc/CVE-2017-1000366-rtld-LD_LIBRARY_PATH.patch
···
··· 1 + From 4d009d39ac9ede0369e268554a181b428f177a80 Mon Sep 17 00:00:00 2001 2 + Message-Id: <4d009d39ac9ede0369e268554a181b428f177a80.1495998948.git.fweimer@redhat.com> 3 + In-Reply-To: <cover.1495998948.git.fweimer@redhat.com> 4 + References: <cover.1495998948.git.fweimer@redhat.com> 5 + From: Florian Weimer <fweimer@redhat.com> 6 + Date: Sun, 28 May 2017 20:37:40 +0200 7 + Subject: [PATCH 1/3] rtld: Completely ignore LD_LIBRARY_PATH for AT_SECURE=1 8 + programs 9 + To: libc-alpha@sourceware.org 10 + 11 + LD_LIBRARY_PATH can only be used to reorder system search paths, which 12 + is not useful functionality. 13 + --- 14 + elf/rtld.c | 3 ++- 15 + 1 file changed, 2 insertions(+), 1 deletion(-) 16 + 17 + diff --git a/elf/rtld.c b/elf/rtld.c 18 + index 319ef06..824b6cf 100644 19 + --- a/elf/rtld.c 20 + +++ b/elf/rtld.c 21 + @@ -2419,7 +2419,8 @@ process_envvars (enum mode *modep) 22 + 23 + case 12: 24 + /* The library search path. */ 25 + - if (memcmp (envline, "LIBRARY_PATH", 12) == 0) 26 + + if (!__libc_enable_secure 27 + + && memcmp (envline, "LIBRARY_PATH", 12) == 0) 28 + { 29 + library_path = &envline[13]; 30 + break; 31 + -- 32 + 2.9.4 33 +
+115
pkgs/development/libraries/glibc/CVE-2017-1000366-rtld-LD_PRELOAD.patch
···
··· 1 + From 65ff0b7a085b85271ec8fde99f542281b495e3bc Mon Sep 17 00:00:00 2001 2 + Message-Id: <65ff0b7a085b85271ec8fde99f542281b495e3bc.1495998948.git.fweimer@redhat.com> 3 + In-Reply-To: <cover.1495998948.git.fweimer@redhat.com> 4 + References: <cover.1495998948.git.fweimer@redhat.com> 5 + From: Florian Weimer <fweimer@redhat.com> 6 + Date: Sun, 28 May 2017 20:57:40 +0200 7 + Subject: [PATCH 2/3] rtld: Reject overly long LD_PRELOAD path elements 8 + To: libc-alpha@sourceware.org 9 + 10 + --- 11 + elf/rtld.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++--------------- 12 + 1 file changed, 53 insertions(+), 16 deletions(-) 13 + 14 + diff --git a/elf/rtld.c b/elf/rtld.c 15 + index 824b6cf..30f0cae 100644 16 + --- a/elf/rtld.c 17 + +++ b/elf/rtld.c 18 + @@ -99,6 +99,22 @@ uintptr_t __pointer_chk_guard_local 19 + strong_alias (__pointer_chk_guard_local, __pointer_chk_guard) 20 + #endif 21 + 22 + +/* Check that AT_SECURE=0, or that the passed name does not contain 23 + + directories and is not overly long. Reject empty names 24 + + unconditionally. */ 25 + +static bool 26 + +dso_name_valid_for_suid (const char *p) 27 + +{ 28 + + if (__glibc_unlikely (__libc_enable_secure)) 29 + + { 30 + + /* Ignore pathnames with directories for AT_SECURE=1 31 + + programs, and also skip overlong names. */ 32 + + size_t len = strlen (p); 33 + + if (len >= NAME_MAX || memchr (p, '/', len) != NULL) 34 + + return false; 35 + + } 36 + + return *p != '\0'; 37 + +} 38 + 39 + /* List of auditing DSOs. */ 40 + static struct audit_list 41 + @@ -716,6 +732,46 @@ static const char *preloadlist attribute_relro; 42 + /* Nonzero if information about versions has to be printed. */ 43 + static int version_info attribute_relro; 44 + 45 + +/* The LD_PRELOAD environment variable gives list of libraries 46 + + separated by white space or colons that are loaded before the 47 + + executable's dependencies and prepended to the global scope list. 48 + + (If the binary is running setuid all elements containing a '/' are 49 + + ignored since it is insecure.) Return the number of preloads 50 + + performed. */ 51 + +unsigned int 52 + +handle_ld_preload (const char *preloadlist, struct link_map *main_map) 53 + +{ 54 + + unsigned int npreloads = 0; 55 + + const char *p = preloadlist; 56 + +#ifdef PATH_MAX 57 + + char fname[PATH_MAX]; 58 + +#else 59 + + char fname[4096]; 60 + +#endif 61 + + 62 + + while (*p != '\0') 63 + + { 64 + + /* Split preload list at space/colon. */ 65 + + size_t len = strcspn (p, " :"); 66 + + if (len > 0 && len < sizeof(fname)) 67 + + { 68 + + memcpy (fname, p, len); 69 + + fname[len] = '\0'; 70 + + } 71 + + else 72 + + fname[0] = '\0'; 73 + + 74 + + /* Skip over the substring and the following delimiter. */ 75 + + p += len; 76 + + if (*p == ' ' || *p == ':') 77 + + ++p; 78 + + 79 + + if (dso_name_valid_for_suid (fname)) 80 + + npreloads += do_preload (fname, main_map, "LD_PRELOAD"); 81 + + } 82 + + return npreloads; 83 + +} 84 + + 85 + static void 86 + dl_main (const ElfW(Phdr) *phdr, 87 + ElfW(Word) phnum, 88 + @@ -1462,23 +1514,8 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", 89 + 90 + if (__glibc_unlikely (preloadlist != NULL)) 91 + { 92 + - /* The LD_PRELOAD environment variable gives list of libraries 93 + - separated by white space or colons that are loaded before the 94 + - executable's dependencies and prepended to the global scope 95 + - list. If the binary is running setuid all elements 96 + - containing a '/' are ignored since it is insecure. */ 97 + - char *list = strdupa (preloadlist); 98 + - char *p; 99 + - 100 + HP_TIMING_NOW (start); 101 + - 102 + - /* Prevent optimizing strsep. Speed is not important here. */ 103 + - while ((p = (strsep) (&list, " :")) != NULL) 104 + - if (p[0] != '\0' 105 + - && (__builtin_expect (! __libc_enable_secure, 1) 106 + - || strchr (p, '/') == NULL)) 107 + - npreloads += do_preload (p, main_map, "LD_PRELOAD"); 108 + - 109 + + npreloads += handle_ld_preload (preloadlist, main_map); 110 + HP_TIMING_NOW (stop); 111 + HP_TIMING_DIFF (diff, start, stop); 112 + HP_TIMING_ACCUM_NT (load_time, diff); 113 + -- 114 + 2.9.4 115 +
+5
pkgs/development/libraries/glibc/common.nix
··· 59 "/bin:/usr/bin", which is inappropriate on NixOS machines. This 60 patch extends the search path by "/run/current-system/sw/bin". */ 61 ./fix_path_attribute_in_getconf.patch 62 ] 63 ++ lib.optional stdenv.isi686 ./fix-i686-memchr.patch; 64
··· 59 "/bin:/usr/bin", which is inappropriate on NixOS machines. This 60 patch extends the search path by "/run/current-system/sw/bin". */ 61 ./fix_path_attribute_in_getconf.patch 62 + 63 + /* Stack Clash */ 64 + ./CVE-2017-1000366-rtld-LD_LIBRARY_PATH.patch 65 + ./CVE-2017-1000366-rtld-LD_PRELOAD.patch 66 + ./CVE-2017-1000366-rtld-LD_AUDIT.patch 67 ] 68 ++ lib.optional stdenv.isi686 ./fix-i686-memchr.patch; 69