Skip to content

Commit 2c712d4

Browse files
committed
Prevent RLE data in corrupt .tga from overflowing the buffer
Also masked out the 1-bit A value from a 15-bit image; this could cause the bounds of _al_rgb_scale_5[] to be exceeded.
1 parent 477bf8b commit 2c712d4

File tree

1 file changed

+96
-20
lines changed

1 file changed

+96
-20
lines changed

addons/image/tga.c

Lines changed: 96 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
* By Tim Gunn.
1414
*
1515
* RLE support added by Michal Mertl and Salvador Eduardo Tropea.
16-
*
16+
*
1717
* Palette reading improved by Peter Wang.
1818
*
1919
* Big-endian support added by Eric Botcazou.
@@ -34,6 +34,7 @@ ALLEGRO_DEBUG_CHANNEL("image")
3434

3535
/* raw_tga_read8:
3636
* Helper for reading 256-color raw data from TGA files.
37+
* Returns pointer past the end.
3738
*/
3839
static INLINE unsigned char *raw_tga_read8(unsigned char *b, int w, ALLEGRO_FILE *f)
3940
{
@@ -44,8 +45,9 @@ static INLINE unsigned char *raw_tga_read8(unsigned char *b, int w, ALLEGRO_FILE
4445

4546
/* rle_tga_read8:
4647
* Helper for reading 256-color RLE data from TGA files.
48+
* Returns pointer past the end or NULL for error.
4749
*/
48-
static void rle_tga_read8(unsigned char *b, int w, ALLEGRO_FILE *f)
50+
static unsigned char *rle_tga_read8(unsigned char *b, int w, ALLEGRO_FILE *f)
4951
{
5052
int value, count, c = 0;
5153

@@ -55,6 +57,10 @@ static void rle_tga_read8(unsigned char *b, int w, ALLEGRO_FILE *f)
5557
/* run-length packet */
5658
count = (count & 0x7F) + 1;
5759
c += count;
60+
if (c > w) {
61+
/* Stepped past the end of the line, error */
62+
return NULL;
63+
}
5864
value = al_fgetc(f);
5965
while (count--)
6066
*b++ = value;
@@ -63,9 +69,14 @@ static void rle_tga_read8(unsigned char *b, int w, ALLEGRO_FILE *f)
6369
/* raw packet */
6470
count++;
6571
c += count;
72+
if (c > w) {
73+
/* Stepped past the end of the line, error */
74+
return NULL;
75+
}
6676
b = raw_tga_read8(b, count, f);
6777
}
6878
} while (c < w);
79+
return b;
6980
}
7081

7182

@@ -82,6 +93,7 @@ static INLINE int32_t single_tga_read32(ALLEGRO_FILE *f)
8293

8394
/* raw_tga_read32:
8495
* Helper for reading 32-bit raw data from TGA files.
96+
* Returns pointer past the end.
8597
*/
8698
static unsigned int *raw_tga_read32(unsigned int *b, int w, ALLEGRO_FILE *f)
8799
{
@@ -95,8 +107,9 @@ static unsigned int *raw_tga_read32(unsigned int *b, int w, ALLEGRO_FILE *f)
95107

96108
/* rle_tga_read32:
97109
* Helper for reading 32-bit RLE data from TGA files.
110+
* Returns pointer past the end or NULL for error.
98111
*/
99-
static void rle_tga_read32(unsigned int *b, int w, ALLEGRO_FILE *f)
112+
static unsigned int *rle_tga_read32(unsigned int *b, int w, ALLEGRO_FILE *f)
100113
{
101114
int color, count, c = 0;
102115

@@ -106,6 +119,10 @@ static void rle_tga_read32(unsigned int *b, int w, ALLEGRO_FILE *f)
106119
/* run-length packet */
107120
count = (count & 0x7F) + 1;
108121
c += count;
122+
if (c > w) {
123+
/* Stepped past the end of the line, error */
124+
return NULL;
125+
}
109126
color = single_tga_read32(f);
110127
while (count--)
111128
*b++ = color;
@@ -114,9 +131,14 @@ static void rle_tga_read32(unsigned int *b, int w, ALLEGRO_FILE *f)
114131
/* raw packet */
115132
count++;
116133
c += count;
134+
if (c > w) {
135+
/* Stepped past the end of the line, error */
136+
return NULL;
137+
}
117138
b = raw_tga_read32(b, count, f);
118139
}
119140
} while (c < w);
141+
return b;
120142
}
121143

122144

@@ -132,6 +154,7 @@ static INLINE void single_tga_read24(ALLEGRO_FILE *f, unsigned char color[3])
132154

