bug-m4
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: undiagnosed integer overflow in parsing frozen files


From: Eric Blake
Subject: Re: undiagnosed integer overflow in parsing frozen files
Date: Fri, 9 May 2008 17:09:07 +0000 (UTC)
User-agent: Loom/3.14 (http://gmane.org/)

Eric Blake <ebb9 <at> byu.net> writes:

> According to Jim Meyering on 5/8/2008 1:10 PM:
> |
> | However, given too long a string of digits, "Number" overflows.
> 
> Accidental, but not unnoticed, and hopefully not severe.
> But now that you mention it, I'll
> probably tighten up the check

Like this.


>From b5fe50a4ef3e20912ee835888c9effda8a290721 Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Fri, 9 May 2008 07:59:51 -0600
Subject: [PATCH] Detect integer overflow when loading frozen file.

* src/freeze.c (reload_frozen_state) [GET_NUMBER]: Rewrite to fail
immediately on overflow.
Reported by Jim Meyering.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog    |    5 +++++
 src/freeze.c |   31 ++++++++++++++++++-------------
 2 files changed, 23 insertions(+), 13 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 0a40526..fc894b1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
 2008-05-09  Eric Blake  <address@hidden>
 
+       Detect integer overflow when loading frozen file.
+       * src/freeze.c (reload_frozen_state) [GET_NUMBER]: Rewrite to fail
+       immediately on overflow.
+       Reported by Jim Meyering.
+
        Stage 23: allow tracing of indirect macro calls.
        Track all trace information as part of the argv struct, rather
        than temporarily resetting global state.  Teach indir to trace
diff --git a/src/freeze.c b/src/freeze.c
index 383d008..16ed75e 100644
--- a/src/freeze.c
+++ b/src/freeze.c
@@ -179,33 +179,38 @@ reload_frozen_state (const char *name)
   int number[2];
   const builtin *bp;
 
-#define GET_CHARACTER \
+#define GET_CHARACTER                                          \
   (character = getc (file))
 
-#define GET_NUMBER(Number) \
+#define GET_NUMBER(Number, AllowNeg)                           \
   do                                                           \
     {                                                          \
-      (Number) = 0;                                            \
-      while (isdigit (character))                              \
+      unsigned int n = 0;                                      \
+      while (isdigit (character) && n <= INT_MAX / 10)         \
        {                                                       \
-         (Number) = 10 * (Number) + character - '0';           \
+         n = 10 * n + character - '0';                         \
          GET_CHARACTER;                                        \
        }                                                       \
+      if (((AllowNeg) ? INT_MIN : INT_MAX) < n                 \
+         || isdigit (character))                               \
+       m4_error (EXIT_FAILURE, 0, NULL,                        \
+                 _("integer overflow in frozen file"));        \
+      (Number) = n;                                            \
     }                                                          \
   while (0)
 
-#define VALIDATE(Expected) \
+#define VALIDATE(Expected)                                     \
   do                                                           \
     {                                                          \
       if (character != (Expected))                             \
-       issue_expect_message ((Expected));                      \
+       issue_expect_message (Expected);                        \
     }                                                          \
   while (0)
 
   /* Skip comments (`#' at beginning of line) and blank lines, setting
      character to the next directive or to EOF.  */
 
-#define GET_DIRECTIVE \
+#define GET_DIRECTIVE                                          \
   do                                                           \
     {                                                          \
       GET_CHARACTER;                                           \
@@ -215,7 +220,7 @@ reload_frozen_state (const char *name)
            GET_CHARACTER;                                      \
          VALIDATE ('\n');                                      \
        }                                                       \
-    }                                                           \
+    }                                                          \
   while (character == '\n')
 
   file = m4_path_search (name, NULL);
@@ -231,7 +236,7 @@ reload_frozen_state (const char *name)
   GET_DIRECTIVE;
   VALIDATE ('V');
   GET_CHARACTER;
