@@ -25,13 +25,59 @@ static void read4B(UINT32* dest, UINT8* buf)
25
25
* dest = (UINT32 )((buf [0 ] << 24 ) | (buf [1 ] << 16 ) | (buf [2 ] << 8 ) | buf [3 ]);
26
26
}
27
27
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 )
29
64
{
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
+
30
73
UINT8 pixel , count ;
31
74
int x = 0 ;
32
75
33
76
for (;n > 0 ; n -- )
34
77
{
78
+ if (src > end_of_buffer ) {
79
+ return -1 ;
80
+ }
35
81
pixel = * src ++ ;
36
82
if (n == 1 && pixel != 0 ) {
37
83
return n ;
@@ -45,13 +91,19 @@ static int expandrow(UINT8* dest, UINT8* src, int n, int z, int xsize)
45
91
}
46
92
x += count ;
47
93
if (pixel & RLE_COPY_FLAG ) {
94
+ if (src + count > end_of_buffer ) {
95
+ return -1 ;
96
+ }
48
97
while (count -- ) {
49
98
* dest = * src ++ ;
50
99
dest += z ;
51
100
}
52
101
53
102
}
54
103
else {
104
+ if (src > end_of_buffer ) {
105
+ return -1 ;
106
+ }
55
107
pixel = * src ++ ;
56
108
while (count -- ) {
57
109
* dest = pixel ;
@@ -63,14 +115,16 @@ static int expandrow(UINT8* dest, UINT8* src, int n, int z, int xsize)
63
115
return 0 ;
64
116
}
65
117
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 )
67
119
{
68
120
UINT8 pixel , count ;
69
-
70
121
int x = 0 ;
71
122
72
123
for (;n > 0 ; n -- )
73
124
{
125
+ if (src + 1 > end_of_buffer ) {
126
+ return -1 ;
127
+ }
74
128
pixel = src [1 ];
75
129
src += 2 ;
76
130
if (n == 1 && pixel != 0 ) {
@@ -85,13 +139,19 @@ static int expandrow2(UINT8* dest, const UINT8* src, int n, int z, int xsize)
85
139
}
86
140
x += count ;
87
141
if (pixel & RLE_COPY_FLAG ) {
142
+ if (src + 2 * count > end_of_buffer ) {
143
+ return -1 ;
144
+ }
88
145
while (count -- ) {
89
146
memcpy (dest , src , 2 );
90
147
src += 2 ;
91
148
dest += z * 2 ;
92
149
}
93
150
}
94
151
else {
152
+ if (src + 2 > end_of_buffer ) {
153
+ return -1 ;
154
+ }
95
155
while (count -- ) {
96
156
memcpy (dest , src , 2 );
97
157
dest += z * 2 ;
@@ -141,7 +201,10 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state,
141
201
return -1 ;
142
202
}
143
203
_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
+ }
145
208
146
209
147
210
/* decoder initialization */
@@ -175,28 +238,28 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state,
175
238
read4B (& c -> lengthtab [c -> tabindex ], & ptr [c -> bufindex ]);
176
239
}
177
240
178
- state -> count += c -> tablen * sizeof (UINT32 ) * 2 ;
179
-
180
241
/* read compressed rows */
181
242
for (c -> rowno = 0 ; c -> rowno < im -> ysize ; c -> rowno ++ , state -> y += state -> ystep )
182
243
{
183
244
for (c -> channo = 0 ; c -> channo < im -> bands ; c -> channo ++ )
184
245
{
185
246
c -> rleoffset = c -> starttab [c -> rowno + c -> channo * im -> ysize ];
186
247
c -> rlelength = c -> lengthtab [c -> rowno + c -> channo * im -> ysize ];
187
- c -> rleoffset -= SGI_HEADER_SIZE ;
188
248
189
- if (c -> rleoffset + c -> rlelength > c -> bufsize ) {
249
+ // Check for underflow of rleoffset-SGI_HEADER_SIZE
250
+ if (c -> rleoffset < SGI_HEADER_SIZE ) {
190
251
state -> errcode = IMAGING_CODEC_OVERRUN ;
191
252
goto sgi_finish_decode ;
192
253
}
193
254
255
+ c -> rleoffset -= SGI_HEADER_SIZE ;
256
+
194
257
/* row decompression */
195
258
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 ] );
197
260
}
198
261
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 ] );
200
263
}
201
264
if (status == -1 ) {
202
265
state -> errcode = IMAGING_CODEC_OVERRUN ;
@@ -205,16 +268,13 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state,
205
268
goto sgi_finish_decode ;
206
269
}
207
270
208
- state -> count += c -> rlelength ;
209
271
}
210
272
211
273
/* store decompressed data in image */
212
274
state -> shuffle ((UINT8 * )im -> image [state -> y ], state -> buffer , im -> xsize );
213
275
214
276
}
215
277
216
- c -> bufsize ++ ;
217
-
218
278
sgi_finish_decode : ;
219
279
220
280
free (c -> starttab );
@@ -224,5 +284,5 @@ sgi_finish_decode: ;
224
284
state -> errcode = err ;
225
285
return -1 ;
226
286
}
227
- return state -> count - c -> bufsize ;
287
+ return 0 ;
228
288
}
0 commit comments