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