Skip to content

Commit f0aab06

Browse files
authored
fix(targa): Protection against corrupt, mis-sized palette (#5165)
* Check that the palette isn't senselessly bigger than the bpp calls for. * Protection against integer overflow when addressing the palette. * Fix misunderstanding of the role of the palette "start" index. Pixel values are absolute, not relative to the start index. The bug would have produced incorrect images (or incorrectly reported image corruptions) if we ever came across an tga file with a non-zero palette start index. --------- Signed-off-by: Larry Gritz <lg@larrygritz.com>
1 parent 0e42093 commit f0aab06

5 files changed

Lines changed: 19 additions & 8 deletions

File tree

src/targa.imageio/targa_pvt.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ typedef struct {
3434
uint8_t idlen; ///< image comment length
3535
uint8_t cmap_type; ///< palette type
3636
uint8_t type; ///< image type (see tga_image_type)
37-
uint16_t cmap_first; ///< offset to first entry
38-
uint16_t cmap_length; ///<
39-
uint8_t cmap_size; ///< palette size
37+
uint16_t cmap_first; ///< offset to first stored color entry
38+
uint16_t cmap_length; ///< number of stored color map entries
39+
uint8_t cmap_size; ///< bits per palette entry: 15, 16, 24, or 32
4040
uint16_t x_origin; ///<
4141
uint16_t y_origin; ///<
4242
uint16_t width; ///< image width

src/targa.imageio/targainput.cpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,6 @@ TGAInput::open(const std::string& name, ImageSpec& newspec)
203203
errorfmt("Palette image with no palette");
204204
return false;
205205
}
206-
207206
if (is_palette()) {
208207
if (m_tga.type == TYPE_GRAY || m_tga.type == TYPE_GRAY_RLE) {
209208
// it should be an error for TYPE_RGB* as well, but apparently some
@@ -216,6 +215,12 @@ TGAInput::open(const std::string& name, ImageSpec& newspec)
216215
errorfmt("Illegal palette entry size: {} bits", m_tga.cmap_size);
217216
return false;
218217
}
218+
if (m_tga.cmap_first + m_tga.cmap_length > (uint64_t(1) << m_tga.bpp)) {
219+
errorfmt(
220+
"Too big a color palette ({}) for {} bpp, assume corruption",
221+
m_tga.cmap_first + m_tga.cmap_length, m_tga.bpp);
222+
return false;
223+
}
219224
}
220225

221226
m_alpha_type = TGA_ALPHA_NONE;
@@ -572,18 +577,20 @@ TGAInput::decode_pixel(unsigned char* in, unsigned char* out,
572577
unsigned char* palette, int bytespp, int palbytespp,
573578
size_t palette_alloc_size)
574579
{
575-
unsigned int k = 0;
580+
uint64_t k = 0;
576581
// I hate nested switches...
577582
switch (m_tga.type) {
578583
case TYPE_PALETTED:
579584
case TYPE_PALETTED_RLE:
580585
for (int i = 0; i < bytespp; ++i)
581586
k |= in[i] << (8 * i); // Assemble it in little endian order
582-
k = (m_tga.cmap_first + k) * palbytespp;
583-
if (k + palbytespp > palette_alloc_size) {
587+
if (k < m_tga.cmap_first || k >= m_tga.cmap_first + m_tga.cmap_length) {
584588
errorfmt("Corrupt palette index");
585589
return false;
586590
}
591+
// The palette indices stored in the file's pixels are absolute, so
592+
// subtract the start offset to correctly index from the palette.
593+
k = (k - m_tga.cmap_first) * uint64_t(palbytespp);
587594
switch (palbytespp) {
588595
case 2:
589596
// see the comment for 16bpp RGB below for an explanation of this

testsuite/targa/ref/out.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,14 +201,17 @@ Full command line was:
201201
oiiotool ERROR: read : "src/crash1707.tga": Invalid alpha type 138. Corrupted header?
202202
Full command line was:
203203
> oiiotool --oiioattrib try_all_readers 0 src/crash1707.tga -o crash1707.exr
204-
oiiotool ERROR: read : "src/crash1708.tga": Corrupt palette index
204+
oiiotool ERROR: read : "src/crash1708.tga": Too big a color palette (382) for 8 bpp, assume corruption
205205
Full command line was:
206206
> oiiotool --oiioattrib try_all_readers 0 src/crash1708.tga -o crash1708.exr
207207
oiiotool ERROR: read : "src/crash3952.tga": Uncompressed image size 15231.5 MB exceeds the 1024 MB limit.
208208
Image claimed to be 60927x65535, 4-channel uint8. Possible corrupt input?
209209
If this is a valid file, raise the OIIO attribute "limits:imagesize_MB".
210210
Full command line was:
211211
> oiiotool --oiioattrib limits:imagesize_MB 1024 --oiioattrib try_all_readers 0 src/crash3952.tga -o crash3952.exr
212+
oiiotool ERROR: read : "src/crash-20250423.tga": Corrupt palette index
213+
Full command line was:
214+
> oiiotool --oiioattrib try_all_readers 0 src/crash-20250423.tga -o out.null
212215
Reading src/1x1.tga
213216
src/1x1.tga : 1 x 1, 3 channel, uint2 targa
214217
SHA-1: DB9237F28F9622F7B7E73B783A8822B63BDB3708

testsuite/targa/run.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
command += oiiotool("--oiioattrib limits:imagesize_MB 1024 "
2828
"--oiioattrib try_all_readers 0 "
2929
"src/crash3952.tga -o crash3952.exr", failureok = True)
30+
command += oiiotool("--oiioattrib try_all_readers 0 src/crash-20250423.tga -o out.null", failureok=True);
3031

3132
# Test odds and ends, unusual files
3233
command += rw_command("src", "1x1.tga")
26 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)