Remove unused OSX_DARWIN macro. Reported by Mark Miller in #1852529.
[privoxy.git] / deanimate.c
index 59ed56e..4e4aaac 100644 (file)
@@ -1,16 +1,19 @@
-const char deanimate_rcs[] = "$Id: deanimate.c,v 1.11 2002/03/26 22:29:54 swa Exp $";
+const char deanimate_rcs[] = "$Id: deanimate.c,v 1.16 2007/07/14 08:01:58 fabiankeil Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/deanimate.c,v $
  *
- * Purpose     :  Declares functions to deanimate GIF images on the fly.
+ * Purpose     :  Declares functions to manipulate binary images on the
+ *                fly.  High-level functions include:
+ *                  - Deanimation of GIF images
+ *                  - Fixup of malformed comment block in JPEG headers
  *                
  *                Functions declared include: gif_deanimate, buf_free,
- *                buf_copy,  buf_getbyte, gif_skip_data_block, and
- *                gif_extract_image
+ *                buf_copy,  buf_getbyte, gif_skip_data_block,
+ *                gif_extract_image and jpeg_inspect
  *
- * Copyright   :  Written by and Copyright (C) 2001 by the the SourceForge
- *                Privoxy team. http://www.privoxy.org/
+ * Copyright   :  Written by and Copyright (C) 2001 - 2004, 2006 by the
+ *                SourceForge Privoxy team. http://www.privoxy.org/
  *
  *                Based on the GIF file format specification (see
  *                http://tronche.com/computer-graphics/gif/gif89a.html)
@@ -37,6 +40,29 @@ const char deanimate_rcs[] = "$Id: deanimate.c,v 1.11 2002/03/26 22:29:54 swa Ex
  *
  * Revisions   :
  *    $Log: deanimate.c,v $
+ *    Revision 1.16  2007/07/14 08:01:58  fabiankeil
+ *    s@failiure@failure@
+ *
+ *    Revision 1.15  2007/01/03 14:39:19  fabiankeil
+ *    Fix a gcc43 warning and mark the binbuffer
+ *    as immutable for buf_getbyte().
+ *
+ *    Revision 1.14  2006/07/18 14:48:45  david__schmidt
+ *    Reorganizing the repository: swapping out what was HEAD (the old 3.1 branch)
+ *    with what was really the latest development (the v_3_0_branch branch)
+ *
+ *    Revision 1.12.2.1  2004/10/03 12:53:32  david__schmidt
+ *    Add the ability to check jpeg images for invalid
+ *    lengths of comment blocks.  Defensive strategy
+ *    against the exploit:
+ *       Microsoft Security Bulletin MS04-028
+ *       Buffer Overrun in JPEG Processing (GDI+) Could
+ *       Allow Code Execution (833987)
+ *    Enabled with +inspect-jpegs in actions files.
+ *
+ *    Revision 1.12  2002/05/12 21:36:29  jongfoster
+ *    Correcting function comments
+ *
  *    Revision 1.11  2002/03/26 22:29:54  swa
  *    we have a new homepage!
  *
@@ -80,6 +106,7 @@ const char deanimate_rcs[] = "$Id: deanimate.c,v 1.11 2002/03/26 22:29:54 swa Ex
 #include <string.h>
 #include <fcntl.h>
 
+#include "errlog.h"
 #include "project.h"
 #include "deanimate.h"
 #include "miscutil.h"
@@ -126,10 +153,10 @@ void buf_free(struct binbuffer *buf)
  *          2  :  length = Desired minimum size
  *                
  *
- * Returns     :  0 on success, 1 on failiure.
+ * Returns     :  0 on success, 1 on failure.
  *
  *********************************************************************/
-int buf_extend(struct binbuffer *buf, size_t length)
+static int buf_extend(struct binbuffer *buf, size_t length)
 {
    char *newbuf;
 
@@ -167,10 +194,10 @@ int buf_extend(struct binbuffer *buf, size_t length)
  *          2  :  dst = Pointer to the destination binbuffer
  *          3  :  length = Number of bytes to be copied
  *
- * Returns     :  0 on success, 1 on failiure.
+ * Returns     :  0 on success, 1 on failure.
  *
  *********************************************************************/
-int buf_copy(struct binbuffer *src, struct binbuffer *dst, size_t length)
+static int buf_copy(struct binbuffer *src, struct binbuffer *dst, size_t length)
 {
 
    /*
@@ -213,10 +240,10 @@ int buf_copy(struct binbuffer *src, struct binbuffer *dst, size_t length)
  *          1  :  src = Pointer to the source binbuffer
  *          2  :  offset = Offset to the desired byte
  *
- * Returns     :  The byte on success, or 0 on failiure
+ * Returns     :  The byte on success, or 0 on failure
  *
  *********************************************************************/
-unsigned char buf_getbyte(struct binbuffer *src, size_t offset)
+static unsigned char buf_getbyte(const struct binbuffer *src, size_t offset)
 {
    if (src->offset + offset < src->size)
    {
@@ -242,10 +269,10 @@ unsigned char buf_getbyte(struct binbuffer *src, size_t offset)
  * Parameters  :
  *          1  :  buf = Pointer to the binbuffer
  *
- * Returns     :  0 on success, or 1 on failiure
+ * Returns     :  0 on success, or 1 on failure
  *
  *********************************************************************/
-int gif_skip_data_block(struct binbuffer *buf)
+static int gif_skip_data_block(struct binbuffer *buf)
 {
    unsigned char c;
 
@@ -256,7 +283,8 @@ int gif_skip_data_block(struct binbuffer *buf)
     */
    while((c = buf_getbyte(buf, 0)) != '\0')
    {
-      if ((buf->offset += c + 1) >= buf->size - 1)
+      buf->offset += (size_t)c + 1;
+      if (buf->offset >= buf->size - 1)
       {
          return 1;
       }
@@ -281,13 +309,13 @@ int gif_skip_data_block(struct binbuffer *buf)
  *          1  :  src = Pointer to the source binbuffer
  *          2  :  dst = Pointer to the destination binbuffer
  *
- * Returns     :  0 on success, or 1 on failiure
+ * Returns     :  0 on success, or 1 on failure
  *
  *********************************************************************/
-int gif_extract_image(struct binbuffer *src, struct binbuffer *dst)
+static int gif_extract_image(struct binbuffer *src, struct binbuffer *dst)
 {
    unsigned char c;
-   
+
    /*
     * Remember the colormap flag and copy the image head
     */
@@ -346,7 +374,7 @@ int gif_extract_image(struct binbuffer *src, struct binbuffer *dst)
  *          3  :  get_first_image = Flag: If set, get the first image
  *                                        If unset (default), get the last
  *
- * Returns     :  0 on success, or 1 on failiure
+ * Returns     :  0 on success, or 1 on failure
  *
  *********************************************************************/
 int gif_deanimate(struct binbuffer *src, struct binbuffer *dst, int get_first_image)
@@ -497,6 +525,113 @@ write:
 }
 
 
+/*********************************************************************
+ * 
+ * Function    :  jpeg_inspect
+ *
+ * Description :  Checks a jpeg image for an invalid length in a 
+ *                comment block (0xFFFE0000 or 0xFFFE0001) and
+ *                changes it to 0xFFFE0002.  Defensive strategy 
+ *                against the exploit:
+ *                  Microsoft Security Bulletin MS04-028
+ *                  Buffer Overrun in JPEG Processing (GDI+) Could
+ *                  Allow Code Execution (833987)
+ *
+ * Parameters  :
+ *          1  :  src = Pointer to the image binbuffer
+ *
+ * Returns     :  0 on success, or 1 on failure
+ *
+ *********************************************************************/
+int jpeg_inspect(struct binbuffer *src, struct binbuffer *dst)
+{
+   long i;
+   /*
+    * We process the image using a simple finite state machine, 
+    * searching for byte patterns.
+    */
+   enum { J_INIT, /* The initial state */
+          J_FF,   /* Found byte 0xFF */
+          J_FE,   /* Found bytes 0xFF 0xFE */
+          J_00,   /* Found bytes 0xFF 0xFE 0x00 */
+          J_DA    /*
+                   * Found bytes 0xFF 0xDA; short-circuit to done-ness
+                   * since this signals the beginning end of headers.
+                   */
+        };
+   short state = J_INIT;
+   unsigned char c;
+
+   if (NULL == src || NULL == dst)
+   {
+      return 1;
+   }
+
+   if (buf_copy(src, dst, src->size))
+   {
+      return 1;
+   }
+
+   /* Need to search the jpg for patterns:
+    * 0xFF 0xFE 0x00 0x00
+    * or 
+    * 0xFF 0xFE 0x00 0x01
+    * from beginning until:
+    * 0xFF 0xDA
+    * (or the end of the buffer)
+    * If found, change the pattern to 0xFF 0xFE 0x00 0x02
+    */
+
+   for (i = 0; i < dst->size; i++)
+   {
+      c = dst->buffer[i];
+      switch (state)
+      {
+         case J_INIT:
+            if (c == 0xFF)
+               state = J_FF;
+            break;
+         case J_FF:
+            if (c == 0xDA)
+               state = J_DA; /* End of headers - we're done with this image. */
+            else if (c == 0xFE)
+               state = J_FE;
+            else
+               state = J_INIT;
+            break;
+         case J_FE:
+            if (c == 0x00)
+               state = J_00;
+            else
+               state = J_INIT;
+            break;
+         case J_00:
+            if ((c == 0x00) || (c == 0x01))
+            {
+               dst->buffer[i] = 2; /* Reset comment block size to 2. */
+               log_error(LOG_LEVEL_INFO, "JPEG comment exploit removed.");
+               /* TODO:
+                * I'm unsure if we can have more than one comment block.  Just in case,
+                * we'll scan the rest of the header for more by going back to J_INIT
+                * state.  If there is no possibility of >1 comment block, we could 
+                * short-circuit to done-ness here.
+                */
+               state = J_INIT;
+            }
+            else
+               state = J_INIT;
+            break;
+         default:
+            break;
+      }
+      if (state == J_DA)
+         break;
+   }
+
+   return 0;
+}
+
+
 /*
   Local Variables:
   tab-width: 3