133155
/* raw_tga_read24:
134156
* Helper for reading 24-bit raw data from TGA files.
157+
* Returns pointer past the end.
135158
*/
136159
static unsigned char *raw_tga_read24(unsigned char *b, int w, ALLEGRO_FILE *f)
137160
{
@@ -147,8 +170,9 @@ static unsigned char *raw_tga_read24(unsigned char *b, int w, ALLEGRO_FILE *f)
147170

148171
/* rle_tga_read24:
149172
* Helper for reading 24-bit RLE data from TGA files.
173+
* Returns pointer past the end or NULL for error.
150174
*/
151-
static void rle_tga_read24(unsigned char *b, int w, ALLEGRO_FILE *f)
175+
static unsigned char *rle_tga_read24(unsigned char *b, int w, ALLEGRO_FILE *f)
152176
{
153177
int count, c = 0;
154178
unsigned char color[3];
@@ -159,6 +183,10 @@ static void rle_tga_read24(unsigned char *b, int w, ALLEGRO_FILE *f)
159183
/* run-length packet */
160184
count = (count & 0x7F) + 1;
161185
c += count;
186+
if (c > w) {
187+
/* Stepped past the end of the line, error */
188+
return NULL;
189+
}
162190
single_tga_read24(f, color);
163191
while (count--) {
164192
b[0] = color[0];
@@ -171,9 +199,14 @@ static void rle_tga_read24(unsigned char *b, int w, ALLEGRO_FILE *f)
171199
/* raw packet */
172200
count++;
173201
c += count;
202+
if (c > w) {
203+
/* Stepped past the end of the line, error */
204+
return NULL;
205+
}
174206
b = raw_tga_read24(b, count, f);
175207
}
176208
} while (c < w);
209+
return b;
177210
}
178211

179212

@@ -190,6 +223,7 @@ static INLINE int single_tga_read16(ALLEGRO_FILE *f)
190223

191224
/* raw_tga_read16:
192225
* Helper for reading 16-bit raw data from TGA files.
226+
* Returns pointer past the end.
193227
*/
194228
static unsigned short *raw_tga_read16(unsigned short *b, int w, ALLEGRO_FILE *f)
195229
{
@@ -203,8 +237,9 @@ static unsigned short *raw_tga_read16(unsigned short *b, int w, ALLEGRO_FILE *f)
203237

204238
/* rle_tga_read16:
205239
* Helper for reading 16-bit RLE data from TGA files.
240+
* Returns pointer past the end or NULL for error.
206241
*/
207-
static void rle_tga_read16(unsigned short *b, int w, ALLEGRO_FILE *f)
242+
static unsigned short *rle_tga_read16(unsigned short *b, int w, ALLEGRO_FILE *f)
208243
{
209244
int color, count, c = 0;
210245

@@ -214,6 +249,10 @@ static void rle_tga_read16(unsigned short *b, int w, ALLEGRO_FILE *f)
214249
/* run-length packet */
215250
count = (count & 0x7F) + 1;
216251
c += count;
252+
if (c > w) {
253+
/* Stepped past the end of the line, error */
254+
return NULL;
255+
}
217256
color = single_tga_read16(f);
218257
while (count--)
219258
*b++ = color;
@@ -222,9 +261,14 @@ static void rle_tga_read16(unsigned short *b, int w, ALLEGRO_FILE *f)
222261
/* raw packet */
223262
count++;
224263
c += count;
264+
if (c > w) {
265+
/* Stepped past the end of the line, error */
266+
return NULL;
267+
}
225268
b = raw_tga_read16(b, count, f);
226269
}
227270
} while (c < w);
271+
return b;
228272
}
229273

230274

