[icu/f18] Resolves: rhbz#918168 CVE-2013-0900 race condition allows DoS

Eike Rathke erack at fedoraproject.org
Wed Mar 6 21:52:07 UTC 2013


commit d78048c6f6c45f71bbfb15c113271d3a93b7b117
Author: Eike Rathke <erack at redhat.com>
Date:   Wed Mar 6 18:03:25 2013 +0100

    Resolves: rhbz#918168 CVE-2013-0900 race condition allows DoS
    
    Upstream changes
    https://ssl.icu-project.org/trac/changeset/32865
    https://ssl.icu-project.org/trac/changeset/32908
    
    See also
    https://bugzilla.redhat.com/show_bug.cgi?id=918167
    
    Plus changed UMutex to UMTX to make these compile in icu49.

 CVE-2013-0900_umutex.patch                         |   12 +
 ...9737.CVE-2013-0900_changesets_32865_32908.patch |  291 ++++++++++++++++++++
 icu.spec                                           |    9 +-
 3 files changed, 311 insertions(+), 1 deletions(-)
---
diff --git a/CVE-2013-0900_umutex.patch b/CVE-2013-0900_umutex.patch
new file mode 100644
index 0000000..82eced7
--- /dev/null
+++ b/CVE-2013-0900_umutex.patch
@@ -0,0 +1,12 @@
+diff -ruN icu.orig/source/common/locid.cpp icu/source/common/locid.cpp
+--- icu.orig/source/common/locid.cpp	2013-03-06 21:27:35.170696967 +0100
++++ icu/source/common/locid.cpp	2013-03-06 21:29:47.711378977 +0100
+@@ -53,7 +53,7 @@
+ static Locale *gLocaleCache = NULL;
+ 
+ // gDefaultLocaleMutex protects all access to gDefaultLocalesHashT and gDefaultLocale.
+-static UMutex gDefaultLocaleMutex = U_MUTEX_INITIALIZER;
++static UMTX gDefaultLocaleMutex = NULL;
+ static UHashtable *gDefaultLocalesHashT = NULL;
+ static Locale *gDefaultLocale = NULL;
+ 
diff --git a/icu.9737.CVE-2013-0900_changesets_32865_32908.patch b/icu.9737.CVE-2013-0900_changesets_32865_32908.patch
new file mode 100644
index 0000000..0dc7476
--- /dev/null
+++ b/icu.9737.CVE-2013-0900_changesets_32865_32908.patch
@@ -0,0 +1,291 @@
+Squashed into one:
+https://ssl.icu-project.org/trac/changeset/32865
+https://ssl.icu-project.org/trac/changeset/32908
+
+diff -ruN icu.orig/source/common/locid.cpp icu/source/common/locid.cpp
+--- icu.orig/source/common/locid.cpp	2012-04-05 22:46:14.000000000 +0200
++++ icu/source/common/locid.cpp	2013-03-05 21:54:11.974608225 +0100
+@@ -1,6 +1,6 @@
+ /*
+  **********************************************************************
+- *   Copyright (C) 1997-2011, International Business Machines
++ *   Copyright (C) 1997-2012, International Business Machines
+  *   Corporation and others.  All Rights Reserved.
+  **********************************************************************
+ *
+@@ -33,6 +33,7 @@
+ #include "unicode/locid.h"
+ #include "unicode/uloc.h"
+ #include "putilimp.h"
++#include "mutex.h"
+ #include "umutex.h"
+ #include "uassert.h"
+ #include "cmemory.h"
+@@ -43,6 +44,21 @@
+ 
+ #define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
+ 
++U_CDECL_BEGIN
++static UBool U_CALLCONV locale_cleanup(void);
++U_CDECL_END
++
++U_NAMESPACE_BEGIN
++
++static Locale *gLocaleCache = NULL;
++
++// gDefaultLocaleMutex protects all access to gDefaultLocalesHashT and gDefaultLocale.
++static UMutex gDefaultLocaleMutex = U_MUTEX_INITIALIZER;
++static UHashtable *gDefaultLocalesHashT = NULL;
++static Locale *gDefaultLocale = NULL;
++
++U_NAMESPACE_END
++
+ typedef enum ELocalePos {
+     eENGLISH,
+     eFRENCH,
+@@ -77,10 +93,6 @@
+             UBool valuesToo,
+             UErrorCode *status);
+ 
+-static icu::Locale *gLocaleCache = NULL;
+-static icu::Locale *gDefaultLocale = NULL;
+-static UHashtable *gDefaultLocalesHashT = NULL;
+-
+ U_CDECL_BEGIN
+ //
+ // Deleter function for Locales owned by the default Locale hash table/
+@@ -102,24 +114,19 @@
+     if (gDefaultLocalesHashT) {
+         uhash_close(gDefaultLocalesHashT);   // Automatically deletes all elements, using deleter func.
+         gDefaultLocalesHashT = NULL;
++        gDefaultLocale = NULL;
+     }
+-    else if (gDefaultLocale) {
+-        // The cache wasn't created, and only one default locale was created.
+-        delete gDefaultLocale;
+-    }
+-    gDefaultLocale = NULL;
+ 
+     return TRUE;
+ }
+ U_CDECL_END
+ 
+ U_NAMESPACE_BEGIN
+-//
+-//  locale_set_default_internal.
+-//
+-void locale_set_default_internal(const char *id)
+-{
+-    UErrorCode   status = U_ZERO_ERROR;
++
++Locale *locale_set_default_internal(const char *id, UErrorCode& status) {
++    // Synchronize this entire function.
++    Mutex lock(&gDefaultLocaleMutex);
++    
+     UBool canonicalize = FALSE;
+ 
+     // If given a NULL string for the locale id, grab the default
+@@ -127,17 +134,10 @@
+     //   (Different from most other locale APIs, where a null name means use
+     //    the current ICU default locale.)
+     if (id == NULL) {
+-        umtx_lock(NULL);
+-        id = uprv_getDefaultLocaleID();
+-        umtx_unlock(NULL);
++        id = uprv_getDefaultLocaleID();   // This function not thread safe? TODO: verify.
+         canonicalize = TRUE; // always canonicalize host ID
+     }
+ 
+-    // put the locale id into a canonical form,
+-    //   in preparation for looking up this locale in the hash table of
+-    //   already-created locale objects.
+-    //
+-    status = U_ZERO_ERROR;
+     char localeNameBuf[512];
+ 
+     if (canonicalize) {
+@@ -148,100 +148,37 @@
+     localeNameBuf[sizeof(localeNameBuf)-1] = 0;  // Force null termination in event of
+                                                  //   a long name filling the buffer.
+                                                  //   (long names are truncated.)
++                                                 //
++    if (U_FAILURE(status)) {
++        return gDefaultLocale;
++    }
+ 
+-    // Lazy creation of the hash table itself, if needed.
+-    UBool isOnlyLocale;
+-    UMTX_CHECK(NULL, (gDefaultLocale == NULL), isOnlyLocale);
+-    if (isOnlyLocale) {
+-        // We haven't seen this locale id before.
+-        // Create a new Locale object for it.
+-        Locale *newFirstDefault = new Locale(Locale::eBOGUS);
+-        if (newFirstDefault == NULL) {
+-            // No way to report errors from here.
+-            return;
+-        }
+-        newFirstDefault->init(localeNameBuf, FALSE);
+-        umtx_lock(NULL);
+-        if (gDefaultLocale == NULL) {
+-            gDefaultLocale = newFirstDefault;  // Assignment to gDefaultLocale must happen inside mutex
+-            newFirstDefault = NULL;
+-            ucln_common_registerCleanup(UCLN_COMMON_LOCALE, locale_cleanup);
+-        }
+-        // Else some other thread raced us through here, and set the new Locale.
+-        // Use the hash table next.
+-        umtx_unlock(NULL);
+-        if (newFirstDefault == NULL) {
+-            // We were successful in setting the locale, and we were the first one to set it.
+-            return;
+-        }
+-        // else start using the hash table.
+-    }
+-
+-    // Lazy creation of the hash table itself, if needed.
+-    UBool hashTableNeedsInit;
+-    UMTX_CHECK(NULL, (gDefaultLocalesHashT == NULL), hashTableNeedsInit);
+-    if (hashTableNeedsInit) {
+-        status = U_ZERO_ERROR;
+-        UHashtable *tHashTable = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
++    if (gDefaultLocalesHashT == NULL) {
++        gDefaultLocalesHashT = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
+         if (U_FAILURE(status)) {
+-            return;
++            return gDefaultLocale;
+         }
+-        uhash_setValueDeleter(tHashTable, deleteLocale);
+-        umtx_lock(NULL);
+-        if (gDefaultLocalesHashT == NULL) {
+-            gDefaultLocalesHashT = tHashTable;
+-            ucln_common_registerCleanup(UCLN_COMMON_LOCALE, locale_cleanup);
+-        } else {
+-            uhash_close(tHashTable);
+-            hashTableNeedsInit = FALSE;
+-        }
+-        umtx_unlock(NULL);
++        uhash_setValueDeleter(gDefaultLocalesHashT, deleteLocale);
++        ucln_common_registerCleanup(UCLN_COMMON_LOCALE, locale_cleanup);
+     }
+ 
+-    // Hash table lookup, key is the locale full name
+-    umtx_lock(NULL);
+     Locale *newDefault = (Locale *)uhash_get(gDefaultLocalesHashT, localeNameBuf);
+-    if (newDefault != NULL) {
+-        // We have the requested locale in the hash table already.
+-        // Just set it as default.  Inside the mutex lock, for those troublesome processors.
+-        gDefaultLocale = newDefault;
+-        umtx_unlock(NULL);
+-    } else {
+-        umtx_unlock(NULL);
+-        // We haven't seen this locale id before.
+-        // Create a new Locale object for it.
++    if (newDefault == NULL) {
+         newDefault = new Locale(Locale::eBOGUS);
+         if (newDefault == NULL) {
+-            // No way to report errors from here.
+-            return;
++            status = U_MEMORY_ALLOCATION_ERROR;
++            return gDefaultLocale;
+         }
+         newDefault->init(localeNameBuf, FALSE);
+-
+-        // Add newly created Locale to the hash table of default Locales
+-        const char *key = newDefault->getName();
+-        U_ASSERT(uprv_strcmp(key, localeNameBuf) == 0);
+-        umtx_lock(NULL);
+-        Locale *hashTableVal = (Locale *)uhash_get(gDefaultLocalesHashT, key);
+-        if (hashTableVal == NULL) {
+-            if (hashTableNeedsInit) {
+-                // This is the second request to set the locale.
+-                // Cache the first one.
+-                uhash_put(gDefaultLocalesHashT, (void *)gDefaultLocale->getName(), gDefaultLocale, &status);
+-            }
+-            uhash_put(gDefaultLocalesHashT, (void *)key, newDefault, &status);
+-            gDefaultLocale = newDefault;
+-            // ignore errors from hash table insert.  (Couldn't do anything anyway)
+-            // We can still set the default Locale,
+-            //  it just wont be cached, and will eventually leak.
+-        } else {
+-            // Some other thread raced us through here, and got the new Locale
+-            //   into the hash table before us.  Use that one.
+-            gDefaultLocale = hashTableVal;  // Assignment to gDefaultLocale must happen inside mutex
+-            delete newDefault;
++        uhash_put(gDefaultLocalesHashT, (char*) newDefault->getName(), newDefault, &status);
++        if (U_FAILURE(status)) {
++            return gDefaultLocale;
+         }
+-        umtx_unlock(NULL);
+     }
++    gDefaultLocale = newDefault;
++    return gDefaultLocale;
+ }
++
+ U_NAMESPACE_END
+ 
+ /* sfb 07/21/99 */
+@@ -249,7 +186,8 @@
+ locale_set_default(const char *id)
+ {
+     U_NAMESPACE_USE
+-    locale_set_default_internal(id);
++    UErrorCode status = U_ZERO_ERROR;
++    locale_set_default_internal(id, status);
+ }
+ /* end */
+ 
+@@ -257,7 +195,6 @@
+ locale_get_default(void)
+ {
+     U_NAMESPACE_USE
+-
+     return Locale::getDefault().getName();
+ }
+ 
+@@ -663,19 +600,14 @@
+ const Locale& U_EXPORT2
+ Locale::getDefault()
+ {
+-    const Locale *retLocale;
+-    UMTX_CHECK(NULL, gDefaultLocale, retLocale);
+-    if (retLocale == NULL) {
+-        locale_set_default_internal(NULL);
+-        umtx_lock(NULL);
+-        // Need a mutex  in case some other thread set a new
+-        // default inbetween when we set and when we get the new default.  For
+-        // processors with weak memory coherency, we might not otherwise see all
+-        // of the newly created new default locale.
+-        retLocale = gDefaultLocale;
+-        umtx_unlock(NULL);
++    {
++        Mutex lock(&gDefaultLocaleMutex);
++        if (gDefaultLocale != NULL) {
++            return *gDefaultLocale;
++        }
+     }
+-    return *retLocale;
++    UErrorCode status = U_ZERO_ERROR;
++    return *locale_set_default_internal(NULL, status);
+ }
+ 
+ 
+@@ -692,7 +624,7 @@
+      * This is a convenient way to access the default locale caching mechanisms.
+      */
+     const char *localeID = newLocale.getName();
+-    locale_set_default_internal(localeID);
++    locale_set_default_internal(localeID, status);
+ }
+ 
+ Locale U_EXPORT2
+diff -ruN icu.orig/source/common/unicode/locid.h icu/source/common/unicode/locid.h
+--- icu.orig/source/common/unicode/locid.h	2012-04-05 22:46:08.000000000 +0200
++++ icu/source/common/unicode/locid.h	2013-03-05 21:54:11.975608225 +0100
+@@ -738,7 +738,7 @@
+      * A friend to allow the default locale to be set by either the C or C++ API.
+      * @internal
+      */
+-    friend void locale_set_default_internal(const char *);
++    friend Locale *locale_set_default_internal(const char *, UErrorCode& status);
+ };
+ 
+ inline UBool
diff --git a/icu.spec b/icu.spec
index 133feab..bc77518 100644
--- a/icu.spec
+++ b/icu.spec
@@ -1,6 +1,6 @@
 Name:      icu
 Version:   49.1.1
