1 |
luigiwalser |
1188362 |
From: Tobias Stoeckmann <tobias@stoeckmann.org> |
2 |
|
|
Date: Sun, 29 Oct 2017 15:19:41 +0100 |
3 |
|
|
Subject: Bug 739133 - (CVE-2017-17785) Heap overflow while parsing FLI files. |
4 |
|
|
Origin: https://git.gnome.org/browse/GIMP/commit/?id=1882bac996a20ab5c15c42b0c5e8f49033a1af54 |
5 |
|
|
Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2017-17785 |
6 |
|
|
Bug-Debian: https://bugs.debian.org/884836 |
7 |
|
|
Bug: https://bugzilla.gnome.org/show_bug.cgi?id=739133 |
8 |
|
|
|
9 |
|
|
It is possible to trigger a heap overflow while parsing FLI files. The |
10 |
|
|
RLE decoder is vulnerable to out of boundary writes due to lack of |
11 |
|
|
boundary checks. |
12 |
|
|
|
13 |
|
|
The variable "framebuf" points to a memory area which was allocated |
14 |
|
|
with fli_header->width * fli_header->height bytes. The RLE decoder |
15 |
|
|
therefore must never write beyond that limit. |
16 |
|
|
|
17 |
|
|
If an illegal frame is detected, the parser won't stop, which means |
18 |
|
|
that the next valid sequence is properly parsed again. This should |
19 |
|
|
allow GIMP to parse FLI files as good as possible even if they are |
20 |
|
|
broken by an attacker or by accident. |
21 |
|
|
|
22 |
|
|
While at it, I changed the variable xc to be of type size_t, because |
23 |
|
|
the multiplication of width and height could overflow a 16 bit type. |
24 |
|
|
|
25 |
|
|
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org> |
26 |
|
|
(cherry picked from commit edb251a7ef1602d20a5afcbf23f24afb163de63b) |
27 |
|
|
--- |
28 |
|
|
plug-ins/file-fli/fli.c | 50 ++++++++++++++++++++++++++++++++++--------------- |
29 |
|
|
1 file changed, 35 insertions(+), 15 deletions(-) |
30 |
|
|
|
31 |
|
|
diff --git a/plug-ins/file-fli/fli.c b/plug-ins/file-fli/fli.c |
32 |
|
|
index 313efeb977..ffb651e2af 100644 |
33 |
|
|
--- a/plug-ins/file-fli/fli.c |
34 |
|
|
+++ b/plug-ins/file-fli/fli.c |
35 |
|
|
@@ -25,6 +25,8 @@ |
36 |
|
|
|
37 |
|
|
#include "config.h" |
38 |
|
|
|
39 |
|
|
+#include <glib/gstdio.h> |
40 |
|
|
+ |
41 |
|
|
#include <string.h> |
42 |
|
|
#include <stdio.h> |
43 |
|
|
|
44 |
|
|
@@ -461,23 +463,27 @@ void fli_read_brun(FILE *f, s_fli_header *fli_header, unsigned char *framebuf) |
45 |
|
|
unsigned short yc; |
46 |
|
|
unsigned char *pos; |
47 |
|
|
for (yc=0; yc < fli_header->height; yc++) { |
48 |
|
|
- unsigned short xc, pc, pcnt; |
49 |
|
|
+ unsigned short pc, pcnt; |
50 |
|
|
+ size_t n, xc; |
51 |
|
|
pc=fli_read_char(f); |
52 |
|
|
xc=0; |
53 |
|
|
pos=framebuf+(fli_header->width * yc); |
54 |
|
|
+ n=(size_t)fli_header->width * (fli_header->height-yc); |
55 |
|
|
for (pcnt=pc; pcnt>0; pcnt--) { |
56 |
|
|
unsigned short ps; |
57 |
|
|
ps=fli_read_char(f); |
58 |
|
|
if (ps & 0x80) { |
59 |
|
|
unsigned short len; |
60 |
|
|
- for (len=-(signed char)ps; len>0; len--) { |
61 |
|
|
+ for (len=-(signed char)ps; len>0 && xc<n; len--) { |
62 |
|
|
pos[xc++]=fli_read_char(f); |
63 |
|
|
} |
64 |
|
|
} else { |
65 |
|
|
unsigned char val; |
66 |
|
|
+ size_t len; |
67 |
|
|
+ len=MIN(n-xc,ps); |
68 |
|
|
val=fli_read_char(f); |
69 |
|
|
- memset(&(pos[xc]), val, ps); |
70 |
|
|
- xc+=ps; |
71 |
|
|
+ memset(&(pos[xc]), val, len); |
72 |
|
|
+ xc+=len; |
73 |
|
|
} |
74 |
|
|
} |
75 |
|
|
} |
76 |
|
|
@@ -564,25 +570,34 @@ void fli_read_lc(FILE *f, s_fli_header *fli_header, unsigned char *old_framebuf, |
77 |
|
|
memcpy(framebuf, old_framebuf, fli_header->width * fli_header->height); |
78 |
|
|
firstline = fli_read_short(f); |
79 |
|
|
numline = fli_read_short(f); |
80 |
|
|
+ if (numline > fli_header->height || fli_header->height-numline < firstline) |
81 |
|
|
+ return; |
82 |
|
|
+ |
83 |
|
|
for (yc=0; yc < numline; yc++) { |
84 |
|
|
- unsigned short xc, pc, pcnt; |
85 |
|
|
+ unsigned short pc, pcnt; |
86 |
|
|
+ size_t n, xc; |
87 |
|
|
pc=fli_read_char(f); |
88 |
|
|
xc=0; |
89 |
|
|
pos=framebuf+(fli_header->width * (firstline+yc)); |
90 |
|
|
+ n=(size_t)fli_header->width * (fli_header->height-firstline-yc); |
91 |
|
|
for (pcnt=pc; pcnt>0; pcnt--) { |
92 |
|
|
unsigned short ps,skip; |
93 |
|
|
skip=fli_read_char(f); |
94 |
|
|
ps=fli_read_char(f); |
95 |
|
|
- xc+=skip; |
96 |
|
|
+ xc+=MIN(n-xc,skip); |
97 |
|
|
if (ps & 0x80) { |
98 |
|
|
unsigned char val; |
99 |
|
|
+ size_t len; |
100 |
|
|
ps=-(signed char)ps; |
101 |
|
|
val=fli_read_char(f); |
102 |
|
|
- memset(&(pos[xc]), val, ps); |
103 |
|
|
- xc+=ps; |
104 |
|
|
+ len=MIN(n-xc,ps); |
105 |
|
|
+ memset(&(pos[xc]), val, len); |
106 |
|
|
+ xc+=len; |
107 |
|
|
} else { |
108 |
|
|
- fread(&(pos[xc]), ps, 1, f); |
109 |
|
|
- xc+=ps; |
110 |
|
|
+ size_t len; |
111 |
|
|
+ len=MIN(n-xc,ps); |
112 |
|
|
+ fread(&(pos[xc]), len, 1, f); |
113 |
|
|
+ xc+=len; |
114 |
|
|
} |
115 |
|
|
} |
116 |
|
|
} |
117 |
|
|
@@ -689,7 +704,8 @@ void fli_read_lc_2(FILE *f, s_fli_header *fli_header, unsigned char *old_framebu |
118 |
|
|
yc=0; |
119 |
|
|
numline = fli_read_short(f); |
120 |
|
|
for (lc=0; lc < numline; lc++) { |
121 |
|
|
- unsigned short xc, pc, pcnt, lpf, lpn; |
122 |
|
|
+ unsigned short pc, pcnt, lpf, lpn; |
123 |
|
|
+ size_t n, xc; |
124 |
|
|
pc=fli_read_short(f); |
125 |
|
|
lpf=0; lpn=0; |
126 |
|
|
while (pc & 0x8000) { |
127 |
|
|
@@ -700,26 +716,30 @@ void fli_read_lc_2(FILE *f, s_fli_header *fli_header, unsigned char *old_framebu |
128 |
|
|
} |
129 |
|
|
pc=fli_read_short(f); |
130 |
|
|
} |
131 |
|
|
+ yc=MIN(yc, fli_header->height); |
132 |
|
|
xc=0; |
133 |
|
|
pos=framebuf+(fli_header->width * yc); |
134 |
|
|
+ n=(size_t)fli_header->width * (fli_header->height-yc); |
135 |
|
|
for (pcnt=pc; pcnt>0; pcnt--) { |
136 |
|
|
unsigned short ps,skip; |
137 |
|
|
skip=fli_read_char(f); |
138 |
|
|
ps=fli_read_char(f); |
139 |
|
|
- xc+=skip; |
140 |
|
|
+ xc+=MIN(n-xc,skip); |
141 |
|
|
if (ps & 0x80) { |
142 |
|
|
unsigned char v1,v2; |
143 |
|
|
ps=-(signed char)ps; |
144 |
|
|
v1=fli_read_char(f); |
145 |
|
|
v2=fli_read_char(f); |
146 |
|
|
- while (ps>0) { |
147 |
|
|
+ while (ps>0 && xc+1<n) { |
148 |
|
|
pos[xc++]=v1; |
149 |
|
|
pos[xc++]=v2; |
150 |
|
|
ps--; |
151 |
|
|
} |
152 |
|
|
} else { |
153 |
|
|
- fread(&(pos[xc]), ps, 2, f); |
154 |
|
|
- xc+=ps << 1; |
155 |
|
|
+ size_t len; |
156 |
|
|
+ len=MIN((n-xc)/2,ps); |
157 |
|
|
+ fread(&(pos[xc]), len, 2, f); |
158 |
|
|
+ xc+=len << 1; |
159 |
|
|
} |
160 |
|
|
} |
161 |
|
|
if (lpf) pos[xc]=lpn; |
162 |
|
|
-- |
163 |
|
|
2.15.1 |
164 |
|
|
|