summarylogtreecommitdiffstats
path: root/CVE-2013-0900.patch
blob: 710d3e9d4a008d6ea8d739be2a1ad47e764a48fa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
Description: CVE-2013-0900: Race condition in ICU.
 Credit to Google Chrome Security Team (Inferno)
 Patch taken from backport done by Fedora 17
Origin: upstream, http://www.icu-project.org/trac/changeset/32865, http://www.icu-project.org/trac/changeset/32908
Bug-Debian: http://bugs.debian.org/702346
Bug-RedHat: https://bugzilla.redhat.com/show_bug.cgi?id=CVE-2013-0900

Index: icu-4.8.1.1/source/common/locid.cpp
===================================================================
--- icu-4.8.1.1.orig/source/common/locid.cpp	2013-03-21 11:21:45.053153118 -0400
+++ icu-4.8.1.1/source/common/locid.cpp	2013-03-21 11:21:45.029153121 -0400
@@ -1,6 +1,6 @@
 /*
  **********************************************************************
- *   Copyright (C) 1997-2010, International Business Machines
+ *   Copyright (C) 1997-2012, International Business Machines
  *   Corporation and others.  All Rights Reserved.
  **********************************************************************
 *
@@ -32,6 +32,7 @@
 
 #include "unicode/locid.h"
 #include "unicode/uloc.h"
+#include "mutex.h"
 #include "umutex.h"
 #include "uassert.h"
 #include "cmemory.h"
@@ -41,6 +42,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 U_NAMESPACE_QUALIFIER Locale *gLocaleCache         = NULL;
+
+// gDefaultLocaleMutex protects all access to gDefaultLocalesHashT and gDefaultLocale.
+static UMTX                          gDefaultLocaleMutex  = 0;
+static UHashtable                   *gDefaultLocalesHashT = NULL;
+static U_NAMESPACE_QUALIFIER Locale *gDefaultLocale       = NULL;
+
+U_NAMESPACE_END
+
 typedef enum ELocalePos {
     eENGLISH,
     eFRENCH,
@@ -75,10 +91,6 @@
             UBool valuesToo,
             UErrorCode *status);
 
-static U_NAMESPACE_QUALIFIER Locale *gLocaleCache         = NULL;
-static U_NAMESPACE_QUALIFIER Locale *gDefaultLocale       = NULL;
-static UHashtable                   *gDefaultLocalesHashT = NULL;
-
 U_CDECL_BEGIN
 //
 // Deleter function for Locales owned by the default Locale hash table/
@@ -100,24 +112,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
@@ -125,17 +132,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) {
@@ -146,100 +146,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;
-        }
-        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;
+            return gDefaultLocale;
         }
-        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 */
@@ -247,7 +184,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 */
 
@@ -255,7 +193,6 @@
 locale_get_default(void)
 {
     U_NAMESPACE_USE
-
     return Locale::getDefault().getName();
 }
 
@@ -661,19 +598,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);
 }
 
 
@@ -690,7 +622,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
Index: icu-4.8.1.1/source/common/unicode/locid.h
===================================================================
--- icu-4.8.1.1.orig/source/common/unicode/locid.h	2013-03-21 11:21:45.053153118 -0400
+++ icu-4.8.1.1/source/common/unicode/locid.h	2013-03-21 11:21:45.041153115 -0400
@@ -732,7 +732,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