]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
Fix _nl_find_msg malloc failure case, and callers.
authorCarlos O'Donell <carlos@redhat.com>
Wed, 22 May 2013 18:50:26 +0000 (14:50 -0400)
committerCarlos O'Donell <carlos@redhat.com>
Wed, 22 May 2013 18:50:26 +0000 (14:50 -0400)
This patch fixes two issues, and perhaps should be two distinct commits,
but I present it here as one for the sake of completeness.

Commit 006dd86111c44572dbd3b26e9c63dd0f834d7762 fails to check malloc's
return in intl/dcigettext.c (_nl_find_msg):
~~~
      freemem_size = INITIAL_BLOCK_SIZE;
      newmem = (transmem_block_t *) malloc (freemem_size);
...
      newmem->next = transmem_list;
      transmem_list = newmem;
~~~
If malloc fails then newmem is NULL then newmem->next results in a
fault.

The fix is easy enough, check for newmem != NULL, and fall through to
the error condition below which returns (char *) -1 e.g. resource error.

The problem is that returning (char *) -1  will break all sorts of other
code, so while what we did is correct, the real failure case fix is
slightly broader.

There are 4 other places where _nl_find_msg is called, one is OK, the
other three are fixed to handle -1 error return value.

No regressions on x86-64 or x86.

However, no regressions isn't really a useful metric for this code.

The change was tested as documented here:
http://sourceware.org/glibc/wiki/Testing/WhiteBox
using SystemTap for fault injection to simulate malloc failure.

---

2013-05-03  Carlos O'Donell  <carlos at redhat.com>

[BZ #15441]
* intl/dcigettext.c (DCIGETTEXT): Skip translating if _nl_find_msg
returns -1.
(_nl_find_msg): Return -1 if recursive call returned -1. If newmem is
null return -1.
* intl/loadmsgcat.c (_nl_load_domain): If _nl_find_msg returns -1 abort
loading the domain.

ChangeLog
NEWS
intl/dcigettext.c
intl/loadmsgcat.c

index 46a36cee0117d37b2428041e978ff908b3f77a02..49d3c366b6fd950f025263747f6f399c68aa2e99 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2013-05-03  Carlos O'Donell  <carlos at redhat.com>
+
+       [BZ #15441]
+       * intl/dcigettext.c (DCIGETTEXT): Skip translating if _nl_find_msg
+       returns -1.
+       (_nl_find_msg): Return -1 if recursive call returned -1. If newmem is
+       null return -1.
+       * intl/loadmsgcat.c (_nl_load_domain): If _nl_find_msg returns -1 abort
+       loading the domain.
+
 2013-05-22  Joseph Myers  <joseph@codesourcery.com>
 
        * math/gen-libm-test.pl (parse_args): Do not include expected
diff --git a/NEWS b/NEWS
index 970c53b614bf40eb2a80dacf465ee3d7ad0ffa75..152e7a4caadbba26f8772368c73f3ebbbc16c04c 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -17,8 +17,8 @@ Version 2.18
   15085, 15086, 15160, 15214, 15221, 15232, 15234, 15283, 15285, 15287,
   15304, 15305, 15307, 15309, 15327, 15330, 15335, 15336, 15337, 15339,
   15342, 15346, 15359, 15361, 15366, 15380, 15394, 15395, 15405, 15406,
-  15409, 15416, 15418, 15419, 15423, 15424, 15426, 15429, 15442, 15448,
-  15480, 15485, 15488, 15490, 15493, 15497, 15506.
+  15409, 15416, 15418, 15419, 15423, 15424, 15426, 15429, 15441, 15442,
+  15448, 15480, 15485, 15488, 15490, 15493, 15497, 15506.
 
 * CVE-2013-0242 Buffer overrun in regexp matcher has been fixed (Bugzilla
   #15078).
index 110307bdb2109e197eda77b5407015f0775f58af..f4aa215744ce89e38f82dfe24c36bf6c08b7f4d7 100644 (file)
@@ -638,6 +638,11 @@ DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category)
                  retval = _nl_find_msg (domain->successor[cnt], binding,
                                         msgid1, 1, &retlen);
 
+                 /* Resource problems are not fatal, instead we return no
+                    translation.  */
+                 if (__builtin_expect (retval == (char *) -1, 0))
+                   goto no_translation;
+
                  if (retval != NULL)
                    {
                      domain = domain->successor[cnt];
@@ -941,6 +946,11 @@ _nl_find_msg (domain_file, domainbinding, msgid, convert, lengthp)
            nullentry =
              _nl_find_msg (domain_file, domainbinding, "", 0, &nullentrylen);
 
+           /* Resource problems are fatal.  If we continue onwards we will
+              only attempt to calloc a new conv_tab and fail later.  */
+           if (__builtin_expect (nullentry == (char *) -1, 0))
+             return (char *) -1;
+
            if (nullentry != NULL)
              {
                const char *charsetstr;
@@ -1170,10 +1180,14 @@ _nl_find_msg (domain_file, domainbinding, msgid, convert, lengthp)
                      freemem_size = INITIAL_BLOCK_SIZE;
                      newmem = (transmem_block_t *) malloc (freemem_size);
 # ifdef _LIBC
-                     /* Add the block to the list of blocks we have to free
-                        at some point.  */
-                     newmem->next = transmem_list;
-                     transmem_list = newmem;
+                     if (newmem != NULL)
+                       {
+                         /* Add the block to the list of blocks we have to free
+                            at some point.  */
+                         newmem->next = transmem_list;
+                         transmem_list = newmem;
+                       }
+                     /* Fall through and return -1.  */
 # endif
                    }
                  if (__builtin_expect (newmem == NULL, 0))
index e4b7b385a0aa8c19f2de8451b4830ea5de237464..ac90ed1015da38d67dd505f1795afa6cf14df563 100644 (file)
@@ -1237,7 +1237,7 @@ _nl_load_domain (domain_file, domainbinding)
     default:
       /* This is an invalid revision.  */
     invalid:
-      /* This is an invalid .mo file.  */
+      /* This is an invalid .mo file or we ran out of resources.  */
       free (domain->malloced);
 #ifdef HAVE_MMAP
       if (use_mmap)
@@ -1257,6 +1257,11 @@ _nl_load_domain (domain_file, domainbinding)
 
   /* Get the header entry and look for a plural specification.  */
   nullentry = _nl_find_msg (domain_file, domainbinding, "", 0, &nullentrylen);
+  if (__builtin_expect (nullentry == (char *) -1, 0))
+    {
+      __libc_rwlock_fini (domain->conversions_lock);
+      goto invalid;
+    }
   EXTRACT_PLURAL_EXPRESSION (nullentry, &domain->plural, &domain->nplurals);
 
  out: