[babl] babl: proof icc parsing against corrupt data



commit dafec35ec5815c6319d3b5ad7f10616857cc694c
Author: Øyvind Kolås <pippin gimp org>
Date:   Sat Aug 19 23:43:32 2017 +0200

    babl: proof icc parsing against corrupt data

 babl/babl-icc.c |  224 ++++++++++++++++++++++++++++++------------------------
 1 files changed, 124 insertions(+), 100 deletions(-)
---
diff --git a/babl/babl-icc.c b/babl/babl-icc.c
index 7fd9b32..129368b 100644
--- a/babl/babl-icc.c
+++ b/babl/babl-icc.c
@@ -1,3 +1,21 @@
+/* babl - dynamically extendable universal pixel conversion library.
+ * Copyright (C) 2017, Øyvind Kolås.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
 #include "config.h"
 #include "babl-internal.h"
 #include <stdio.h>
@@ -6,80 +24,85 @@
 #define ICC_HEADER_LEN 128
 #define TAG_COUNT_OFF  ICC_HEADER_LEN
 
-static int load_byte (const char *icc, int offset)
+static int load_byte (const char *icc, int length, int offset)
 {
+/* all reading functions take both the char *pointer and the length of the
+ * buffer, and all reads thus gets protected by this condition.
+ */
+  if (offset < 0 || offset > length)
+    return 0;
+
   return *(uint8_t*) (&icc[offset]);
 }
 
-static int16_t load_u1Fixed15 (const char *icc, int offset)
+static int load_sbyte (const char *icc, int length, int offset)
+{
+  if (offset < 0 || offset > length)
+    return 0;
+
+  return *(int8_t*) (&icc[offset]);
+}
+
+static int16_t load_u1f15 (const char *icc, int length, int offset)
 {
-  return load_byte (icc, offset + 1) +
-         (load_byte (icc, offset + 0) << 8);
+  return load_sbyte (icc, length, offset + 1) +
+         (load_byte (icc, length, offset + 0) << 8);
 }
 
-static uint16_t load_uint16 (const char *icc, int offset)
+static uint16_t load_u16 (const char *icc, int length, int offset)
 {
-  return load_byte (icc, offset + 1) +
-         (load_byte (icc, offset + 0) << 8);
+  return load_byte (icc, length, offset + 1) +
+         (load_byte (icc, length, offset + 0) << 8);
 }
 
-static double load_s15Fixed16 (const char *icc, int offset)
+static double load_s15f15 (const char *icc, int length, int offset)
 {
-  return load_u1Fixed15 (icc, offset) + load_uint16 (icc, offset + 2) / 65535.0f;
+  return load_u1f15 (icc, length, offset) +
+         load_u16 (icc, length, offset + 2) / 65535.0f;
 }
 
-static double load_u16Fixed16 (const char *icc, int offset)
+static double load_u16f16 (const char *icc, int length, int offset)
 {
-  return load_uint16 (icc, offset) + load_uint16 (icc, offset + 2) / 65535.0;
+  return load_u16 (icc, length, offset) +
+         load_u16 (icc, length, offset + 2) / 65535.0;
 }
 
-static uint32_t load_uint32 (const char *icc, int offset)
+static uint32_t load_u32 (const char *icc, int length, int offset)
 {
-  return load_byte (icc, offset + 3) +
-         (load_byte (icc, offset + 2) << 8) +
-         (load_byte (icc, offset + 1) << 16) +
-         (load_byte (icc, offset + 0) << 24);
+  return load_byte (icc, length, offset + 3) +
+         (load_byte (icc, length, offset + 2) << 8) +
+         (load_byte (icc, length, offset + 1) << 16) +
+         (load_byte (icc, length, offset + 0) << 24);
 }
 
-static void load_sign (const char *icc, int offset, char *sign)
+static void load_sign (const char *icc, int length,
+                       int offset, char *sign)
 {
-  sign[0]=load_byte(icc, offset);
-  sign[1]=load_byte(icc, offset + 1);
-  sign[2]=load_byte(icc, offset + 2);
-  sign[3]=load_byte(icc, offset + 3);
+  sign[0]=load_byte(icc, length, offset);
+  sign[1]=load_byte(icc, length, offset + 1);
+  sign[2]=load_byte(icc, length, offset + 2);
+  sign[3]=load_byte(icc, length, offset + 3);
   sign[4]=0;
 }
 
-/* looks up offset and length for a specifi icc tag
+/* looks up offset and length for a specific icc tag
  */
-static int icc_tag (const char *icc, const char *tag, int *offset, int *length)
+static int icc_tag (const char *icc, int length,
+                    const char *tag, int *offset, int *el_length)
 {
-  int tag_count = load_uint32 (icc, TAG_COUNT_OFF);
-  int profile_size = load_uint32 (icc, 0);
+  int tag_count = load_u32 (icc, length, TAG_COUNT_OFF);
   int t;
 
   for (t =  0; t < tag_count; t++)
   {
      char tag_signature[5];
-     load_sign (icc, TAG_COUNT_OFF + 4 + 12 * t, tag_signature);
+     load_sign (icc, length, TAG_COUNT_OFF + 4 + 12 * t, tag_signature);
      if (!strcmp (tag_signature, tag))
      {
-        if (!offset)
-          return 1;
-        *offset = load_uint32 (icc, TAG_COUNT_OFF + 4 + 12* t + 4);
-        /* avert some potential for maliciousnes.. */
-        if (*offset >= profile_size)
-          {
-            *offset = profile_size - 1;
-          }
-        if (!length)
-          return 1;
-        *length = load_uint32 (icc, TAG_COUNT_OFF + 4 + 12* t + 4 * 2);
-        /* avert some potential for maliciousnes.. */
-        if (*offset + *length >= profile_size)
-          {
-            *length = profile_size - *offset - 1;
-          }
+        if (offset)
+          *offset = load_u32 (icc, length, TAG_COUNT_OFF + 4 + 12* t + 4);
+        if (el_length)
+          *el_length = load_u32 (icc, length, TAG_COUNT_OFF + 4 + 12* t + 4*2);
         return 1;
      }
   }
@@ -92,7 +115,7 @@ static const Babl *babl_trc_from_icc (const char *icc,
 {
   int offset = 0;
   {
-    int count = load_uint32 (icc, offset + 8);
+    int count = load_u32 (icc, length, offset + 8);
     int i;
     {
       if (count == 0)
@@ -101,8 +124,8 @@ static const Babl *babl_trc_from_icc (const char *icc,
       }
       else if (count == 1)
       {
-        return babl_trc_gamma (load_byte (icc, offset + 12) +
-                               load_byte (icc, offset + 12 + 1) / 255.0);
+        return babl_trc_gamma (load_byte (icc, length, offset + 12) +
+                               load_byte (icc, length, offset + 12 + 1)/255.0);
       }
       else
       {
@@ -113,9 +136,10 @@ static const Babl *babl_trc_from_icc (const char *icc,
 
         for (i = 0; i < count && i < 10; i ++)
         {
-          fprintf (stdout, "%i=%i ", i, load_uint16 (icc, offset + 12 + i * 2));
+          fprintf (stdout, "%i=%i ", i, load_u16 (icc, length,
+                                                  offset + 12 + i * 2));
           if (i % 7 == 0)
-           fprintf (stdout, "\n");
+            fprintf (stdout, "\n");
         }
       }
     }
@@ -128,11 +152,11 @@ babl_space_rgb_icc (const char *icc,
                     int         length,
                     char      **error)
 {
-  int  profile_size          = load_uint32 (icc, 0);
-  int  icc_ver_major         = load_byte (icc, 8);
-  const Babl *trc_red = NULL;
+  int  profile_size     = load_u32 (icc, length, 0);
+  int  icc_ver_major    = load_byte (icc, length, 8);
+  const Babl *trc_red   = NULL;
   const Babl *trc_green = NULL;
-  const Babl *trc_blue = NULL;
+  const Babl *trc_blue  = NULL;
   char profile_class[5];
   char color_space[5];
 
@@ -146,13 +170,13 @@ babl_space_rgb_icc (const char *icc,
     *error = "only ICC v2 profiles supported";
     return NULL;
   }
-  load_sign (icc, 12, profile_class);
+  load_sign (icc, length, 12, profile_class);
   if (strcmp (profile_class, "mntr"))
   {
     *error = "not a monitor-class profile";
     return NULL;
   }
-  load_sign (icc, 16, color_space);
+  load_sign (icc, length, 16, color_space);
   if (strcmp (color_space, "RGB "))
   {
     *error = "not defining an RGB space";
@@ -160,23 +184,20 @@ babl_space_rgb_icc (const char *icc,
   }
   {
      int offset, element_size;
-     if (icc_tag (icc, "rTRC", &offset, &element_size))
+     if (icc_tag (icc, length, "rTRC", &offset, &element_size))
      {
        trc_red = babl_trc_from_icc (icc + offset, element_size, error);
-       if (*error)
-         return NULL;
+       if (*error) return NULL;
      }
-     if (icc_tag (icc, "gTRC", &offset, &element_size))
+     if (icc_tag (icc, length, "gTRC", &offset, &element_size))
      {
        trc_green = babl_trc_from_icc (icc + offset, element_size, error);
-       if (*error)
-         return NULL;
+       if (*error) return NULL;
      }
-     if (icc_tag (icc, "bTRC", &offset, &element_size))
+     if (icc_tag (icc, length, "bTRC", &offset, &element_size))
      {
        trc_blue = babl_trc_from_icc (icc + offset, element_size, error);
-       if (*error)
-         return NULL;
+       if (*error) return NULL;
      }
   }
 
@@ -186,37 +207,40 @@ babl_space_rgb_icc (const char *icc,
      return NULL;
   }
 
-  if (icc_tag (icc, "chrm", NULL, NULL) &&
-      icc_tag (icc, "wtpt", NULL, NULL))
+  if (icc_tag (icc, length, "chrm", NULL, NULL) &&
+      icc_tag (icc, length, "wtpt", NULL, NULL))
   {
      int offset, element_size;
      double redX, redY, greenX, greenY, blueX, blueY;
+     int channels, phosporant;
 
-     icc_tag (icc, "chrm", &offset, &element_size);
-     {
-     int channels   = load_uint16 (icc, offset + 8);
-     int phosporant = load_uint16 (icc, offset + 10);
-
-     redX    = load_s15Fixed16 (icc, offset + 12);
-     redY    = load_s15Fixed16 (icc, offset + 12 + 4);
-     greenX  = load_s15Fixed16 (icc, offset + 20);
-     greenY  = load_s15Fixed16 (icc, offset + 20 + 4);
-     blueX   = load_s15Fixed16 (icc, offset + 28);
-     blueY   = load_s15Fixed16 (icc, offset + 28 + 4);
+     icc_tag (icc, length, "chrm", &offset, &element_size);
+     channels   = load_u16 (icc, length, offset + 8);
+     phosporant = load_u16 (icc, length, offset + 10);
 
-     fprintf (stdout, "chromaticity:\n");
-     fprintf (stdout, "  channels: %i\n", channels);
-     fprintf (stdout, "  phosphorant: %i\n", phosporant);
-     fprintf (stdout, "  CIE xy red: %f %f\n", redX, redY);
-     fprintf (stdout, "  CIE xy green: %f %f\n", greenX, greenY);
-     fprintf (stdout, "  CIE xy blue: %f %f\n", blueX, blueY);
+     if (phosporant != 0)
+     {
+       *error = "unhandled phosporants, please report bug";
+       return NULL;
      }
+     if (channels != 3)
+     {
+       *error = "unexpected non 3 count of channels";
+       return NULL;
+     }
+
+     redX    = load_s15f15 (icc, length, offset + 12);
+     redY    = load_s15f15 (icc, length, offset + 12 + 4);
+     greenX  = load_s15f15 (icc, length, offset + 20);
+     greenY  = load_s15f15 (icc, length, offset + 20 + 4);
+     blueX   = load_s15f15 (icc, length, offset + 28);
+     blueY   = load_s15f15 (icc, length, offset + 28 + 4);
 
-     icc_tag (icc, "wtpt", &offset, &element_size);
+     icc_tag (icc, length, "wtpt", &offset, &element_size);
      {
-       double wX = load_u16Fixed16 (icc, offset + 8);
-       double wY = load_u16Fixed16 (icc, offset + 8 + 4);
-       double wZ = load_u16Fixed16 (icc, offset + 8 + 4 * 2);
+       double wX = load_u16f16 (icc, length, offset + 8);
+       double wY = load_u16f16 (icc, length, offset + 8 + 4);
+       double wZ = load_u16f16 (icc, length, offset + 8 + 4 * 2);
 
        return babl_space_rgb_chromaticities (NULL,
                        wX / (wX + wY + wZ),
@@ -228,27 +252,27 @@ babl_space_rgb_icc (const char *icc,
 
      }
   }
-  else if (icc_tag (icc, "rXYZ", NULL, NULL) &&
-           icc_tag (icc, "gXYZ", NULL, NULL) &&
-           icc_tag (icc, "bXYZ", NULL, NULL))
+  else if (icc_tag (icc, length, "rXYZ", NULL, NULL) &&
+           icc_tag (icc, length, "gXYZ", NULL, NULL) &&
+           icc_tag (icc, length, "bXYZ", NULL, NULL))
   {
      int offset, element_size;
      double rx, gx, bx;
      double ry, gy, by;
      double rz, gz, bz;
 
-     icc_tag (icc, "rXYZ", &offset, &element_size);
-     rx = load_u16Fixed16 (icc, offset + 8 + 4 * 0);
-     ry = load_u16Fixed16 (icc, offset + 8 + 4 * 1);
-     rz = load_u16Fixed16 (icc, offset + 8 + 4 * 2);
-     icc_tag (icc, "gXYZ", &offset, &element_size);
-     gx = load_u16Fixed16 (icc, offset + 8 + 4 * 0);
-     gy = load_u16Fixed16 (icc, offset + 8 + 4 * 1);
-     gz = load_u16Fixed16 (icc, offset + 8 + 4 * 2);
-     icc_tag (icc, "bXYZ", &offset, &element_size);
-     bx = load_u16Fixed16 (icc, offset + 8 + 4 * 0);
-     by = load_u16Fixed16 (icc, offset + 8 + 4 * 1);
-     bz = load_u16Fixed16 (icc, offset + 8 + 4 * 2);
+     icc_tag (icc, length, "rXYZ", &offset, &element_size);
+     rx = load_u16f16 (icc, length, offset + 8 + 4 * 0);
+     ry = load_u16f16 (icc, length, offset + 8 + 4 * 1);
+     rz = load_u16f16 (icc, length, offset + 8 + 4 * 2);
+     icc_tag (icc, length, "gXYZ", &offset, &element_size);
+     gx = load_u16f16 (icc, length, offset + 8 + 4 * 0);
+     gy = load_u16f16 (icc, length, offset + 8 + 4 * 1);
+     gz = load_u16f16 (icc, length, offset + 8 + 4 * 2);
+     icc_tag (icc, length, "bXYZ", &offset, &element_size);
+     bx = load_u16f16 (icc, length, offset + 8 + 4 * 0);
+     by = load_u16f16 (icc, length, offset + 8 + 4 * 1);
+     bz = load_u16f16 (icc, length, offset + 8 + 4 * 2);
 
      return babl_space_rgb_matrix (NULL,
                 rx, gx, bx,


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