lol

glibc: fix CVE-2014-0475 by upstream patches

https://sourceware.org/bugzilla/show_bug.cgi?id=17137

authored by

Vladimír Čunát and committed by
Peter Simons
9253a95f b76a7504

+172
+2
pkgs/development/libraries/glibc/2.19/common.nix
··· 58 58 ./fix_path_attribute_in_getconf.patch 59 59 60 60 ./fix-math.patch 61 + 62 + ./cve-2014-0475.patch 61 63 ]; 62 64 63 65 postPatch = ''
+170
pkgs/development/libraries/glibc/2.19/cve-2014-0475.patch
··· 1 + Picked from upstream commits, but excluding changes to news and tests: 2 + d183645616b0533 and 4e8f95a0df7c2 3 + Also see https://sourceware.org/bugzilla/show_bug.cgi?id=17137 4 + 5 + diff --git a/locale/setlocale.c b/locale/setlocale.c 6 + index 9458468..6455b8b 100644 7 + --- a/locale/setlocale.c 8 + +++ b/locale/setlocale.c 9 + @@ -272,6 +272,8 @@ setlocale (int category, const char *locale) 10 + of entries of the form `CATEGORY=VALUE'. */ 11 + const char *newnames[__LC_LAST]; 12 + struct __locale_data *newdata[__LC_LAST]; 13 + + /* Copy of the locale argument, for in-place splitting. */ 14 + + char *locale_copy = NULL; 15 + 16 + /* Set all name pointers to the argument name. */ 17 + for (category = 0; category < __LC_LAST; ++category) 18 + @@ -281,7 +283,13 @@ setlocale (int category, const char *locale) 19 + if (__glibc_unlikely (strchr (locale, ';') != NULL)) 20 + { 21 + /* This is a composite name. Make a copy and split it up. */ 22 + - char *np = strdupa (locale); 23 + + locale_copy = strdup (locale); 24 + + if (__glibc_unlikely (locale_copy == NULL)) 25 + + { 26 + + __libc_rwlock_unlock (__libc_setlocale_lock); 27 + + return NULL; 28 + + } 29 + + char *np = locale_copy; 30 + char *cp; 31 + int cnt; 32 + 33 + @@ -299,6 +307,7 @@ setlocale (int category, const char *locale) 34 + { 35 + error_return: 36 + __libc_rwlock_unlock (__libc_setlocale_lock); 37 + + free (locale_copy); 38 + 39 + /* Bogus category name. */ 40 + ERROR_RETURN; 41 + @@ -391,8 +400,9 @@ setlocale (int category, const char *locale) 42 + /* Critical section left. */ 43 + __libc_rwlock_unlock (__libc_setlocale_lock); 44 + 45 + - /* Free the resources (the locale path variable). */ 46 + + /* Free the resources. */ 47 + free (locale_path); 48 + + free (locale_copy); 49 + 50 + return composite; 51 + } 52 + diff --git a/locale/findlocale.c b/locale/findlocale.c 53 + index bbaf708..22e8b53 100644 54 + --- a/locale/findlocale.c 55 + +++ b/locale/findlocale.c 56 + @@ -17,6 +17,7 @@ 57 + <http://www.gnu.org/licenses/>. */ 58 + 59 + #include <assert.h> 60 + +#include <errno.h> 61 + #include <locale.h> 62 + #include <stdlib.h> 63 + #include <string.h> 64 + @@ -57,6 +58,45 @@ struct loaded_l10nfile *_nl_locale_file_list[__LC_LAST]; 65 + 66 + const char _nl_default_locale_path[] attribute_hidden = LOCALEDIR; 67 + 68 + +/* Checks if the name is actually present, that is, not NULL and not 69 + + empty. */ 70 + +static inline int 71 + +name_present (const char *name) 72 + +{ 73 + + return name != NULL && name[0] != '\0'; 74 + +} 75 + + 76 + +/* Checks that the locale name neither extremely long, nor contains a 77 + + ".." path component (to prevent directory traversal). */ 78 + +static inline int 79 + +valid_locale_name (const char *name) 80 + +{ 81 + + /* Not set. */ 82 + + size_t namelen = strlen (name); 83 + + /* Name too long. The limit is arbitrary and prevents stack overflow 84 + + issues later. */ 85 + + if (__glibc_unlikely (namelen > 255)) 86 + + return 0; 87 + + /* Directory traversal attempt. */ 88 + + static const char slashdot[4] = {'/', '.', '.', '/'}; 89 + + if (__glibc_unlikely (memmem (name, namelen, 90 + + slashdot, sizeof (slashdot)) != NULL)) 91 + + return 0; 92 + + if (namelen == 2 && __glibc_unlikely (name[0] == '.' && name [1] == '.')) 93 + + return 0; 94 + + if (namelen >= 3 95 + + && __glibc_unlikely (((name[0] == '.' 96 + + && name[1] == '.' 97 + + && name[2] == '/') 98 + + || (name[namelen - 3] == '/' 99 + + && name[namelen - 2] == '.' 100 + + && name[namelen - 1] == '.')))) 101 + + return 0; 102 + + /* If there is a slash in the name, it must start with one. */ 103 + + if (__glibc_unlikely (memchr (name, '/', namelen) != NULL) && name[0] != '/') 104 + + return 0; 105 + + return 1; 106 + +} 107 + 108 + struct __locale_data * 109 + internal_function 110 + @@ -65,7 +105,7 @@ _nl_find_locale (const char *locale_path, size_t locale_path_len, 111 + { 112 + int mask; 113 + /* Name of the locale for this category. */ 114 + - char *loc_name; 115 + + char *loc_name = (char *) *name; 116 + const char *language; 117 + const char *modifier; 118 + const char *territory; 119 + @@ -73,31 +113,39 @@ _nl_find_locale (const char *locale_path, size_t locale_path_len, 120 + const char *normalized_codeset; 121 + struct loaded_l10nfile *locale_file; 122 + 123 + - if ((*name)[0] == '\0') 124 + + if (loc_name[0] == '\0') 125 + { 126 + /* The user decides which locale to use by setting environment 127 + variables. */ 128 + - *name = getenv ("LC_ALL"); 129 + - if (*name == NULL || (*name)[0] == '\0') 130 + - *name = getenv (_nl_category_names.str 131 + + loc_name = getenv ("LC_ALL"); 132 + + if (!name_present (loc_name)) 133 + + loc_name = getenv (_nl_category_names.str 134 + + _nl_category_name_idxs[category]); 135 + - if (*name == NULL || (*name)[0] == '\0') 136 + - *name = getenv ("LANG"); 137 + + if (!name_present (loc_name)) 138 + + loc_name = getenv ("LANG"); 139 + + if (!name_present (loc_name)) 140 + + loc_name = (char *) _nl_C_name; 141 + } 142 + 143 + - if (*name == NULL || (*name)[0] == '\0' 144 + - || (__builtin_expect (__libc_enable_secure, 0) 145 + - && strchr (*name, '/') != NULL)) 146 + - *name = (char *) _nl_C_name; 147 + + /* We used to fall back to the C locale if the name contains a slash 148 + + character '/', but we now check for directory traversal in 149 + + valid_locale_name, so this is no longer necessary. */ 150 + 151 + - if (__builtin_expect (strcmp (*name, _nl_C_name), 1) == 0 152 + - || __builtin_expect (strcmp (*name, _nl_POSIX_name), 1) == 0) 153 + + if (__builtin_expect (strcmp (loc_name, _nl_C_name), 1) == 0 154 + + || __builtin_expect (strcmp (loc_name, _nl_POSIX_name), 1) == 0) 155 + { 156 + /* We need not load anything. The needed data is contained in 157 + the library itself. */ 158 + *name = (char *) _nl_C_name; 159 + return _nl_C[category]; 160 + } 161 + + else if (!valid_locale_name (loc_name)) 162 + + { 163 + + __set_errno (EINVAL); 164 + + return NULL; 165 + + } 166 + + 167 + + *name = loc_name; 168 + 169 + /* We really have to load some data. First we try the archive, 170 + but only if there was no LOCPATH environment variable specified. */