aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo <thinkabit.ukim@gmail.com>2020-03-27 06:51:59 -0300
committerLeo <thinkabit.ukim@gmail.com>2020-03-27 06:55:38 -0300
commit3f5cd043a943818e7829508f1e45dc772c5d273a (patch)
treeb3bd98ab1d00df86811aa46e7ce47183267fcc3b
parentf9323c22d56bf68412789c47e0ba4b429feeea7f (diff)
downloadalpine_aports-3f5cd043a943818e7829508f1e45dc772c5d273a.tar.bz2
alpine_aports-3f5cd043a943818e7829508f1e45dc772c5d273a.tar.xz
alpine_aports-3f5cd043a943818e7829508f1e45dc772c5d273a.zip
main/unzip: actually fix CVE-2019-13232
use patch from Fedora
-rw-r--r--main/unzip/APKBUILD8
-rw-r--r--main/unzip/CVE-2019-13232.patch487
2 files changed, 491 insertions, 4 deletions
diff --git a/main/unzip/APKBUILD b/main/unzip/APKBUILD
index a4be378d78..3dc0ea49f3 100644
--- a/main/unzip/APKBUILD
+++ b/main/unzip/APKBUILD
@@ -3,7 +3,7 @@
3pkgname=unzip 3pkgname=unzip
4pkgver=6.0 4pkgver=6.0
5_pkgver=${pkgver//./} 5_pkgver=${pkgver//./}
6pkgrel=5 6pkgrel=6
7pkgdesc="Extract PKZIP-compatible .zip files" 7pkgdesc="Extract PKZIP-compatible .zip files"
8url="http://www.info-zip.org/UnZip.html" 8url="http://www.info-zip.org/UnZip.html"
9arch="all" 9arch="all"
@@ -22,12 +22,12 @@ source="https://dev.alpinelinux.org/archive/unzip/unzip$_pkgver.tgz
22 CVE-2016-9844.patch 22 CVE-2016-9844.patch
23 CVE-2018-1000035.patch 23 CVE-2018-1000035.patch
24 fix-CVE-2014-8139.patch 24 fix-CVE-2014-8139.patch
25 CVE-2019-13232.patch::https://github.com/madler/unzip/commit/47b3ceae397d21bf822bc2ac73052a4b1daf8e1c.patch 25 CVE-2019-13232.patch
26 " 26 "
27builddir="$srcdir/$pkgname$_pkgver" 27builddir="$srcdir/$pkgname$_pkgver"
28 28
29# secfixes: 29# secfixes:
30# 6.0-r5: 30# 6.0-r6:
31# - CVE-2019-13232 31# - CVE-2019-13232
32# 6.0-r3: 32# 6.0-r3:
33# - CVE-2014-8139 33# - CVE-2014-8139
@@ -67,4 +67,4 @@ b1e3fac6a787828efaaef8ec7cc52e1573aea27a6f29830af37ec4ba8bcd2a6488c953ab10eee056
678c4a4313072ff0d87eadb0f5472eb48f2802b835dd282305811a96de87a41fed48be60fbdd434e6b6359418f0559f7793deaa1d68161a0c0ead9f8574bb9f14c CVE-2016-9844.patch 678c4a4313072ff0d87eadb0f5472eb48f2802b835dd282305811a96de87a41fed48be60fbdd434e6b6359418f0559f7793deaa1d68161a0c0ead9f8574bb9f14c CVE-2016-9844.patch
686f757385a23fe6a034f676df6bf233243afa8743761e3d715e532d066fcd7dc8f8dcd6192be693258f3855837e5534490784378768abe7ce710fb869258d49b7 CVE-2018-1000035.patch 686f757385a23fe6a034f676df6bf233243afa8743761e3d715e532d066fcd7dc8f8dcd6192be693258f3855837e5534490784378768abe7ce710fb869258d49b7 CVE-2018-1000035.patch
6913f9c54fcdde478c4afe391c8e7ef9c31b03228aaace5da38382612951cbfd60710fd3d931569297953be32b2c5906715aed4b1c05e28cc8fccbb27f38b57550 fix-CVE-2014-8139.patch 6913f9c54fcdde478c4afe391c8e7ef9c31b03228aaace5da38382612951cbfd60710fd3d931569297953be32b2c5906715aed4b1c05e28cc8fccbb27f38b57550 fix-CVE-2014-8139.patch
70aa8dcf335c6f48c3d7f0ab6aa220b838f2a5be54ac3b8dea4729d2acfed180e51e6ca1299d96439d99bae5a0caba5e3df73558ca2ea7099d7275bfc1f0fc8c09 CVE-2019-13232.patch" 70d11758bda3b022f1adb4031bfbc770c6391e3470f3126ec5a4d3d2800d5452245eee26256f539d60adee33f01ba8ba8345299736cd9568da1242f6f739e4a598 CVE-2019-13232.patch"
diff --git a/main/unzip/CVE-2019-13232.patch b/main/unzip/CVE-2019-13232.patch
new file mode 100644
index 0000000000..01e343a356
--- /dev/null
+++ b/main/unzip/CVE-2019-13232.patch
@@ -0,0 +1,487 @@
1From 47b3ceae397d21bf822bc2ac73052a4b1daf8e1c Mon Sep 17 00:00:00 2001
2From: Mark Adler <madler@alumni.caltech.edu>
3Date: Tue, 11 Jun 2019 22:01:18 -0700
4Subject: [PATCH] Detect and reject a zip bomb using overlapped entries.
5
6This detects an invalid zip file that has at least one entry that
7overlaps with another entry or with the central directory to the
8end of the file. A Fifield zip bomb uses overlapped local entries
9to vastly increase the potential inflation ratio. Such an invalid
10zip file is rejected.
11
12See https://www.bamsoftware.com/hacks/zipbomb/ for David Fifield's
13analysis, construction, and examples of such zip bombs.
14
15The detection maintains a list of covered spans of the zip files
16so far, where the central directory to the end of the file and any
17bytes preceding the first entry at zip file offset zero are
18considered covered initially. Then as each entry is decompressed
19or tested, it is considered covered. When a new entry is about to
20be processed, its initial offset is checked to see if it is
21contained by a covered span. If so, the zip file is rejected as
22invalid.
23
24This commit depends on a preceding commit: "Fix bug in
25undefer_input() that misplaced the input state."
26---
27 extract.c | 190 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
28 globals.c | 1 +
29 globals.h | 3 +
30 process.c | 11 ++++
31 unzip.h | 1 +
32 5 files changed, 205 insertions(+), 1 deletion(-)
33
34diff --git a/extract.c b/extract.c
35index 1acd769..0973a33 100644
36--- a/extract.c
37+++ b/extract.c
38@@ -319,6 +319,125 @@ static ZCONST char Far UnsupportedExtraField[] =
39 "\nerror: unsupported extra-field compression type (%u)--skipping\n";
40 static ZCONST char Far BadExtraFieldCRC[] =
41 "error [%s]: bad extra-field CRC %08lx (should be %08lx)\n";
42+static ZCONST char Far NotEnoughMemCover[] =
43+ "error: not enough memory for bomb detection\n";
44+static ZCONST char Far OverlappedComponents[] =
45+ "error: invalid zip file with overlapped components (possible zip bomb)\n";
46+
47+
48+
49+
50+
51+/* A growable list of spans. */
52+typedef zoff_t bound_t;
53+typedef struct {
54+ bound_t beg; /* start of the span */
55+ bound_t end; /* one past the end of the span */
56+} span_t;
57+typedef struct {
58+ span_t *span; /* allocated, distinct, and sorted list of spans */
59+ size_t num; /* number of spans in the list */
60+ size_t max; /* allocated number of spans (num <= max) */
61+} cover_t;
62+
63+/*
64+ * Return the index of the first span in cover whose beg is greater than val.
65+ * If there is no such span, then cover->num is returned.
66+ */
67+static size_t cover_find(cover, val)
68+ cover_t *cover;
69+ bound_t val;
70+{
71+ size_t lo = 0, hi = cover->num;
72+ while (lo < hi) {
73+ size_t mid = (lo + hi) >> 1;
74+ if (val < cover->span[mid].beg)
75+ hi = mid;
76+ else
77+ lo = mid + 1;
78+ }
79+ return hi;
80+}
81+
82+/* Return true if val lies within any one of the spans in cover. */
83+static int cover_within(cover, val)
84+ cover_t *cover;
85+ bound_t val;
86+{
87+ size_t pos = cover_find(cover, val);
88+ return pos > 0 && val < cover->span[pos - 1].end;
89+}
90+
91+/*
92+ * Add a new span to the list, but only if the new span does not overlap any
93+ * spans already in the list. The new span covers the values beg..end-1. beg
94+ * must be less than end.
95+ *
96+ * Keep the list sorted and merge adjacent spans. Grow the allocated space for
97+ * the list as needed. On success, 0 is returned. If the new span overlaps any
98+ * existing spans, then 1 is returned and the new span is not added to the
99+ * list. If the new span is invalid because beg is greater than or equal to
100+ * end, then -1 is returned. If the list needs to be grown but the memory
101+ * allocation fails, then -2 is returned.
102+ */
103+static int cover_add(cover, beg, end)
104+ cover_t *cover;
105+ bound_t beg;
106+ bound_t end;
107+{
108+ size_t pos;
109+ int prec, foll;
110+
111+ if (beg >= end)
112+ /* The new span is invalid. */
113+ return -1;
114+
115+ /* Find where the new span should go, and make sure that it does not
116+ overlap with any existing spans. */
117+ pos = cover_find(cover, beg);
118+ if ((pos > 0 && beg < cover->span[pos - 1].end) ||
119+ (pos < cover->num && end > cover->span[pos].beg))
120+ return 1;
121+
122+ /* Check for adjacencies. */
123+ prec = pos > 0 && beg == cover->span[pos - 1].end;
124+ foll = pos < cover->num && end == cover->span[pos].beg;
125+ if (prec && foll) {
126+ /* The new span connects the preceding and following spans. Merge the
127+ following span into the preceding span, and delete the following
128+ span. */
129+ cover->span[pos - 1].end = cover->span[pos].end;
130+ cover->num--;
131+ memmove(cover->span + pos, cover->span + pos + 1,
132+ (cover->num - pos) * sizeof(span_t));
133+ }
134+ else if (prec)
135+ /* The new span is adjacent only to the preceding span. Extend the end
136+ of the preceding span. */
137+ cover->span[pos - 1].end = end;
138+ else if (foll)
139+ /* The new span is adjacent only to the following span. Extend the
140+ beginning of the following span. */
141+ cover->span[pos].beg = beg;
142+ else {
143+ /* The new span has gaps between both the preceding and the following
144+ spans. Assure that there is room and insert the span. */
145+ if (cover->num == cover->max) {
146+ size_t max = cover->max == 0 ? 16 : cover->max << 1;
147+ span_t *span = realloc(cover->span, max * sizeof(span_t));
148+ if (span == NULL)
149+ return -2;
150+ cover->span = span;
151+ cover->max = max;
152+ }
153+ memmove(cover->span + pos + 1, cover->span + pos,
154+ (cover->num - pos) * sizeof(span_t));
155+ cover->num++;
156+ cover->span[pos].beg = beg;
157+ cover->span[pos].end = end;
158+ }
159+ return 0;
160+}
161
162
163
164@@ -374,6 +493,29 @@ int extract_or_test_files(__G) /* return PK-type error code */
165 }
166 #endif /* !SFX || SFX_EXDIR */
167
168+ /* One more: initialize cover structure for bomb detection. Start with a
169+ span that covers the central directory though the end of the file. */
170+ if (G.cover == NULL) {
171+ G.cover = malloc(sizeof(cover_t));
172+ if (G.cover == NULL) {
173+ Info(slide, 0x401, ((char *)slide,
174+ LoadFarString(NotEnoughMemCover)));
175+ return PK_MEM;
176+ }
177+ ((cover_t *)G.cover)->span = NULL;
178+ ((cover_t *)G.cover)->max = 0;
179+ }
180+ ((cover_t *)G.cover)->num = 0;
181+ if ((G.extra_bytes != 0 &&
182+ cover_add((cover_t *)G.cover, 0, G.extra_bytes) != 0) ||
183+ cover_add((cover_t *)G.cover,
184+ G.extra_bytes + G.ecrec.offset_start_central_directory,
185+ G.ziplen) != 0) {
186+ Info(slide, 0x401, ((char *)slide,
187+ LoadFarString(NotEnoughMemCover)));
188+ return PK_MEM;
189+ }
190+
191 /*---------------------------------------------------------------------------
192 The basic idea of this function is as follows. Since the central di-
193 rectory lies at the end of the zipfile and the member files lie at the
194@@ -591,7 +733,8 @@ int extract_or_test_files(__G) /* return PK-type error code */
195 if (error > error_in_archive)
196 error_in_archive = error;
197 /* ...and keep going (unless disk full or user break) */
198- if (G.disk_full > 1 || error_in_archive == IZ_CTRLC) {
199+ if (G.disk_full > 1 || error_in_archive == IZ_CTRLC ||
200+ error == PK_BOMB) {
201 /* clear reached_end to signal premature stop ... */
202 reached_end = FALSE;
203 /* ... and cancel scanning the central directory */
204@@ -1060,6 +1203,11 @@ static int extract_or_test_entrylist(__G__ numchunk,
205
206 /* seek_zipf(__G__ pInfo->offset); */
207 request = G.pInfo->offset + G.extra_bytes;
208+ if (cover_within((cover_t *)G.cover, request)) {
209+ Info(slide, 0x401, ((char *)slide,
210+ LoadFarString(OverlappedComponents)));
211+ return PK_BOMB;
212+ }
213 inbuf_offset = request % INBUFSIZ;
214 bufstart = request - inbuf_offset;
215
216@@ -1591,6 +1739,18 @@ static int extract_or_test_entrylist(__G__ numchunk,
217 return IZ_CTRLC; /* cancel operation by user request */
218 }
219 #endif
220+ error = cover_add((cover_t *)G.cover, request,
221+ G.cur_zipfile_bufstart + (G.inptr - G.inbuf));
222+ if (error < 0) {
223+ Info(slide, 0x401, ((char *)slide,
224+ LoadFarString(NotEnoughMemCover)));
225+ return PK_MEM;
226+ }
227+ if (error != 0) {
228+ Info(slide, 0x401, ((char *)slide,
229+ LoadFarString(OverlappedComponents)));
230+ return PK_BOMB;
231+ }
232 #ifdef MACOS /* MacOS is no preemptive OS, thus call event-handling by hand */
233 UserStop();
234 #endif
235@@ -1992,6 +2152,34 @@ static int extract_or_test_member(__G) /* return PK-type error code */
236 }
237
238 undefer_input(__G);
239+
240+ if ((G.lrec.general_purpose_bit_flag & 8) != 0) {
241+ /* skip over data descriptor (harder than it sounds, due to signature
242+ * ambiguity)
243+ */
244+# define SIG 0x08074b50
245+# define LOW 0xffffffff
246+ uch buf[12];
247+ unsigned shy = 12 - readbuf((char *)buf, 12);
248+ ulg crc = shy ? 0 : makelong(buf);
249+ ulg clen = shy ? 0 : makelong(buf + 4);
250+ ulg ulen = shy ? 0 : makelong(buf + 8); /* or high clen if ZIP64 */
251+ if (crc == SIG && /* if not SIG, no signature */
252+ (G.lrec.crc32 != SIG || /* if not SIG, have signature */
253+ (clen == SIG && /* if not SIG, no signature */
254+ ((G.lrec.csize & LOW) != SIG || /* if not SIG, have signature */
255+ (ulen == SIG && /* if not SIG, no signature */
256+ (G.zip64 ? G.lrec.csize >> 32 : G.lrec.ucsize) != SIG
257+ /* if not SIG, have signature */
258+ )))))
259+ /* skip four more bytes to account for signature */
260+ shy += 4 - readbuf((char *)buf, 4);
261+ if (G.zip64)
262+ shy += 8 - readbuf((char *)buf, 8); /* skip eight more for ZIP64 */
263+ if (shy)
264+ error = PK_ERR;
265+ }
266+
267 return error;
268
269 } /* end function extract_or_test_member() */
270diff --git a/globals.c b/globals.c
271index fa8cca5..1e0f608 100644
272--- a/globals.c
273+++ b/globals.c
274@@ -181,6 +181,7 @@ Uz_Globs *globalsCtor()
275 # if (!defined(NO_TIMESTAMPS))
276 uO.D_flag=1; /* default to '-D', no restoration of dir timestamps */
277 # endif
278+ G.cover = NULL; /* not allocated yet */
279 #endif
280
281 uO.lflag=(-1);
282diff --git a/globals.h b/globals.h
283index 11b7215..2bdcdeb 100644
284--- a/globals.h
285+++ b/globals.h
286@@ -260,12 +260,15 @@ typedef struct Globals {
287 ecdir_rec ecrec; /* used in unzip.c, extract.c */
288 z_stat statbuf; /* used by main, mapname, check_for_newer */
289
290+ int zip64; /* true if Zip64 info in extra field */
291+
292 int mem_mode;
293 uch *outbufptr; /* extract.c static */
294 ulg outsize; /* extract.c static */
295 int reported_backslash; /* extract.c static */
296 int disk_full;
297 int newfile;
298+ void **cover; /* used in extract.c for bomb detection */
299
300 int didCRlast; /* fileio static */
301 ulg numlines; /* fileio static: number of lines printed */
302diff --git a/process.c b/process.c
303index 1e9a1e1..d2e4dc3 100644
304--- a/process.c
305+++ b/process.c
306@@ -637,6 +637,13 @@ void free_G_buffers(__G) /* releases all memory allocated in global vars */
307 }
308 #endif
309
310+ /* Free the cover span list and the cover structure. */
311+ if (G.cover != NULL) {
312+ free(*(G.cover));
313+ free(G.cover);
314+ G.cover = NULL;
315+ }
316+
317 } /* end function free_G_buffers() */
318
319
320@@ -1890,6 +1897,8 @@ int getZip64Data(__G__ ef_buf, ef_len)
321 #define Z64FLGS 0xffff
322 #define Z64FLGL 0xffffffff
323
324+ G.zip64 = FALSE;
325+
326 if (ef_len == 0 || ef_buf == NULL)
327 return PK_COOL;
328
329@@ -1927,6 +1936,8 @@ int getZip64Data(__G__ ef_buf, ef_len)
330 #if 0
331 break; /* Expect only one EF_PKSZ64 block. */
332 #endif /* 0 */
333+
334+ G.zip64 = TRUE;
335 }
336
337 /* Skip this extra field block. */
338diff --git a/unzip.h b/unzip.h
339index 5b2a326..ed24a5b 100644
340--- a/unzip.h
341+++ b/unzip.h
342@@ -645,6 +645,7 @@ typedef struct _Uzp_cdir_Rec {
343 #define PK_NOZIP 9 /* zipfile not found */
344 #define PK_PARAM 10 /* bad or illegal parameters specified */
345 #define PK_FIND 11 /* no files found */
346+#define PK_BOMB 12 /* likely zip bomb */
347 #define PK_DISK 50 /* disk full */
348 #define PK_EOF 51 /* unexpected EOF */
349
350From 6d351831be705cc26d897db44f878a978f4138fc Mon Sep 17 00:00:00 2001
351From: Mark Adler <madler@alumni.caltech.edu>
352Date: Thu, 25 Jul 2019 20:43:17 -0700
353Subject: [PATCH] Do not raise a zip bomb alert for a misplaced central
354 directory.
355
356There is a zip-like file in the Firefox distribution, omni.ja,
357which is a zip container with the central directory placed at the
358start of the file instead of after the local entries as required
359by the zip standard. This commit marks the actual location of the
360central directory, as well as the end of central directory records,
361as disallowed locations. This now permits such containers to not
362raise a zip bomb alert, where in fact there are no overlaps.
363---
364 extract.c | 25 +++++++++++++++++++------
365 process.c | 6 ++++++
366 unzpriv.h | 10 ++++++++++
367 3 files changed, 35 insertions(+), 6 deletions(-)
368
369diff --git a/extract.c b/extract.c
370index 0973a33..1b73cb0 100644
371--- a/extract.c
372+++ b/extract.c
373@@ -493,8 +493,11 @@ int extract_or_test_files(__G) /* return PK-type error code */
374 }
375 #endif /* !SFX || SFX_EXDIR */
376
377- /* One more: initialize cover structure for bomb detection. Start with a
378- span that covers the central directory though the end of the file. */
379+ /* One more: initialize cover structure for bomb detection. Start with
380+ spans that cover any extra bytes at the start, the central directory,
381+ the end of central directory record (including the Zip64 end of central
382+ directory locator, if present), and the Zip64 end of central directory
383+ record, if present. */
384 if (G.cover == NULL) {
385 G.cover = malloc(sizeof(cover_t));
386 if (G.cover == NULL) {
387@@ -506,15 +509,25 @@ int extract_or_test_files(__G) /* return PK-type error code */
388 ((cover_t *)G.cover)->max = 0;
389 }
390 ((cover_t *)G.cover)->num = 0;
391- if ((G.extra_bytes != 0 &&
392- cover_add((cover_t *)G.cover, 0, G.extra_bytes) != 0) ||
393- cover_add((cover_t *)G.cover,
394+ if (cover_add((cover_t *)G.cover,
395 G.extra_bytes + G.ecrec.offset_start_central_directory,
396- G.ziplen) != 0) {
397+ G.extra_bytes + G.ecrec.offset_start_central_directory +
398+ G.ecrec.size_central_directory) != 0) {
399 Info(slide, 0x401, ((char *)slide,
400 LoadFarString(NotEnoughMemCover)));
401 return PK_MEM;
402 }
403+ if ((G.extra_bytes != 0 &&
404+ cover_add((cover_t *)G.cover, 0, G.extra_bytes) != 0) ||
405+ (G.ecrec.have_ecr64 &&
406+ cover_add((cover_t *)G.cover, G.ecrec.ec64_start,
407+ G.ecrec.ec64_end) != 0) ||
408+ cover_add((cover_t *)G.cover, G.ecrec.ec_start,
409+ G.ecrec.ec_end) != 0) {
410+ Info(slide, 0x401, ((char *)slide,
411+ LoadFarString(OverlappedComponents)));
412+ return PK_BOMB;
413+ }
414
415 /*---------------------------------------------------------------------------
416 The basic idea of this function is as follows. Since the central di-
417diff --git a/process.c b/process.c
418index d2e4dc3..d75d405 100644
419--- a/process.c
420+++ b/process.c
421@@ -1408,6 +1408,10 @@ static int find_ecrec64(__G__ searchlen) /* return PK-class error */
422
423 /* Now, we are (almost) sure that we have a Zip64 archive. */
424 G.ecrec.have_ecr64 = 1;
425+ G.ecrec.ec_start -= ECLOC64_SIZE+4;
426+ G.ecrec.ec64_start = ecrec64_start_offset;
427+ G.ecrec.ec64_end = ecrec64_start_offset +
428+ 12 + makeint64(&byterec[ECREC64_LENGTH]);
429
430 /* Update the "end-of-central-dir offset" for later checks. */
431 G.real_ecrec_offset = ecrec64_start_offset;
432@@ -1542,6 +1546,8 @@ static int find_ecrec(__G__ searchlen) /* return PK-class error */
433 makelong(&byterec[OFFSET_START_CENTRAL_DIRECTORY]);
434 G.ecrec.zipfile_comment_length =
435 makeword(&byterec[ZIPFILE_COMMENT_LENGTH]);
436+ G.ecrec.ec_start = G.real_ecrec_offset;
437+ G.ecrec.ec_end = G.ecrec.ec_start + 22 + G.ecrec.zipfile_comment_length;
438
439 /* Now, we have to read the archive comment, BEFORE the file pointer
440 is moved away backwards to seek for a Zip64 ECLOC64 structure.
441diff --git a/unzpriv.h b/unzpriv.h
442index dc9eff5..297b3c7 100644
443--- a/unzpriv.h
444+++ b/unzpriv.h
445@@ -2185,6 +2185,16 @@ typedef struct VMStimbuf {
446 int have_ecr64; /* valid Zip64 ecdir-record exists */
447 int is_zip64_archive; /* Zip64 ecdir-record is mandatory */
448 ush zipfile_comment_length;
449+ zusz_t ec_start, ec_end; /* offsets of start and end of the
450+ end of central directory record,
451+ including if present the Zip64
452+ end of central directory locator,
453+ which immediately precedes the
454+ end of central directory record */
455+ zusz_t ec64_start, ec64_end; /* if have_ecr64 is true, then these
456+ are the offsets of the start and
457+ end of the Zip64 end of central
458+ directory record */
459 } ecdir_rec;
460
461
462From 41beb477c5744bc396fa1162ee0c14218ec12213 Mon Sep 17 00:00:00 2001
463From: Mark Adler <madler@alumni.caltech.edu>
464Date: Mon, 27 May 2019 08:20:32 -0700
465Subject: [PATCH] Fix bug in undefer_input() that misplaced the input state.
466
467---
468 fileio.c | 4 +++-
469 1 file changed, 3 insertions(+), 1 deletion(-)
470
471diff --git a/fileio.c b/fileio.c
472index c042987..bc00d74 100644
473--- a/fileio.c
474+++ b/fileio.c
475@@ -530,8 +530,10 @@ void undefer_input(__G)
476 * This condition was checked when G.incnt_leftover was set > 0 in
477 * defer_leftover_input(), and it is NOT allowed to touch G.csize
478 * before calling undefer_input() when (G.incnt_leftover > 0)
479- * (single exception: see read_byte()'s "G.csize <= 0" handling) !!
480+ * (single exception: see readbyte()'s "G.csize <= 0" handling) !!
481 */
482+ if (G.csize < 0L)
483+ G.csize = 0L;
484 G.incnt = G.incnt_leftover + (int)G.csize;
485 G.inptr = G.inptr_leftover - (int)G.csize;
486 G.incnt_leftover = 0;
487