-Release:   7%{?dist}
+Release:   8%{?dist}
 Summary:   International Components for Unicode
 Group:     Development/Tools
 License:   MIT and UCD and Public Domain
@@ -17,6 +17,8 @@ Patch4: icu.9283.regexcmp.crash.patch
 Patch5: gennorm2-man.patch
 Patch6: gencfu-man.patch
 Patch7: icuinfo-man.patch
+Patch8: icu.9737.CVE-2013-0900_changesets_32865_32908.patch
+Patch9: CVE-2013-0900_umutex.patch
 
 %description
 Tools and utilities for developing with icu.
@@ -66,6 +68,8 @@ BuildArch: noarch
 %patch5 -p1 -b .gennorm2-man.patch
 %patch6 -p1 -b .gencfu-man.patch
 %patch7 -p1 -b .icuinfo-man.patch
+%patch8 -p1 -b .icu9737.CVE-2013-0900_changesets_32865_32908.patch
+%patch9 -p1 -b .CVE-2013-0900_umutex.patch
 
 %build
 cd source
@@ -168,6 +172,9 @@ make %{?_smp_mflags} -C source check
 %doc source/__docs/%{name}/html/*
 
 %changelog
+* Wed Mar 06 2013 Eike Rathke <erack at redhat.com> - 49.1.1-8
+- Resolves: rhbz#918168 CVE-2013-0900 race condition allows DoS
+
 * Sat Feb 23 2013 Eike Rathke <erack at redhat.com> - 49.1.1-7
 - added manpages for gennorm2, gencfu and icuinfo, rhbz#884035
 


More information about the scm-commits mailing list