-  GET_NUMBER (number[0]);
+  GET_NUMBER (number[0], false);
   if (number[0] > 1)
     m4_error (EXIT_MISMATCH, 0, NULL,
              _("frozen file version %d greater than max supported of 1"),
@@ -262,14 +267,14 @@ reload_frozen_state (const char *name)
          if (operation == 'D' && character == '-')
            {
              GET_CHARACTER;
-             GET_NUMBER (number[0]);
+             GET_NUMBER (number[0], true);
              number[0] = -number[0];
            }
          else
-           GET_NUMBER (number[0]);
+           GET_NUMBER (number[0], false);
          VALIDATE (',');
          GET_CHARACTER;
-         GET_NUMBER (number[1]);
+         GET_NUMBER (number[1], false);
          VALIDATE ('\n');
 
          if (operation != 'D')
-- 
1.5.5.1


>From 34985ceaf524a511894776fe446279b5a7c12ced Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Fri, 9 May 2008 09:24:41 -0600
Subject: [PATCH] Improve error message when frozen file is invalid.

* src/freeze.c (reload_frozen_state): Track current line.
[GET_STRING]: New helper macro.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog    |    4 +++
 src/freeze.c |   79 ++++++++++++++++++++++++++++++++-------------------------
 2 files changed, 48 insertions(+), 35 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index fc894b1..2abc489 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
 2008-05-09  Eric Blake  <address@hidden>
 
+       Improve error message when frozen file is invalid.
+       * src/freeze.c (reload_frozen_state): Track current line.
+       [GET_STRING]: New helper macro.
+
        Detect integer overflow when loading frozen file.
        * src/freeze.c (reload_frozen_state) [GET_NUMBER]: Rewrite to fail
        immediately on overflow.
diff --git a/src/freeze.c b/src/freeze.c
index 16ed75e..15f06fe 100644
--- a/src/freeze.c
+++ b/src/freeze.c
@@ -178,9 +178,21 @@ reload_frozen_state (const char *name)
   int allocated[2];
   int number[2];
   const builtin *bp;
+  bool advance_line = true;
 
 #define GET_CHARACTER                                          \
-  (character = getc (file))
+  do                                                           \
+    {                                                          \
+      if (advance_line)                                                \
+       {                                                       \
+         current_line++;                                       \
+         advance_line = false;                                 \
+       }                                                       \
+      (character = getc (file));                               \
+      if (character == '\n')                                   \
+       advance_line = true;                                    \
+    }                                                          \
+  while (0)
 
 #define GET_NUMBER(Number, AllowNeg)                           \
   do                                                           \
@@ -223,9 +235,35 @@ reload_frozen_state (const char *name)
     }                                                          \
   while (character == '\n')
 
+#define GET_STRING(i)                                                  \
+  do                                                                   \
+    {                                                                  \
+      void *tmp;                                                       \
+      char *p;                                                         \
+      if (number[(i)] + 1 > allocated[(i)])                            \
+       {                                                               \
+         free (string[(i)]);                                           \
+         allocated[(i)] = number[(i)] + 1;                             \
+         string[(i)] = xcharalloc ((size_t) allocated[(i)]);           \
+       }                                                               \
+      if (number[(i)] > 0                                              \
+         && !fread (string[(i)], (size_t) number[(i)], 1, file))       \
+       m4_error (EXIT_FAILURE, 0, NULL,                                \
+                 _("premature end of frozen file"));                   \
+      string[(i)][number[(i)]] = '\0';                                 \
+      p = string[(i)];                                                 \
+      while ((tmp = memchr(p, '\n', number[(i)] - (p - string[(i)])))) \
+       {                                                               \
+         current_line++;                                               \
+         p = (char *) tmp + 1;                                         \
+       }                                                               \
+    }                                                                  \
+  while (0)
+
   file = m4_path_search (name, NULL);
   if (file == NULL)
     m4_error (EXIT_FAILURE, errno, NULL, _("cannot open %s"), name);
+  current_file = name;
 
   allocated[0] = 100;
   string[0] = xcharalloc ((size_t) allocated[0]);
@@ -278,40 +316,8 @@ reload_frozen_state (const char *name)
          VALIDATE ('\n');
 
          if (operation != 'D')
-           {
-
-             /* Get first string contents.  */
-
-             if (number[0] + 1 > allocated[0])
-               {
-                 free (string[0]);
-                 allocated[0] = number[0] + 1;
-                 string[0] = xcharalloc ((size_t) allocated[0]);
-               }
-
-             if (number[0] > 0)
-               if (!fread (string[0], (size_t) number[0], 1, file))
-                 m4_error (EXIT_FAILURE, 0, NULL,
-                           _("premature end of frozen file"));
-
-             string[0][number[0]] = '\0';
-           }
-
-         /* Get second string contents.  */
-
-         if (number[1] + 1 > allocated[1])
-           {
-             free (string[1]);
-             allocated[1] = number[1] + 1;
-             string[1] = xcharalloc ((size_t) allocated[1]);
-           }
-
-         if (number[1] > 0)
-           if (!fread (string[1], (size_t) number[1], 1, file))
-             m4_error (EXIT_FAILURE, 0, NULL,
-                       _("premature end of frozen file"));
-
-         string[1][number[1]] = '\0';
+           GET_STRING (0);
+         GET_STRING (1);
          GET_CHARACTER;
          VALIDATE ('\n');
 
@@ -375,9 +381,12 @@ reload_frozen_state (const char *name)
   errno = 0;
   if (ferror (file) || fclose (file) != 0)
     m4_error (EXIT_FAILURE, errno, NULL, _("unable to read frozen state"));
+  current_file = NULL;
+  current_line = 0;
 
 #undef GET_CHARACTER
 #undef GET_DIRECTIVE
 #undef GET_NUMBER
 #undef VALIDATE
+#undef GET_STRING
 }
-- 
1.5.5.1








reply via email to

[Prev in Thread] Current Thread [Next in Thread]