Imported Upstream version 0.19.7
[platform/upstream/gettext.git] / gettext-tools / src / read-mo.c
index 9e0220c..c3bfb22 100644 (file)
@@ -1,5 +1,6 @@
 /* Reading binary .mo files.
-   Copyright (C) 1995-1998, 2000-2007 Free Software Foundation, Inc.
+   Copyright (C) 1995-1998, 2000-2007, 2015 Free Software Foundation,
+   Inc.
    Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, April 1995.
 
    This program is free software: you can redistribute it and/or modify
@@ -38,6 +39,7 @@
 #include "message.h"
 #include "format.h"
 #include "gettext.h"
+#include "xsize.h"
 
 #define _(str) gettext (str)
 
@@ -100,8 +102,9 @@ static nls_uint32
 get_uint32 (const struct binary_mo_file *bfp, size_t offset)
 {
   nls_uint32 b0, b1, b2, b3;
+  size_t end = xsum (offset, 4);
 
-  if (offset + 4 > bfp->size)
+  if (size_overflow_p (end) || end > bfp->size)
     error (EXIT_FAILURE, 0, _("file \"%s\" is truncated"), bfp->filename);
 
   b0 = *(unsigned char *) (bfp->data + offset + 0);
@@ -121,8 +124,9 @@ get_string (const struct binary_mo_file *bfp, size_t offset, size_t *lengthp)
   /* See 'struct string_desc'.  */
   nls_uint32 s_length = get_uint32 (bfp, offset);
   nls_uint32 s_offset = get_uint32 (bfp, offset + 4);
+  size_t s_end = xsum3 (s_offset, s_length, 1);
 
-  if (s_offset + s_length + 1 > bfp->size)
+  if (size_overflow_p (s_end) || s_end > bfp->size)
     error (EXIT_FAILURE, 0, _("file \"%s\" is truncated"), bfp->filename);
   if (bfp->data[s_offset + s_length] != '\0')
     error (EXIT_FAILURE, 0,
@@ -146,6 +150,7 @@ get_sysdep_string (const struct binary_mo_file *bfp, size_t offset,
   nls_uint32 s_offset;
 
   /* Compute the length.  */
+  s_offset = get_uint32 (bfp, offset);
   length = 0;
   for (i = 4; ; i += 8)
     {
@@ -154,9 +159,15 @@ get_sysdep_string (const struct binary_mo_file *bfp, size_t offset,
       nls_uint32 sysdep_segment_offset;
       nls_uint32 ss_length;
       nls_uint32 ss_offset;
+      size_t ss_end;
+      size_t s_end;
       size_t n;
 
+      s_end = xsum (s_offset, segsize);
+      if (size_overflow_p (s_end) || s_end > bfp->size)
+        error (EXIT_FAILURE, 0, _("file \"%s\" is truncated"), bfp->filename);
       length += segsize;
+      s_offset += segsize;
 
       if (sysdepref == SEGMENTS_END)
         break;
@@ -168,9 +179,10 @@ get_sysdep_string (const struct binary_mo_file *bfp, size_t offset,
       sysdep_segment_offset = header->sysdep_segments_offset + sysdepref * 8;
       ss_length = get_uint32 (bfp, sysdep_segment_offset);
       ss_offset = get_uint32 (bfp, sysdep_segment_offset + 4);
-      if (ss_offset + ss_length > bfp->size)
+      ss_end = xsum (ss_offset, ss_length);
+      if (size_overflow_p (ss_end) || ss_end > bfp->size)
         error (EXIT_FAILURE, 0, _("file \"%s\" is truncated"), bfp->filename);
-      if (!(ss_length > 0 && bfp->data[ss_offset + ss_length - 1] == '\0'))
+      if (!(ss_length > 0 && bfp->data[ss_end - 1] == '\0'))
         {
           char location[30];
           sprintf (location, "sysdep_segment[%u]", (unsigned int) sysdepref);
@@ -195,8 +207,6 @@ get_sysdep_string (const struct binary_mo_file *bfp, size_t offset,
       nls_uint32 ss_offset;
       size_t n;
 
-      if (s_offset + segsize > bfp->size)
-        error (EXIT_FAILURE, 0, _("file \"%s\" is truncated"), bfp->filename);
       memcpy (p, bfp->data + s_offset, segsize);
       p += segsize;
       s_offset += segsize;