#1763173 from Stefan Huehner: declare some more functions static.
[privoxy.git] / deanimate.c
1 const char deanimate_rcs[] = "$Id: deanimate.c,v 1.16 2007/07/14 08:01:58 fabiankeil Exp $";
2 /*********************************************************************
3  *
4  * File        :  $Source: /cvsroot/ijbswa/current/deanimate.c,v $
5  *
6  * Purpose     :  Declares functions to manipulate binary images on the
7  *                fly.  High-level functions include:
8  *                  - Deanimation of GIF images
9  *                  - Fixup of malformed comment block in JPEG headers
10  *                
11  *                Functions declared include: gif_deanimate, buf_free,
12  *                buf_copy,  buf_getbyte, gif_skip_data_block,
13  *                gif_extract_image and jpeg_inspect
14  *
15  * Copyright   :  Written by and Copyright (C) 2001 - 2004, 2006 by the
16  *                SourceForge Privoxy team. http://www.privoxy.org/
17  *
18  *                Based on the GIF file format specification (see
19  *                http://tronche.com/computer-graphics/gif/gif89a.html)
20  *                and ideas from the Image::DeAnim Perl module by
21  *                Ken MacFarlane, <ksm+cpan@universal.dca.net>
22  *
23  *                This program is free software; you can redistribute it 
24  *                and/or modify it under the terms of the GNU General
25  *                Public License as published by the Free Software
26  *                Foundation; either version 2 of the License, or (at
27  *                your option) any later version.
28  *
29  *                This program is distributed in the hope that it will
30  *                be useful, but WITHOUT ANY WARRANTY; without even the
31  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
32  *                PARTICULAR PURPOSE.  See the GNU General Public
33  *                License for more details.
34  *
35  *                The GNU General Public License should be included with
36  *                this file.  If not, you can view it at
37  *                http://www.gnu.org/copyleft/gpl.html
38  *                or write to the Free Software Foundation, Inc., 59
39  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
40  *
41  * Revisions   :
42  *    $Log: deanimate.c,v $
43  *    Revision 1.16  2007/07/14 08:01:58  fabiankeil
44  *    s@failiure@failure@
45  *
46  *    Revision 1.15  2007/01/03 14:39:19  fabiankeil
47  *    Fix a gcc43 warning and mark the binbuffer
48  *    as immutable for buf_getbyte().
49  *
50  *    Revision 1.14  2006/07/18 14:48:45  david__schmidt
51  *    Reorganizing the repository: swapping out what was HEAD (the old 3.1 branch)
52  *    with what was really the latest development (the v_3_0_branch branch)
53  *
54  *    Revision 1.12.2.1  2004/10/03 12:53:32  david__schmidt
55  *    Add the ability to check jpeg images for invalid
56  *    lengths of comment blocks.  Defensive strategy
57  *    against the exploit:
58  *       Microsoft Security Bulletin MS04-028
59  *       Buffer Overrun in JPEG Processing (GDI+) Could
60  *       Allow Code Execution (833987)
61  *    Enabled with +inspect-jpegs in actions files.
62  *
63  *    Revision 1.12  2002/05/12 21:36:29  jongfoster
64  *    Correcting function comments
65  *
66  *    Revision 1.11  2002/03/26 22:29:54  swa
67  *    we have a new homepage!
68  *
69  *    Revision 1.10  2002/03/24 13:25:43  swa
70  *    name change related issues
71  *
72  *    Revision 1.9  2002/03/13 00:27:04  jongfoster
73  *    Killing warnings
74  *
75  *    Revision 1.8  2002/03/09 19:42:47  jongfoster
76  *    Fixing more warnings
77  *
78  *    Revision 1.7  2002/03/08 17:46:04  jongfoster
79  *    Fixing int/size_t warnings
80  *
81  *    Revision 1.6  2002/03/07 03:46:17  oes
82  *    Fixed compiler warnings
83  *
84  *    Revision 1.5  2001/09/10 10:16:06  oes
85  *    Silenced compiler warnings
86  *
87  *    Revision 1.4  2001/07/18 12:28:49  oes
88  *    - Added feature for extracting the first frame
89  *      to gif_deanimate
90  *    - Separated image buffer extension into buf_extend
91  *    - Extended gif deanimation to GIF87a (untested!)
92  *    - Cosmetics
93  *
94  *    Revision 1.3  2001/07/15 13:57:50  jongfoster
95  *    Adding #includes string.h and miscutil.h
96  *
97  *    Revision 1.2  2001/07/13 13:46:20  oes
98  *    Introduced GIF deanimation feature
99  *
100  *
101  **********************************************************************/
102 \f
103
104 #include "config.h"
105
106 #include <string.h>
107 #include <fcntl.h>
108
109 #include "errlog.h"
110 #include "project.h"
111 #include "deanimate.h"
112 #include "miscutil.h"
113
114 const char deanimate_h_rcs[] = DEANIMATE_H_VERSION;
115
116 /*********************************************************************
117  * 
118  * Function    :  buf_free
119  *
120  * Description :  Safely frees a struct binbuffer
121  *
122  * Parameters  :
123  *          1  :  buf = Pointer to the binbuffer to be freed
124  *
125  * Returns     :  N/A
126  *
127  *********************************************************************/
128 void buf_free(struct binbuffer *buf)
129 {
130    if (buf == NULL) return;
131
132    if (buf->buffer != NULL)
133    {
134       free(buf->buffer);
135    }
136
137    free(buf);
138
139 }
140
141
142 /*********************************************************************
143  * 
144  * Function    :  buf_extend
145  *
146  * Description :  Ensure that a given binbuffer can hold a given amount
147  *                of bytes, by reallocating its buffer if necessary.
148  *                Allocate new mem in chunks of 1024 bytes, so we don't
149  *                have to realloc() too often.
150  *
151  * Parameters  :
152  *          1  :  buf = Pointer to the binbuffer
153  *          2  :  length = Desired minimum size
154  *                
155  *
156  * Returns     :  0 on success, 1 on failure.
157  *
158  *********************************************************************/
159 static int buf_extend(struct binbuffer *buf, size_t length)
160 {
161    char *newbuf;
162
163    if (buf->offset + length > buf->size)
164    {
165       buf->size = ((buf->size + length + (size_t)1023) & ~(size_t)1023);
166       newbuf = (char *)realloc(buf->buffer, buf->size);
167
168       if (newbuf == NULL)
169       {
170          freez(buf->buffer);
171          return 1;
172       }
173       else
174       {
175          buf->buffer = newbuf;
176          return 0;
177       }
178    }
179    return 0;
180
181 }
182
183
184 /*********************************************************************
185  * 
186  * Function    :  buf_copy
187  *
188  * Description :  Safely copies a given amount of bytes from one
189  *                struct binbuffer to another, advancing the
190  *                offsets appropriately.
191  *
192  * Parameters  :
193  *          1  :  src = Pointer to the source binbuffer
194  *          2  :  dst = Pointer to the destination binbuffer
195  *          3  :  length = Number of bytes to be copied
196  *
197  * Returns     :  0 on success, 1 on failure.
198  *
199  *********************************************************************/
200 static int buf_copy(struct binbuffer *src, struct binbuffer *dst, size_t length)
201 {
202
203    /*
204     * Sanity check: Can't copy more data than we have
205     */
206    if (src->offset + length > src->size) 
207    {
208       return 1;
209    }
210
211    /*
212     * Ensure that dst can hold the new data
213     */
214    if (buf_extend(dst, length)) 
215    {
216       return 1;
217    }
218
219    /*
220     * Now that it's safe, memcpy() the desired amount of
221     * data from src to dst and adjust the offsets
222     */
223    memcpy(dst->buffer + dst->offset, src->buffer + src->offset, length);
224    src->offset += length;
225    dst->offset += length;
226
227    return 0;
228
229 }
230
231
232 /*********************************************************************
233  * 
234  * Function    :  buf_getbyte
235  *
236  * Description :  Safely gets a byte from a given binbuffer at a
237  *                given offset
238  *
239  * Parameters  :
240  *          1  :  src = Pointer to the source binbuffer
241  *          2  :  offset = Offset to the desired byte
242  *
243  * Returns     :  The byte on success, or 0 on failure
244  *
245  *********************************************************************/
246 static unsigned char buf_getbyte(const struct binbuffer *src, size_t offset)
247 {
248    if (src->offset + offset < src->size)
249    {
250       return (unsigned char)*(src->buffer + src->offset + offset);
251    }
252    else
253    {
254       return '\0';
255    }
256
257 }
258
259
260 /*********************************************************************
261  * 
262  * Function    :  gif_skip_data_block
263  *
264  * Description :  Safely advances the offset of a given struct binbuffer
265  *                that contains a GIF image and whose offset is
266  *                positioned at the start of a data block, behind
267  *                that block.
268  *
269  * Parameters  :
270  *          1  :  buf = Pointer to the binbuffer
271  *
272  * Returns     :  0 on success, or 1 on failure
273  *
274  *********************************************************************/
275 static int gif_skip_data_block(struct binbuffer *buf)
276 {
277    unsigned char c;
278
279    /* 
280     * Data blocks are sequences of chunks, which are headed
281     * by a one-byte length field, with the last chunk having
282     * zero length.
283     */
284    while((c = buf_getbyte(buf, 0)) != '\0')
285    {
286       buf->offset += (size_t)c + 1;
287       if (buf->offset >= buf->size - 1)
288       {
289          return 1;
290       }
291    }
292    buf->offset++;
293
294    return 0;
295
296 }
297
298
299 /*********************************************************************
300  * 
301  * Function    :  gif_extract_image
302  *
303  * Description :  Safely extracts an image data block from a given
304  *                struct binbuffer that contains a GIF image and whose
305  *                offset is positioned at the start of a data block 
306  *                into a given destination binbuffer.
307  *
308  * Parameters  :
309  *          1  :  src = Pointer to the source binbuffer
310  *          2  :  dst = Pointer to the destination binbuffer
311  *
312  * Returns     :  0 on success, or 1 on failure
313  *
314  *********************************************************************/
315 static int gif_extract_image(struct binbuffer *src, struct binbuffer *dst)
316 {
317    unsigned char c;
318
319    /*
320     * Remember the colormap flag and copy the image head
321     */
322    c = buf_getbyte(src, 9);
323    if (buf_copy(src, dst, 10))
324    {
325       return 1;
326    }
327
328    /*
329     * If the image has a local colormap, copy it.
330     */
331    if (c & 0x80)
332    {
333       if (buf_copy(src, dst, (size_t) 3 * (1 << ((c & 0x07) + 1))))
334       {
335          return 1;
336       }           
337    }
338    if (buf_copy(src, dst, 1)) return 1;
339
340    /*
341     * Copy the image chunk by chunk.
342     */
343    while((c = buf_getbyte(src, 0)) != '\0')
344    {
345       if (buf_copy(src, dst, 1 + (size_t) c)) return 1;
346    }
347    if (buf_copy(src, dst, 1)) return 1;
348
349    /*
350     * Trim and rewind the dst buffer
351     */
352    if (NULL == (dst->buffer = (char *)realloc(dst->buffer, dst->offset))) return 1;
353    dst->size = dst->offset;
354    dst->offset = 0;
355
356    return(0);
357
358 }
359
360 /*********************************************************************
361  * 
362  * Function    :  gif_deanimate
363  *
364  * Description :  Deanimate a given GIF image, i.e. given a GIF with
365  *                an (optional) image block and an arbitrary number
366  *                of image extension blocks, produce an output GIF with
367  *                only one image block that contains the last image
368  *                (extenstion) block of the original.
369  *                Also strip Comments, Application extenstions, etc.
370  *
371  * Parameters  :
372  *          1  :  src = Pointer to the source binbuffer
373  *          2  :  dst = Pointer to the destination binbuffer
374  *          3  :  get_first_image = Flag: If set, get the first image
375  *                                        If unset (default), get the last
376  *
377  * Returns     :  0 on success, or 1 on failure
378  *
379  *********************************************************************/
380 int gif_deanimate(struct binbuffer *src, struct binbuffer *dst, int get_first_image)
381 {
382    unsigned char c;
383    struct binbuffer *image;
384
385    if (NULL == src || NULL == dst)
386    {
387       return 1;
388    }
389
390    c = buf_getbyte(src, 10);
391
392    /*
393     * Check & copy GIF header 
394     */
395    if (strncmp(src->buffer, "GIF89a", 6) && strncmp(src->buffer, "GIF87a", 6)) 
396    {
397       return 1;
398    }
399    else
400    {
401       if (buf_copy(src, dst, 13))
402       {
403          return 1;
404       }
405    }
406
407    /*
408     * Look for global colormap and  copy if found.
409     */
410    if(c & 0x80)
411    {
412       if (buf_copy(src, dst, (size_t) 3 * (1 << ((c & 0x07) + 1))))
413       {
414          return 1;
415       }
416    }
417
418    /*
419     * Reserve a buffer for the current image block
420     */
421    if (NULL == (image = (struct binbuffer *)zalloc(sizeof(*image))))
422    {
423       return 1;
424    }
425
426    /*
427     * Parse the GIF block by block and copy the relevant
428     * parts to dst
429     */
430    while(src->offset < src->size)
431    {
432       switch(buf_getbyte(src, 0))
433       {
434          /*
435           *  End-of-GIF Marker: Append current image and return
436           */
437       case 0x3b:
438          goto write;
439
440          /* 
441           * Image block: Extract to current image buffer.
442           */
443       case 0x2c:
444          image->offset = 0;
445          if (gif_extract_image(src, image)) goto failed;
446          if (get_first_image) goto write;
447          continue;
448
449          /*
450           * Extension block: Look at next byte and decide
451           */
452       case 0x21:
453          switch (buf_getbyte(src, 1))
454          {
455             /*
456              * Image extension: Copy extension  header and image
457              *                  to the current image buffer
458              */
459          case 0xf9:
460             image->offset = 0;
461             if (buf_copy(src, image, 8) || buf_getbyte(src, 0) != 0x2c) goto failed;
462             if (gif_extract_image(src, image)) goto failed;
463             if (get_first_image) goto write;
464             continue;
465
466             /*
467              * Application extension: Skip
468              */
469          case 0xff:
470             if ((src->offset += 14) >= src->size || gif_skip_data_block(src)) goto failed;
471             continue;
472
473             /*
474              * Comment extension: Skip
475              */
476          case 0xfe:
477             if ((src->offset += 2) >= src->size || gif_skip_data_block(src)) goto failed;
478             continue;
479
480             /*
481              * Plain text extension: Skip
482              */
483          case 0x01:
484             if ((src->offset += 15) >= src->size || gif_skip_data_block(src)) goto failed;
485             continue;
486
487             /*
488              * Ooops, what type of extension is that?
489              */
490          default:
491             goto failed;
492
493          }
494
495          /*
496           * Ooops, what type of block is that?
497           */
498       default:
499          goto failed;
500          
501       }
502    } /* -END- while src */
503
504    /*
505     * Either we got here by goto, or because the GIF is
506     * bogus and EOF was reached before an end-of-gif marker 
507     * was found.
508     */
509
510 failed:
511    buf_free(image);
512    return 1;
513
514    /*
515     * Append the current image to dst and return
516     */
517
518 write:
519    if (buf_copy(image, dst, image->size)) goto failed;
520    if (buf_extend(dst, 1)) goto failed;
521    *(dst->buffer + dst->offset++) = 0x3b;
522    buf_free(image);
523    return 0;
524
525 }
526
527
528 /*********************************************************************
529  * 
530  * Function    :  jpeg_inspect
531  *
532  * Description :  Checks a jpeg image for an invalid length in a 
533  *                comment block (0xFFFE0000 or 0xFFFE0001) and
534  *                changes it to 0xFFFE0002.  Defensive strategy 
535  *                against the exploit:
536  *                  Microsoft Security Bulletin MS04-028
537  *                  Buffer Overrun in JPEG Processing (GDI+) Could
538  *                  Allow Code Execution (833987)
539  *
540  * Parameters  :
541  *          1  :  src = Pointer to the image binbuffer
542  *
543  * Returns     :  0 on success, or 1 on failure
544  *
545  *********************************************************************/
546 int jpeg_inspect(struct binbuffer *src, struct binbuffer *dst)
547 {
548    long i;
549    /*
550     * We process the image using a simple finite state machine, 
551     * searching for byte patterns.
552     */
553    enum { J_INIT, /* The initial state */
554           J_FF,   /* Found byte 0xFF */
555           J_FE,   /* Found bytes 0xFF 0xFE */
556           J_00,   /* Found bytes 0xFF 0xFE 0x00 */
557           J_DA    /*
558                    * Found bytes 0xFF 0xDA; short-circuit to done-ness
559                    * since this signals the beginning end of headers.
560                    */
561         };
562    short state = J_INIT;
563    unsigned char c;
564
565    if (NULL == src || NULL == dst)
566    {
567       return 1;
568    }
569
570    if (buf_copy(src, dst, src->size))
571    {
572       return 1;
573    }
574
575    /* Need to search the jpg for patterns:
576     * 0xFF 0xFE 0x00 0x00
577     * or 
578     * 0xFF 0xFE 0x00 0x01
579     * from beginning until:
580     * 0xFF 0xDA
581     * (or the end of the buffer)
582     * If found, change the pattern to 0xFF 0xFE 0x00 0x02
583     */
584
585    for (i = 0; i < dst->size; i++)
586    {
587       c = dst->buffer[i];
588       switch (state)
589       {
590          case J_INIT:
591             if (c == 0xFF)
592                state = J_FF;
593             break;
594          case J_FF:
595             if (c == 0xDA)
596                state = J_DA; /* End of headers - we're done with this image. */
597             else if (c == 0xFE)
598                state = J_FE;
599             else
600                state = J_INIT;
601             break;
602          case J_FE:
603             if (c == 0x00)
604                state = J_00;
605             else
606                state = J_INIT;
607             break;
608          case J_00:
609             if ((c == 0x00) || (c == 0x01))
610             {
611                dst->buffer[i] = 2; /* Reset comment block size to 2. */
612                log_error(LOG_LEVEL_INFO, "JPEG comment exploit removed.");
613                /* TODO:
614                 * I'm unsure if we can have more than one comment block.  Just in case,
615                 * we'll scan the rest of the header for more by going back to J_INIT
616                 * state.  If there is no possibility of >1 comment block, we could 
617                 * short-circuit to done-ness here.
618                 */
619                state = J_INIT;
620             }
621             else
622                state = J_INIT;
623             break;
624          default:
625             break;
626       }
627       if (state == J_DA)
628          break;
629    }
630
631    return 0;
632 }
633
634
635 /*
636   Local Variables:
637   tab-width: 3
638   end:
639 */