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