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