@@ -25,13 +25,59 @@ static void read4B(UINT32* dest, UINT8* buf)
2525 * dest = (UINT32 )((buf [0 ] << 24 ) | (buf [1 ] << 16 ) | (buf [2 ] << 8 ) | buf [3 ]);
2626}
2727
28- static int expandrow (UINT8 * dest , UINT8 * src , int n , int z , int xsize )
28+ /*
29+ SgiRleDecoding is done in a single channel row oriented set of RLE chunks.
30+
31+ * The file is arranged as
32+ - SGI Header
33+ - Rle Offset Table
34+ - Rle Length Table
35+ - Scanline Data
36+
37+ * Each RLE atom is c->bpc bytes wide (1 or 2)
38+
39+ * Each RLE Chunk is [specifier atom] [ 1 or n data atoms ]
40+
41+ * Copy Atoms are a byte with the high bit set, and the low 7 are
42+ the number of bytes to copy from the source to the
43+ destination. e.g.
44+
45+ CBBBBBBBB or 0CHLHLHLHLHLHL (B=byte, H/L = Hi low bytes)
46+
47+ * Run atoms do not have the high bit set, and the low 7 bits are
48+ the number of copies of the next atom to copy to the
49+ destination. e.g.:
50+
51+ RB -> BBBBB or RHL -> HLHLHLHLHL
52+
53+ The upshot of this is, there is no way to determine the required
54+ length of the input buffer from reloffset and rlelength without
55+ going through the data at that scan line.
56+
57+ Furthermore, there's no requirement that individual scan lines
58+ pointed to from the rleoffset table are in any sort of order or
59+ used only once, or even disjoint. There's also no requirement that
60+ all of the data in the scan line area of the image file be used
61+
62+ */
63+ static int expandrow (UINT8 * dest , UINT8 * src , int n , int z , int xsize , UINT8 * end_of_buffer )
2964{
65+ /*
66+ * n here is the number of rlechunks
67+ * z is the number of channels, for calculating the interleave
68+ * offset to go to RGBA style pixels
69+ * xsize is the row width
70+ * end_of_buffer is the address of the end of the input buffer
71+ */
72+
3073 UINT8 pixel , count ;
3174 int x = 0 ;
3275
3376 for (;n > 0 ; n -- )
3477 {
78+ if (src > end_of_buffer ) {
79+ return -1 ;
80+ }
3581 pixel = * src ++ ;
3682 if (n == 1 && pixel != 0 ) {
3783 return n ;
@@ -45,13 +91,19 @@ static int expandrow(UINT8* dest, UINT8* src, int n, int z, int xsize)
4591 }
4692 x += count ;
4793 if (pixel & RLE_COPY_FLAG ) {
94+ if (src + count > end_of_buffer ) {
95+ return -1 ;
96+ }
4897 while (count -- ) {
4998 * dest = * src ++ ;
5099 dest += z ;
51100 }
52101
53102 }
54103 else {
104+ if (src > end_of_buffer ) {
105+ return -1 ;
106+ }
55107 pixel = * src ++ ;
56108 while (count -- ) {
57109 * dest = pixel ;
@@ -63,14 +115,16 @@ static int expandrow(UINT8* dest, UINT8* src, int n, int z, int xsize)
63115 return 0 ;
64116}
65117
66- static int expandrow2 (UINT8 * dest , const UINT8 * src , int n , int z , int xsize )
118+ static int expandrow2 (UINT8 * dest , const UINT8 * src , int n , int z , int xsize , UINT8 * end_of_buffer )
67119{
68120 UINT8 pixel , count ;
69-
70121 int x = 0 ;
71122
72123 for (;n > 0 ; n -- )
73124 {
125+ if (src + 1 > end_of_buffer ) {
126+ return -1 ;
127+ }
74128 pixel = src [1 ];
75129 src += 2 ;
76130 if (n == 1 && pixel != 0 ) {
@@ -85,13 +139,19 @@ static int expandrow2(UINT8* dest, const UINT8* src, int n, int z, int xsize)
85139 }
86140 x += count ;
87141 if (pixel & RLE_COPY_FLAG ) {
142+ if (src + 2 * count > end_of_buffer ) {
143+ return -1 ;
144+ }
88145 while (count -- ) {
89146 memcpy (dest , src , 2 );
90147 src += 2 ;
91148 dest += z * 2 ;
92149 }
93150 }
94151 else {
152+ if (src + 2 > end_of_buffer ) {
153+ return -1 ;
154+ }
95155 while (count -- ) {
96156 memcpy (dest , src , 2 );
97157 dest += z * 2 ;
@@ -141,7 +201,10 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state,
141201 return -1 ;
142202 }
143203 _imaging_seek_pyFd (state -> fd , SGI_HEADER_SIZE , SEEK_SET );
144- _imaging_read_pyFd (state -> fd , (char * )ptr , c -> bufsize );
204+ if (_imaging_read_pyFd (state -> fd , (char * )ptr , c -> bufsize ) != c -> bufsize ) {
205+ state -> errcode = IMAGING_CODEC_UNKNOWN ;
206+ return -1 ;
207+ }
145208
146209
147210 /* decoder initialization */
@@ -175,28 +238,28 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state,
175238 read4B (& c -> lengthtab [c -> tabindex ], & ptr [c -> bufindex ]);
176239 }
177240
178- state -> count += c -> tablen * sizeof (UINT32 ) * 2 ;
179-
180241 /* read compressed rows */
181242 for (c -> rowno = 0 ; c -> rowno < im -> ysize ; c -> rowno ++ , state -> y += state -> ystep )
182243 {
183244 for (c -> channo = 0 ; c -> channo < im -> bands ; c -> channo ++ )
184245 {
185246 c -> rleoffset = c -> starttab [c -> rowno + c -> channo * im -> ysize ];
186247 c -> rlelength = c -> lengthtab [c -> rowno + c -> channo * im -> ysize ];
187- c -> rleoffset -= SGI_HEADER_SIZE ;
188248
189- if (c -> rleoffset + c -> rlelength > c -> bufsize ) {
249+ // Check for underflow of rleoffset-SGI_HEADER_SIZE
250+ if (c -> rleoffset < SGI_HEADER_SIZE ) {
190251 state -> errcode = IMAGING_CODEC_OVERRUN ;
191252 goto sgi_finish_decode ;
192253 }
193254
255+ c -> rleoffset -= SGI_HEADER_SIZE ;
256+
194257 /* row decompression */
195258 if (c -> bpc == 1 ) {
196- status = expandrow (& state -> buffer [c -> channo ], & ptr [c -> rleoffset ], c -> rlelength , im -> bands , im -> xsize );
259+ status = expandrow (& state -> buffer [c -> channo ], & ptr [c -> rleoffset ], c -> rlelength , im -> bands , im -> xsize , & ptr [ c -> bufsize - 1 ] );
197260 }
198261 else {
199- status = expandrow2 (& state -> buffer [c -> channo * 2 ], & ptr [c -> rleoffset ], c -> rlelength , im -> bands , im -> xsize );
262+ status = expandrow2 (& state -> buffer [c -> channo * 2 ], & ptr [c -> rleoffset ], c -> rlelength , im -> bands , im -> xsize , & ptr [ c -> bufsize - 1 ] );
200263 }
201264 if (status == -1 ) {
202265 state -> errcode = IMAGING_CODEC_OVERRUN ;
@@ -205,16 +268,13 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state,
205268 goto sgi_finish_decode ;
206269 }
207270
208- state -> count += c -> rlelength ;
209271 }
210272
211273 /* store decompressed data in image */
212274 state -> shuffle ((UINT8 * )im -> image [state -> y ], state -> buffer , im -> xsize );
213275
214276 }
215277
216- c -> bufsize ++ ;
217-
218278sgi_finish_decode : ;
219279
220280 free (c -> starttab );
@@ -224,5 +284,5 @@ sgi_finish_decode: ;
224284 state -> errcode = err ;
225285 return -1 ;
226286 }
227- return state -> count - c -> bufsize ;
287+ return 0 ;
228288}
0 commit comments