@@ -388,12 +432,20 @@ ALLEGRO_BITMAP *_al_load_tga_f(ALLEGRO_FILE *f, int flags)
388432
switch (image_type) {
389433

390434
case 1:
391-
case 3:
435+
case 3: {
436+
unsigned char *ptr;
392437
if (compressed)
393-
rle_tga_read8(buf, image_width, f);
438+
ptr = rle_tga_read8(buf, image_width, f);
394439
else
395-
raw_tga_read8(buf, image_width, f);
396-
440+
ptr = raw_tga_read8(buf, image_width, f);
441+
if (!ptr) {
442+
al_free(buf);
443+
al_unlock_bitmap(bmp);
444+
al_destroy_bitmap(bmp);
445+
ALLEGRO_ERROR("Invalid image data.\n");
446+
return NULL;
447+
}
448+
}
397449
for (i = 0; i < image_width; i++) {
398450
int true_x = (left_to_right) ? i : (image_width - 1 - i);
399451
int pix = buf[i];
@@ -410,11 +462,18 @@ ALLEGRO_BITMAP *_al_load_tga_f(ALLEGRO_FILE *f, int flags)
410462

411463
case 2:
412464
if (bpp == 32) {
465+
unsigned int *ptr;
413466
if (compressed)
414-
rle_tga_read32((unsigned int *)buf, image_width, f);
467+
ptr = rle_tga_read32((unsigned int *)buf, image_width, f);
415468
else
416-
raw_tga_read32((unsigned int *)buf, image_width, f);
417-
469+
ptr = raw_tga_read32((unsigned int *)buf, image_width, f);
470+
if (!ptr) {
471+
al_free(buf);
472+
al_unlock_bitmap(bmp);
473+
al_destroy_bitmap(bmp);
474+
ALLEGRO_ERROR("Invalid image data.\n");
475+
return NULL;
476+
}
418477
for (i = 0; i < image_width; i++) {
419478
int true_x = (left_to_right) ? i : (image_width - 1 - i);
420479
unsigned char *dest = (unsigned char *)lr->data +
@@ -425,12 +484,12 @@ ALLEGRO_BITMAP *_al_load_tga_f(ALLEGRO_FILE *f, int flags)
425484
int r = buf[i * 4 + 1];
426485
int g = buf[i * 4 + 2];
427486
int b = buf[i * 4 + 3];
428-
#else
487+
#else
429488
int b = buf[i * 4 + 0];
430489
int g = buf[i * 4 + 1];
431490
int r = buf[i * 4 + 2];
432491
int a = buf[i * 4 + 3];
433-
#endif
492+
#endif
434493
if (premul) {
435494
r = r * a / 255;
436495
g = g * a / 255;
@@ -444,10 +503,18 @@ ALLEGRO_BITMAP *_al_load_tga_f(ALLEGRO_FILE *f, int flags)
444503
}
445504
}
446505
else if (bpp == 24) {
506+
unsigned char *ptr;
447507
if (compressed)
448-
rle_tga_read24(buf, image_width, f);
508+
ptr = rle_tga_read24(buf, image_width, f);
449509
else
450-
raw_tga_read24(buf, image_width, f);
510+
ptr = raw_tga_read24(buf, image_width, f);
511+
if (!ptr) {
512+
al_free(buf);
513+
al_unlock_bitmap(bmp);
514+
al_destroy_bitmap(bmp);
515+
ALLEGRO_ERROR("Invalid image data.\n");
516+
return NULL;
517+
}
451518
for (i = 0; i < image_width; i++) {
452519
int true_x = (left_to_right) ? i : (image_width - 1 - i);
453520
int b = buf[i * 3 + 0];
@@ -463,14 +530,23 @@ ALLEGRO_BITMAP *_al_load_tga_f(ALLEGRO_FILE *f, int flags)
463530
}
464531
}
465532
else {
533+
unsigned short *ptr;
466534
if (compressed)
467-
rle_tga_read16((unsigned short *)buf, image_width, f);
535+
ptr = rle_tga_read16((unsigned short *)buf, image_width, f);
468536
else
469-
raw_tga_read16((unsigned short *)buf, image_width, f);
537+
ptr = raw_tga_read16((unsigned short *)buf, image_width, f);
538+
if (!ptr) {
539+
al_free(buf);
540+
al_unlock_bitmap(bmp);
541+
al_destroy_bitmap(bmp);
542+
ALLEGRO_ERROR("Invalid image data.\n");
543+
return NULL;
544+
}
470545
for (i = 0; i < image_width; i++) {
471546
int true_x = (left_to_right) ? i : (image_width - 1 - i);
472547
int pix = *((unsigned short *)(buf + i * 2));
473-
int r = _al_rgb_scale_5[(pix >> 10)];
548+
/* TODO - do something with the 1-bit A value (alpha?) */
549+
int r = _al_rgb_scale_5[(pix >> 10) & 0x1F];
474550
int g = _al_rgb_scale_5[(pix >> 5) & 0x1F];
475551
int b = _al_rgb_scale_5[(pix & 0x1F)];
476552

@@ -597,7 +673,7 @@ bool _al_identify_tga(ALLEGRO_FILE *f)
597673
uint8_t x[4];
598674
al_fgetc(f); // skip id length
599675
al_fread(f, x, 4);
600-
676+
601677
if (x[0] > 1) // TGA colormap must be 0 or 1
602678
return false;
603679
if ((x[1] & 0xf7) == 0) // type must be 1, 2, 3, 9, 10 or 11

0 commit comments

Comments
 (0)