]> git.ipfire.org Git - thirdparty/gettext.git/commitdiff
Verify that system dependent strings in .mo files are NUL terminated.
authorBruno Haible <bruno@clisp.org>
Sun, 24 Sep 2017 12:25:53 +0000 (14:25 +0200)
committerBruno Haible <bruno@clisp.org>
Sun, 24 Sep 2017 12:25:53 +0000 (14:25 +0200)
Reported by Jakub Wilk <jwilk@jwilk.net> in
<https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=876498>.

* gettext-runtime/intl/loadmsgcat.c (_nl_load_domain): Bail out if some of the
system-dependent strings has a last static segment that is not NUL terminated.
* gettext-tools/src/read-mo.c (get_sysdep_string): Likewise.

gettext-runtime/intl/loadmsgcat.c
gettext-tools/src/read-mo.c

index beb52a3acc542e3fae22b73e28df1a62a979823a..314d2393d5d9efc2979ab8356dfa53b405460e8d 100644 (file)
@@ -1039,19 +1039,26 @@ _nl_load_domain (struct loaded_l10nfile *domain_file,
                                ? orig_sysdep_tab[i]
                                : trans_sysdep_tab[i]));
                        size_t need = 0;
+                       const char *static_segments =
+                         (char *) data
+                         + W (domain->must_swap, sysdep_string->offset);
                        const struct segment_pair *p = sysdep_string->segments;
 
                        if (W (domain->must_swap, p->sysdepref) != SEGMENTS_END)
-                         for (p = sysdep_string->segments;; p++)
+                         for (;; p++)
                            {
+                             nls_uint32 segsize;
                              nls_uint32 sysdepref;
 
-                             need += W (domain->must_swap, p->segsize);
+                             segsize = W (domain->must_swap, p->segsize);
+                             need += segsize;
 
                              sysdepref = W (domain->must_swap, p->sysdepref);
                              if (sysdepref == SEGMENTS_END)
                                break;
 
+                             static_segments += segsize;
+
                              if (sysdepref >= n_sysdep_segments)
                                {
                                  /* Invalid.  */
@@ -1063,12 +1070,25 @@ _nl_load_domain (struct loaded_l10nfile *domain_file,
                                {
                                  /* This particular string pair is invalid.  */
                                  valid = 0;
-                                 break;
                                }
 
                              need += strlen (sysdep_segment_values[sysdepref]);
                            }
 
+                       /* The last static segment must end in a NUL.  */
+                       {
+                         nls_uint32 segsize =
+                           W (domain->must_swap, p->segsize);
+
+                         if (!(segsize > 0
+                               && static_segments[segsize - 1] == '\0'))
+                           {
+                             /* Invalid.  */
+                             freea (sysdep_segment_values);
+                             goto invalid;
+                           }
+                       }
+
                        needs[j] = need;
                        if (!valid)
                          break;
@@ -1122,7 +1142,7 @@ _nl_load_domain (struct loaded_l10nfile *domain_file,
 
                            if (W (domain->must_swap, p->sysdepref)
                                != SEGMENTS_END)
-                             for (p = sysdep_string->segments;; p++)
+                             for (;; p++)
                                {
                                  nls_uint32 sysdepref;
 
@@ -1183,7 +1203,7 @@ _nl_load_domain (struct loaded_l10nfile *domain_file,
                                  {
                                    inmem_tab_entry->pointer = mem;
 
-                                   for (p = sysdep_string->segments;; p++)
+                                   for (;; p++)
                                      {
                                        nls_uint32 segsize =
                                          W (domain->must_swap, p->segsize);
index 9ddd6b2d2e34579e4ee6e6682e2428b36d38a089..1745864a6d6ec3b0790733d12484b1d964c8dbb7 100644 (file)
@@ -169,11 +169,19 @@ get_sysdep_string (const struct binary_mo_file *bfp, size_t offset,
       s_offset += segsize;
 
       if (sysdepref == SEGMENTS_END)
-        break;
+        {
+          /* The last static segment must end in a NUL.  */
+          if (!(segsize > 0 && bfp->data[s_offset - 1] == '\0'))
+            /* Invalid.  */
+            error (EXIT_FAILURE, 0,
+                   _("file \"%s\" contains a not NUL terminated system dependent string"),
+                   bfp->filename);
+          break;
+        }
       if (sysdepref >= header->n_sysdep_segments)
         /* Invalid.  */
-          error (EXIT_FAILURE, 0, _("file \"%s\" is not in GNU .mo format"),
-                 bfp->filename);
+        error (EXIT_FAILURE, 0, _("file \"%s\" is not in GNU .mo format"),
+               bfp->filename);
       /* See 'struct sysdep_segment'.  */
       sysdep_segment_offset = header->sysdep_segments_offset + sysdepref * 8;
       ss_length = get_uint32 (bfp, sysdep_segment_offset);