1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
|
commit 8d309dd0385fdd298520b69148542375f56ef977
Author: Andrzej Hunt <andrzej@ahunt.org>
Date: Tue Jul 16 18:30:21 2024 +0200
tga: always convert colour-mapped images to RGBA if image claims to contain alpha
If the colourmap contains more than 256 items AND has alpha, it should always
be promoted to RGBA. Therefore we move the "if (info->alphaBits)" check into
the first if clause, to avoid accidentally demoting to RGB in this scenario.
Other parts of the tga parser assume that the destination array is RGBA
when alphaBits is not zero. For example, upsample() will always write 4 bytes
per pixel when alpha is set - (even if we only allocated 3 because we thought
we should use RGB). Erronously allocating only 3 bytes makes it easy to induce
a heap-buffer-overflow write, see ASAN output below. (apply_colormap makes the
same assumption and would probably do the same thing, but upsample is the
first location that we'd hit this issue.)
ERROR: AddressSanitizer: heap-buffer-overflow on address 0x61700002ae00 at pc 0x000000563d97 bp 0x7ffde8677890 sp 0x7ffde8677888
WRITE of size 1 at 0x61700002ae00 thread T0
#0 0x563d96 in upsample /home/ahunt/git/gimp/plug-ins/common/file-tga.c:830:15
#1 0x560b59 in ReadImage /home/ahunt/git/gimp/plug-ins/common/file-tga.c
#2 0x55f4ee in load_image /home/ahunt/git/gimp/plug-ins/common/file-tga.c:647:11
#3 0x5652ab in LLVMFuzzerTestOneInput /home/ahunt/git/gimp/plug-ins/common/file-tga_fuzzer.c:69:17
#4 0x461624 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:599:15
#5 0x460b2a in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool, bool*) /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:505:3
#6 0x462847 in fuzzer::Fuzzer::MutateAndTestOne() /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:745:19
#7 0x4633d5 in fuzzer::Fuzzer::Loop(std::__Fuzzer::vector<fuzzer::SizedFile, fuzzer::fuzzer_allocator<fuzzer::SizedFile> >&) /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:883:5
#8 0x451686 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:906:6
#9 0x47b662 in main /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
#10 0x7fd894a94349 in __libc_start_main (/lib64/libc.so.6+0x24349)
#11 0x424a39 in _start /home/abuild/rpmbuild/BUILD/glibc-2.26/csu/../sysdeps/x86_64/start.S:120
0x61700002ae00 is located 0 bytes to the right of 768-byte region [0x61700002ab00,0x61700002ae00)
allocated by thread T0 here:
#0 0x52ca8d in malloc /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/asan/asan_malloc_linux.cpp:145:3
#1 0x7fd895b14cf2 in g_malloc /home/ahunt/git/glib/_build/../glib/gmem.c:106:13
#2 0x55fce9 in ReadImage /home/ahunt/git/gimp/plug-ins/common/file-tga.c:1039:26
#3 0x55f4ee in load_image /home/ahunt/git/gimp/plug-ins/common/file-tga.c:647:11
#4 0x5652ab in LLVMFuzzerTestOneInput /home/ahunt/git/gimp/plug-ins/common/file-tga_fuzzer.c:69:17
#5 0x461624 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:599:15
#6 0x460b2a in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool, bool*) /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:505:3
#7 0x462847 in fuzzer::Fuzzer::MutateAndTestOne() /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:745:19
#8 0x4633d5 in fuzzer::Fuzzer::Loop(std::__Fuzzer::vector<fuzzer::SizedFile, fuzzer::fuzzer_allocator<fuzzer::SizedFile> >&) /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:883:5
#9 0x451686 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:906:6
#10 0x47b662 in main /home/abuild/rpmbuild/BUILD/llvm-12.0.0.src/build/../projects/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
#11 0x7fd894a94349 in __libc_start_main (/lib64/libc.so.6+0x24349)
SUMMARY: AddressSanitizer: heap-buffer-overflow /home/ahunt/git/gimp/plug-ins/common/file-tga.c:830:15 in upsample
Shadow bytes around the buggy address:
0x0c2e7fffd570: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c2e7fffd580: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c2e7fffd590: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c2e7fffd5a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c2e7fffd5b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c2e7fffd5c0:[fa]fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c2e7fffd5d0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c2e7fffd5e0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c2e7fffd5f0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c2e7fffd600: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c2e7fffd610: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Shadow gap: cc
==12179==ABORTING
( crash-f65fd5404bff32c1d9d10ee049d9c98d02bbbdc2 )
(cherry picked from commit 49755f085a6fcc9c692b14e67856e91a79245688)
diff --git a/plug-ins/common/file-tga.c b/plug-ins/common/file-tga.c
index e833c60cd9..d70991020a 100644
--- a/plug-ins/common/file-tga.c
+++ b/plug-ins/common/file-tga.c
@@ -1009,9 +1009,9 @@ ReadImage (FILE *fp,
cmap_bytes = (info->colorMapSize + 7 ) / 8;
tga_cmap = g_new (guchar, info->colorMapLength * cmap_bytes);
- if (info->colorMapSize > 24)
+ if (info->colorMapSize > 24 || info->alphaBits > 0)
{
- /* indexed + full alpha => promoted to RGBA */
+ /* indexed + full alpha, or alpha exists => promoted to RGBA */
itype = GIMP_RGB;
dtype = GIMP_RGBA_IMAGE;
convert_cmap = g_new (guchar, info->colorMapLength * 4);
@@ -1023,13 +1023,6 @@ ReadImage (FILE *fp,
dtype = GIMP_RGB_IMAGE;
convert_cmap = g_new (guchar, info->colorMapLength * 3);
}
- else if (info->alphaBits > 0)
- {
- /* if alpha exists here, promote to RGB */
- itype = GIMP_RGB;
- dtype = GIMP_RGBA_IMAGE;
- convert_cmap = g_new (guchar, info->colorMapLength * 4);
- }
else
{
itype = GIMP_INDEXED;
|