diff options
Diffstat (limited to 'pkgs/development/libraries/glibc/2.19/cve-2014-0475.patch')
-rw-r--r-- | pkgs/development/libraries/glibc/2.19/cve-2014-0475.patch | 170 |
1 files changed, 170 insertions, 0 deletions
diff --git a/pkgs/development/libraries/glibc/2.19/cve-2014-0475.patch b/pkgs/development/libraries/glibc/2.19/cve-2014-0475.patch new file mode 100644 index 00000000000..a4f983de8f6 --- /dev/null +++ b/pkgs/development/libraries/glibc/2.19/cve-2014-0475.patch @@ -0,0 +1,170 @@ +Picked from upstream commits, but excluding changes to news and tests: +d183645616b0533 and 4e8f95a0df7c2 +Also see https://sourceware.org/bugzilla/show_bug.cgi?id=17137 + +diff --git a/locale/setlocale.c b/locale/setlocale.c +index 9458468..6455b8b 100644 +--- a/locale/setlocale.c ++++ b/locale/setlocale.c +@@ -272,6 +272,8 @@ setlocale (int category, const char *locale) + of entries of the form `CATEGORY=VALUE'. */ + const char *newnames[__LC_LAST]; + struct __locale_data *newdata[__LC_LAST]; ++ /* Copy of the locale argument, for in-place splitting. */ ++ char *locale_copy = NULL; + + /* Set all name pointers to the argument name. */ + for (category = 0; category < __LC_LAST; ++category) +@@ -281,7 +283,13 @@ setlocale (int category, const char *locale) + if (__glibc_unlikely (strchr (locale, ';') != NULL)) + { + /* This is a composite name. Make a copy and split it up. */ +- char *np = strdupa (locale); ++ locale_copy = strdup (locale); ++ if (__glibc_unlikely (locale_copy == NULL)) ++ { ++ __libc_rwlock_unlock (__libc_setlocale_lock); ++ return NULL; ++ } ++ char *np = locale_copy; + char *cp; + int cnt; + +@@ -299,6 +307,7 @@ setlocale (int category, const char *locale) + { + error_return: + __libc_rwlock_unlock (__libc_setlocale_lock); ++ free (locale_copy); + + /* Bogus category name. */ + ERROR_RETURN; +@@ -391,8 +400,9 @@ setlocale (int category, const char *locale) + /* Critical section left. */ + __libc_rwlock_unlock (__libc_setlocale_lock); + +- /* Free the resources (the locale path variable). */ ++ /* Free the resources. */ + free (locale_path); ++ free (locale_copy); + + return composite; + } +diff --git a/locale/findlocale.c b/locale/findlocale.c +index bbaf708..22e8b53 100644 +--- a/locale/findlocale.c ++++ b/locale/findlocale.c +@@ -17,6 +17,7 @@ + <http://www.gnu.org/licenses/>. */ + + #include <assert.h> ++#include <errno.h> + #include <locale.h> + #include <stdlib.h> + #include <string.h> +@@ -57,6 +58,45 @@ struct loaded_l10nfile *_nl_locale_file_list[__LC_LAST]; + + const char _nl_default_locale_path[] attribute_hidden = LOCALEDIR; + ++/* Checks if the name is actually present, that is, not NULL and not ++ empty. */ ++static inline int ++name_present (const char *name) ++{ ++ return name != NULL && name[0] != '\0'; ++} ++ ++/* Checks that the locale name neither extremely long, nor contains a ++ ".." path component (to prevent directory traversal). */ ++static inline int ++valid_locale_name (const char *name) ++{ ++ /* Not set. */ ++ size_t namelen = strlen (name); ++ /* Name too long. The limit is arbitrary and prevents stack overflow ++ issues later. */ ++ if (__glibc_unlikely (namelen > 255)) ++ return 0; ++ /* Directory traversal attempt. */ ++ static const char slashdot[4] = {'/', '.', '.', '/'}; ++ if (__glibc_unlikely (memmem (name, namelen, ++ slashdot, sizeof (slashdot)) != NULL)) ++ return 0; ++ if (namelen == 2 && __glibc_unlikely (name[0] == '.' && name [1] == '.')) ++ return 0; ++ if (namelen >= 3 ++ && __glibc_unlikely (((name[0] == '.' ++ && name[1] == '.' ++ && name[2] == '/') ++ || (name[namelen - 3] == '/' ++ && name[namelen - 2] == '.' ++ && name[namelen - 1] == '.')))) ++ return 0; ++ /* If there is a slash in the name, it must start with one. */ ++ if (__glibc_unlikely (memchr (name, '/', namelen) != NULL) && name[0] != '/') ++ return 0; ++ return 1; ++} + + struct __locale_data * + internal_function +@@ -65,7 +105,7 @@ _nl_find_locale (const char *locale_path, size_t locale_path_len, + { + int mask; + /* Name of the locale for this category. */ +- char *loc_name; ++ char *loc_name = (char *) *name; + const char *language; + const char *modifier; + const char *territory; +@@ -73,31 +113,39 @@ _nl_find_locale (const char *locale_path, size_t locale_path_len, + const char *normalized_codeset; + struct loaded_l10nfile *locale_file; + +- if ((*name)[0] == '\0') ++ if (loc_name[0] == '\0') + { + /* The user decides which locale to use by setting environment + variables. */ +- *name = getenv ("LC_ALL"); +- if (*name == NULL || (*name)[0] == '\0') +- *name = getenv (_nl_category_names.str ++ loc_name = getenv ("LC_ALL"); ++ if (!name_present (loc_name)) ++ loc_name = getenv (_nl_category_names.str + + _nl_category_name_idxs[category]); +- if (*name == NULL || (*name)[0] == '\0') +- *name = getenv ("LANG"); ++ if (!name_present (loc_name)) ++ loc_name = getenv ("LANG"); ++ if (!name_present (loc_name)) ++ loc_name = (char *) _nl_C_name; + } + +- if (*name == NULL || (*name)[0] == '\0' +- || (__builtin_expect (__libc_enable_secure, 0) +- && strchr (*name, '/') != NULL)) +- *name = (char *) _nl_C_name; ++ /* We used to fall back to the C locale if the name contains a slash ++ character '/', but we now check for directory traversal in ++ valid_locale_name, so this is no longer necessary. */ + +- if (__builtin_expect (strcmp (*name, _nl_C_name), 1) == 0 +- || __builtin_expect (strcmp (*name, _nl_POSIX_name), 1) == 0) ++ if (__builtin_expect (strcmp (loc_name, _nl_C_name), 1) == 0 ++ || __builtin_expect (strcmp (loc_name, _nl_POSIX_name), 1) == 0) + { + /* We need not load anything. The needed data is contained in + the library itself. */ + *name = (char *) _nl_C_name; + return _nl_C[category]; + } ++ else if (!valid_locale_name (loc_name)) ++ { ++ __set_errno (EINVAL); ++ return NULL; ++ } ++ ++ *name = loc_name; + + /* We really have to load some data. First we try the archive, + but only if there was no LOCPATH environment variable specified. */ |