1
0
mirror of https://github.com/termux/termux-packages synced 2024-06-18 23:47:06 +00:00

unzip: import security patches from debian

This commit is contained in:
Chongyun Lee 2022-08-09 21:23:19 +08:00 committed by Uchiha Kakashi
parent 7b33c22dc8
commit e8eb1b421b
9 changed files with 778 additions and 0 deletions

View File

@ -0,0 +1,28 @@
From: "Steven M. Schweda" <sms@antinode.info>
Subject: Fix CVE-2016-9844, buffer overflow in zipinfo
Bug-Debian: https://bugs.debian.org/847486
Bug-Ubuntu: https://launchpad.net/bugs/1643750
X-Debian-version: 6.0-21
--- a/zipinfo.c
+++ b/zipinfo.c
@@ -1921,7 +1921,18 @@
ush dnum=(ush)((G.crec.general_purpose_bit_flag>>1) & 3);
methbuf[3] = dtype[dnum];
} else if (methnum >= NUM_METHODS) { /* unknown */
- sprintf(&methbuf[1], "%03u", G.crec.compression_method);
+ /* 2016-12-05 SMS.
+ * https://launchpad.net/bugs/1643750
+ * Unexpectedly large compression methods overflow
+ * &methbuf[]. Use the old, three-digit decimal format
+ * for values which fit. Otherwise, sacrifice the "u",
+ * and use four-digit hexadecimal.
+ */
+ if (G.crec.compression_method <= 999) {
+ sprintf( &methbuf[ 1], "%03u", G.crec.compression_method);
+ } else {
+ sprintf( &methbuf[ 0], "%04X", G.crec.compression_method);
+ }
}
for (k = 0; k < 15; ++k)

View File

@ -0,0 +1,36 @@
From: Karol Babioch <kbabioch@suse.com>
Subject: Fix buffer overflow in password protected zip archives
Bug-Debian: https://bugs.debian.org/889838
Origin: https://bugzilla.novell.com/attachment.cgi?id=759406
X-Debian-version: 6.0-22
--- a/fileio.c
+++ b/fileio.c
@@ -1582,6 +1582,10 @@
int r = IZ_PW_ENTERED;
char *m;
char *prompt;
+ char *zfnf;
+ char *efnf;
+ size_t zfnfl;
+ int isOverflow;
#ifndef REENTRANT
/* tell picky compilers to shut up about "unused variable" warnings */
@@ -1590,7 +1594,15 @@
if (*rcnt == 0) { /* First call for current entry */
*rcnt = 2;
- if ((prompt = (char *)malloc(2*FILNAMSIZ + 15)) != (char *)NULL) {
+ zfnf = FnFilter1(zfn);
+ efnf = FnFilter2(efn);
+ zfnfl = strlen(zfnf);
+ isOverflow = TRUE;
+ if (2*FILNAMSIZ >= zfnfl && (2*FILNAMSIZ - zfnfl) >= strlen(efnf))
+ {
+ isOverflow = FALSE;
+ }
+ if ((isOverflow == FALSE) && ((prompt = (char *)malloc(2*FILNAMSIZ + 15)) != (char *)NULL)) {
sprintf(prompt, LoadFarString(PasswPrompt),
FnFilter1(zfn), FnFilter2(efn));
m = prompt;

View File

@ -0,0 +1,35 @@
--- unzip60/list.c
+++ unzip60/list.c
@@ -97,7 +97,7 @@ int list_files(__G) /* return PK-type
{
int do_this_file=FALSE, cfactor, error, error_in_archive=PK_COOL;
#ifndef WINDLL
- char sgn, cfactorstr[13];
+ char sgn, cfactorstr[1+10+1+1]; /* <sgn><int>%NUL */
int longhdr=(uO.vflag>1);
#endif
int date_format;
@@ -389,9 +389,9 @@ int list_files(__G) /* return PK-type
}
#else /* !WINDLL */
if (cfactor == 100)
- sprintf(cfactorstr, LoadFarString(CompFactor100));
+ snprintf(cfactorstr, sizeof(cfactorstr), LoadFarString(CompFactor100));
else
- sprintf(cfactorstr, LoadFarString(CompFactorStr), sgn, cfactor);
+ snprintf(cfactorstr, sizeof(cfactorstr), LoadFarString(CompFactorStr), sgn, cfactor);
if (longhdr)
Info(slide, 0, ((char *)slide, LoadFarString(LongHdrStats),
FmZofft(G.crec.ucsize, "8", "u"), methbuf,
@@ -471,9 +471,9 @@ int list_files(__G) /* return PK-type
#else /* !WINDLL */
if (cfactor == 100)
- sprintf(cfactorstr, LoadFarString(CompFactor100));
+ snprintf(cfactorstr, sizeof(cfactorstr), LoadFarString(CompFactor100));
else
- sprintf(cfactorstr, LoadFarString(CompFactorStr), sgn, cfactor);
+ snprintf(cfactorstr, sizeof(cfactorstr), LoadFarString(CompFactorStr), sgn, cfactor);
if (longhdr) {
Info(slide, 0, ((char *)slide, LoadFarString(LongFileTrailer),
FmZofft(tot_ucsize, "8", "u"), FmZofft(tot_csize, "8", "u"),

View File

@ -0,0 +1,22 @@
From: Mark Adler <madler@alumni.caltech.edu>
Subject: Fix bug in undefer_input() that misplaced the input state.
Origin: https://github.com/madler/unzip/commit/41beb477c5744bc396fa1162ee0c14218ec12213
Bug-Debian: https://bugs.debian.org/931433
X-Debian-version: 6.0-24
Fix bug in undefer_input() that misplaced the input state.
--- a/fileio.c
+++ b/fileio.c
@@ -532,8 +532,10 @@
* This condition was checked when G.incnt_leftover was set > 0 in
* defer_leftover_input(), and it is NOT allowed to touch G.csize
* before calling undefer_input() when (G.incnt_leftover > 0)
- * (single exception: see read_byte()'s "G.csize <= 0" handling) !!
+ * (single exception: see readbyte()'s "G.csize <= 0" handling) !!
*/
+ if (G.csize < 0L)
+ G.csize = 0L;
G.incnt = G.incnt_leftover + (int)G.csize;
G.inptr = G.inptr_leftover - (int)G.csize;
G.incnt_leftover = 0;

View File

@ -0,0 +1,335 @@
From: Mark Adler <madler@alumni.caltech.edu>
Subject: Detect and reject a zip bomb using overlapped entries.
Origin: https://github.com/madler/unzip/commit/47b3ceae397d21bf822bc2ac73052a4b1daf8e1c
Bug-Debian: https://bugs.debian.org/931433
X-Debian-version: 6.0-24
Detect and reject a zip bomb using overlapped entries.
This detects an invalid zip file that has at least one entry that
overlaps with another entry or with the central directory to the
end of the file. A Fifield zip bomb uses overlapped local entries
to vastly increase the potential inflation ratio. Such an invalid
zip file is rejected.
See https://www.bamsoftware.com/hacks/zipbomb/ for David Fifield's
analysis, construction, and examples of such zip bombs.
The detection maintains a list of covered spans of the zip files
so far, where the central directory to the end of the file and any
bytes preceding the first entry at zip file offset zero are
considered covered initially. Then as each entry is decompressed
or tested, it is considered covered. When a new entry is about to
be processed, its initial offset is checked to see if it is
contained by a covered span. If so, the zip file is rejected as
invalid.
This commit depends on a preceding commit: "Fix bug in
undefer_input() that misplaced the input state."
--- a/extract.c
+++ b/extract.c
@@ -321,6 +321,125 @@
"\nerror: unsupported extra-field compression type (%u)--skipping\n";
static ZCONST char Far BadExtraFieldCRC[] =
"error [%s]: bad extra-field CRC %08lx (should be %08lx)\n";
+static ZCONST char Far NotEnoughMemCover[] =
+ "error: not enough memory for bomb detection\n";
+static ZCONST char Far OverlappedComponents[] =
+ "error: invalid zip file with overlapped components (possible zip bomb)\n";
+
+
+
+
+
+/* A growable list of spans. */
+typedef zoff_t bound_t;
+typedef struct {
+ bound_t beg; /* start of the span */
+ bound_t end; /* one past the end of the span */
+} span_t;
+typedef struct {
+ span_t *span; /* allocated, distinct, and sorted list of spans */
+ size_t num; /* number of spans in the list */
+ size_t max; /* allocated number of spans (num <= max) */
+} cover_t;
+
+/*
+ * Return the index of the first span in cover whose beg is greater than val.
+ * If there is no such span, then cover->num is returned.
+ */
+static size_t cover_find(cover, val)
+ cover_t *cover;
+ bound_t val;
+{
+ size_t lo = 0, hi = cover->num;
+ while (lo < hi) {
+ size_t mid = (lo + hi) >> 1;
+ if (val < cover->span[mid].beg)
+ hi = mid;
+ else
+ lo = mid + 1;
+ }
+ return hi;
+}
+
+/* Return true if val lies within any one of the spans in cover. */
+static int cover_within(cover, val)
+ cover_t *cover;
+ bound_t val;
+{
+ size_t pos = cover_find(cover, val);
+ return pos > 0 && val < cover->span[pos - 1].end;
+}
+
+/*
+ * Add a new span to the list, but only if the new span does not overlap any
+ * spans already in the list. The new span covers the values beg..end-1. beg
+ * must be less than end.
+ *
+ * Keep the list sorted and merge adjacent spans. Grow the allocated space for
+ * the list as needed. On success, 0 is returned. If the new span overlaps any
+ * existing spans, then 1 is returned and the new span is not added to the
+ * list. If the new span is invalid because beg is greater than or equal to
+ * end, then -1 is returned. If the list needs to be grown but the memory
+ * allocation fails, then -2 is returned.
+ */
+static int cover_add(cover, beg, end)
+ cover_t *cover;
+ bound_t beg;
+ bound_t end;
+{
+ size_t pos;
+ int prec, foll;
+
+ if (beg >= end)
+ /* The new span is invalid. */
+ return -1;
+
+ /* Find where the new span should go, and make sure that it does not
+ overlap with any existing spans. */
+ pos = cover_find(cover, beg);
+ if ((pos > 0 && beg < cover->span[pos - 1].end) ||
+ (pos < cover->num && end > cover->span[pos].beg))
+ return 1;
+
+ /* Check for adjacencies. */
+ prec = pos > 0 && beg == cover->span[pos - 1].end;
+ foll = pos < cover->num && end == cover->span[pos].beg;
+ if (prec && foll) {
+ /* The new span connects the preceding and following spans. Merge the
+ following span into the preceding span, and delete the following
+ span. */
+ cover->span[pos - 1].end = cover->span[pos].end;
+ cover->num--;
+ memmove(cover->span + pos, cover->span + pos + 1,
+ (cover->num - pos) * sizeof(span_t));
+ }
+ else if (prec)
+ /* The new span is adjacent only to the preceding span. Extend the end
+ of the preceding span. */
+ cover->span[pos - 1].end = end;
+ else if (foll)
+ /* The new span is adjacent only to the following span. Extend the
+ beginning of the following span. */
+ cover->span[pos].beg = beg;
+ else {
+ /* The new span has gaps between both the preceding and the following
+ spans. Assure that there is room and insert the span. */
+ if (cover->num == cover->max) {
+ size_t max = cover->max == 0 ? 16 : cover->max << 1;
+ span_t *span = realloc(cover->span, max * sizeof(span_t));
+ if (span == NULL)
+ return -2;
+ cover->span = span;
+ cover->max = max;
+ }
+ memmove(cover->span + pos + 1, cover->span + pos,
+ (cover->num - pos) * sizeof(span_t));
+ cover->num++;
+ cover->span[pos].beg = beg;
+ cover->span[pos].end = end;
+ }
+ return 0;
+}
@@ -376,6 +495,29 @@
}
#endif /* !SFX || SFX_EXDIR */
+ /* One more: initialize cover structure for bomb detection. Start with a
+ span that covers the central directory though the end of the file. */
+ if (G.cover == NULL) {
+ G.cover = malloc(sizeof(cover_t));
+ if (G.cover == NULL) {
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(NotEnoughMemCover)));
+ return PK_MEM;
+ }
+ ((cover_t *)G.cover)->span = NULL;
+ ((cover_t *)G.cover)->max = 0;
+ }
+ ((cover_t *)G.cover)->num = 0;
+ if ((G.extra_bytes != 0 &&
+ cover_add((cover_t *)G.cover, 0, G.extra_bytes) != 0) ||
+ cover_add((cover_t *)G.cover,
+ G.extra_bytes + G.ecrec.offset_start_central_directory,
+ G.ziplen) != 0) {
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(NotEnoughMemCover)));
+ return PK_MEM;
+ }
+
/*---------------------------------------------------------------------------
The basic idea of this function is as follows. Since the central di-
rectory lies at the end of the zipfile and the member files lie at the
@@ -593,7 +735,8 @@
if (error > error_in_archive)
error_in_archive = error;
/* ...and keep going (unless disk full or user break) */
- if (G.disk_full > 1 || error_in_archive == IZ_CTRLC) {
+ if (G.disk_full > 1 || error_in_archive == IZ_CTRLC ||
+ error == PK_BOMB) {
/* clear reached_end to signal premature stop ... */
reached_end = FALSE;
/* ... and cancel scanning the central directory */
@@ -1062,6 +1205,11 @@
/* seek_zipf(__G__ pInfo->offset); */
request = G.pInfo->offset + G.extra_bytes;
+ if (cover_within((cover_t *)G.cover, request)) {
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(OverlappedComponents)));
+ return PK_BOMB;
+ }
inbuf_offset = request % INBUFSIZ;
bufstart = request - inbuf_offset;
@@ -1602,6 +1750,18 @@
return IZ_CTRLC; /* cancel operation by user request */
}
#endif
+ error = cover_add((cover_t *)G.cover, request,
+ G.cur_zipfile_bufstart + (G.inptr - G.inbuf));
+ if (error < 0) {
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(NotEnoughMemCover)));
+ return PK_MEM;
+ }
+ if (error != 0) {
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(OverlappedComponents)));
+ return PK_BOMB;
+ }
#ifdef MACOS /* MacOS is no preemptive OS, thus call event-handling by hand */
UserStop();
#endif
@@ -2003,6 +2163,34 @@
}
undefer_input(__G);
+
+ if ((G.lrec.general_purpose_bit_flag & 8) != 0) {
+ /* skip over data descriptor (harder than it sounds, due to signature
+ * ambiguity)
+ */
+# define SIG 0x08074b50
+# define LOW 0xffffffff
+ uch buf[12];
+ unsigned shy = 12 - readbuf((char *)buf, 12);
+ ulg crc = shy ? 0 : makelong(buf);
+ ulg clen = shy ? 0 : makelong(buf + 4);
+ ulg ulen = shy ? 0 : makelong(buf + 8); /* or high clen if ZIP64 */
+ if (crc == SIG && /* if not SIG, no signature */
+ (G.lrec.crc32 != SIG || /* if not SIG, have signature */
+ (clen == SIG && /* if not SIG, no signature */
+ ((G.lrec.csize & LOW) != SIG || /* if not SIG, have signature */
+ (ulen == SIG && /* if not SIG, no signature */
+ (G.zip64 ? G.lrec.csize >> 32 : G.lrec.ucsize) != SIG
+ /* if not SIG, have signature */
+ )))))
+ /* skip four more bytes to account for signature */
+ shy += 4 - readbuf((char *)buf, 4);
+ if (G.zip64)
+ shy += 8 - readbuf((char *)buf, 8); /* skip eight more for ZIP64 */
+ if (shy)
+ error = PK_ERR;
+ }
+
return error;
} /* end function extract_or_test_member() */
--- a/globals.c
+++ b/globals.c
@@ -181,6 +181,7 @@
# if (!defined(NO_TIMESTAMPS))
uO.D_flag=1; /* default to '-D', no restoration of dir timestamps */
# endif
+ G.cover = NULL; /* not allocated yet */
#endif
uO.lflag=(-1);
--- a/globals.h
+++ b/globals.h
@@ -260,12 +260,15 @@
ecdir_rec ecrec; /* used in unzip.c, extract.c */
z_stat statbuf; /* used by main, mapname, check_for_newer */
+ int zip64; /* true if Zip64 info in extra field */
+
int mem_mode;
uch *outbufptr; /* extract.c static */
ulg outsize; /* extract.c static */
int reported_backslash; /* extract.c static */
int disk_full;
int newfile;
+ void **cover; /* used in extract.c for bomb detection */
int didCRlast; /* fileio static */
ulg numlines; /* fileio static: number of lines printed */
--- a/process.c
+++ b/process.c
@@ -637,6 +637,13 @@
}
#endif
+ /* Free the cover span list and the cover structure. */
+ if (G.cover != NULL) {
+ free(*(G.cover));
+ free(G.cover);
+ G.cover = NULL;
+ }
+
} /* end function free_G_buffers() */
@@ -1913,6 +1920,8 @@
#define Z64FLGS 0xffff
#define Z64FLGL 0xffffffff
+ G.zip64 = FALSE;
+
if (ef_len == 0 || ef_buf == NULL)
return PK_COOL;
@@ -2084,6 +2093,8 @@
(ZCONST char *)(offset + ef_buf), ULen);
G.unipath_filename[ULen] = '\0';
}
+
+ G.zip64 = TRUE;
}
/* Skip this extra field block */
--- a/unzip.h
+++ b/unzip.h
@@ -645,6 +645,7 @@
#define PK_NOZIP 9 /* zipfile not found */
#define PK_PARAM 10 /* bad or illegal parameters specified */
#define PK_FIND 11 /* no files found */
+#define PK_BOMB 12 /* likely zip bomb */
#define PK_DISK 50 /* disk full */
#define PK_EOF 51 /* unexpected EOF */

View File

@ -0,0 +1,103 @@
From: Mark Adler <madler@alumni.caltech.edu>
Subject: Do not raise a zip bomb alert for a misplaced central directory.
Origin: https://github.com/madler/unzip/commit/6d351831be705cc26d897db44f878a978f4138fc
Bug-Debian: https://bugs.debian.org/932404
X-Debian-version: 6.0-25
Do not raise a zip bomb alert for a misplaced central directory.
There is a zip-like file in the Firefox distribution, omni.ja,
which is a zip container with the central directory placed at the
start of the file instead of after the local entries as required
by the zip standard. This commit marks the actual location of the
central directory, as well as the end of central directory records,
as disallowed locations. This now permits such containers to not
raise a zip bomb alert, where in fact there are no overlaps.
--- a/extract.c
+++ b/extract.c
@@ -495,8 +495,11 @@
}
#endif /* !SFX || SFX_EXDIR */
- /* One more: initialize cover structure for bomb detection. Start with a
- span that covers the central directory though the end of the file. */
+ /* One more: initialize cover structure for bomb detection. Start with
+ spans that cover any extra bytes at the start, the central directory,
+ the end of central directory record (including the Zip64 end of central
+ directory locator, if present), and the Zip64 end of central directory
+ record, if present. */
if (G.cover == NULL) {
G.cover = malloc(sizeof(cover_t));
if (G.cover == NULL) {
@@ -508,15 +511,25 @@
((cover_t *)G.cover)->max = 0;
}
((cover_t *)G.cover)->num = 0;
- if ((G.extra_bytes != 0 &&
- cover_add((cover_t *)G.cover, 0, G.extra_bytes) != 0) ||
- cover_add((cover_t *)G.cover,
+ if (cover_add((cover_t *)G.cover,
G.extra_bytes + G.ecrec.offset_start_central_directory,
- G.ziplen) != 0) {
+ G.extra_bytes + G.ecrec.offset_start_central_directory +
+ G.ecrec.size_central_directory) != 0) {
Info(slide, 0x401, ((char *)slide,
LoadFarString(NotEnoughMemCover)));
return PK_MEM;
}
+ if ((G.extra_bytes != 0 &&
+ cover_add((cover_t *)G.cover, 0, G.extra_bytes) != 0) ||
+ (G.ecrec.have_ecr64 &&
+ cover_add((cover_t *)G.cover, G.ecrec.ec64_start,
+ G.ecrec.ec64_end) != 0) ||
+ cover_add((cover_t *)G.cover, G.ecrec.ec_start,
+ G.ecrec.ec_end) != 0) {
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(OverlappedComponents)));
+ return PK_BOMB;
+ }
/*---------------------------------------------------------------------------
The basic idea of this function is as follows. Since the central di-
--- a/process.c
+++ b/process.c
@@ -1408,6 +1408,10 @@
/* Now, we are (almost) sure that we have a Zip64 archive. */
G.ecrec.have_ecr64 = 1;
+ G.ecrec.ec_start -= ECLOC64_SIZE+4;
+ G.ecrec.ec64_start = ecrec64_start_offset;
+ G.ecrec.ec64_end = ecrec64_start_offset +
+ 12 + makeint64(&byterec[ECREC64_LENGTH]);
/* Update the "end-of-central-dir offset" for later checks. */
G.real_ecrec_offset = ecrec64_start_offset;
@@ -1542,6 +1546,8 @@
makelong(&byterec[OFFSET_START_CENTRAL_DIRECTORY]);
G.ecrec.zipfile_comment_length =
makeword(&byterec[ZIPFILE_COMMENT_LENGTH]);
+ G.ecrec.ec_start = G.real_ecrec_offset;
+ G.ecrec.ec_end = G.ecrec.ec_start + 22 + G.ecrec.zipfile_comment_length;
/* Now, we have to read the archive comment, BEFORE the file pointer
is moved away backwards to seek for a Zip64 ECLOC64 structure.
--- a/unzpriv.h
+++ b/unzpriv.h
@@ -2185,6 +2185,16 @@
int have_ecr64; /* valid Zip64 ecdir-record exists */
int is_zip64_archive; /* Zip64 ecdir-record is mandatory */
ush zipfile_comment_length;
+ zusz_t ec_start, ec_end; /* offsets of start and end of the
+ end of central directory record,
+ including if present the Zip64
+ end of central directory locator,
+ which immediately precedes the
+ end of central directory record */
+ zusz_t ec64_start, ec64_end; /* if have_ecr64 is true, then these
+ are the offsets of the start and
+ end of the Zip64 end of central
+ directory record */
} ecdir_rec;

View File

@ -0,0 +1,23 @@
From: Mark Adler <madler@alumni.caltech.edu>
Subject: Fix bug in UZbunzip2() that incorrectly updated G.incnt
Origin: https://github.com/madler/unzip/commit/5e2efcd633a4a1fb95a129a75508e7d769e767be
Bug-Debian: https://bugs.debian.org/963996
X-Debian-version: 6.0-26
Fix bug in UZbunzip2() that incorrectly updated G.incnt.
The update assumed a full buffer, which is not always full. This
could result in a false overlapped element detection when a small
bzip2-compressed file was unzipped. This commit remedies that.
--- a/extract.c
+++ b/extract.c
@@ -3052,7 +3052,7 @@
#endif
G.inptr = (uch *)bstrm.next_in;
- G.incnt = (G.inbuf + INBUFSIZ) - G.inptr; /* reset for other routines */
+ G.incnt -= G.inptr - G.inbuf; /* reset for other routines */
uzbunzip_cleanup_exit:
err = BZ2_bzDecompressEnd(&bstrm);

View File

@ -0,0 +1,23 @@
From: Mark Adler <madler@alumni.caltech.edu>
Subject: Fix bug in UZinflate() that incorrectly updated G.incnt.
Origin: https://github.com/madler/unzip/commit/5c572555cf5d80309a07c30cf7a54b2501493720
X-Debian-version: 6.0-26
Fix bug in UZinflate() that incorrectly updated G.incnt.
The update assumed a full buffer, which is not always full. This
could result in a false overlapped element detection when a small
deflate-compressed file was unzipped using an old zlib. This
commit remedies that.
--- a/inflate.c
+++ b/inflate.c
@@ -700,7 +700,7 @@
G.dstrm.total_out));
G.inptr = (uch *)G.dstrm.next_in;
- G.incnt = (G.inbuf + INBUFSIZ) - G.inptr; /* reset for other routines */
+ G.incnt -= G.inptr - G.inbuf; /* reset for other routines */
uzinflate_cleanup_exit:
err = inflateReset(&G.dstrm);

View File

@ -0,0 +1,173 @@
From: Steven M. Schweda <sms@antinode.info>
Subject: Fix for CVE-2022-0529 and CVE-2022-0530
Bug-Debian: https://bugs.debian.org/1010355
X-Debian-version: 6.0-27
--- a/fileio.c
+++ b/fileio.c
@@ -171,8 +171,10 @@
static ZCONST char Far FilenameTooLongTrunc[] =
"warning: filename too long--truncating.\n";
#ifdef UNICODE_SUPPORT
+ static ZCONST char Far UFilenameCorrupt[] =
+ "error: Unicode filename corrupt.\n";
static ZCONST char Far UFilenameTooLongTrunc[] =
- "warning: Converted unicode filename too long--truncating.\n";
+ "warning: Converted Unicode filename too long--truncating.\n";
#endif
static ZCONST char Far ExtraFieldTooLong[] =
"warning: extra field too long (%d). Ignoring...\n";
@@ -2361,16 +2363,30 @@
/* convert UTF-8 to local character set */
fn = utf8_to_local_string(G.unipath_filename,
G.unicode_escape_all);
- /* make sure filename is short enough */
- if (strlen(fn) >= FILNAMSIZ) {
- fn[FILNAMSIZ - 1] = '\0';
+
+ /* 2022-07-22 SMS, et al. CVE-2022-0530
+ * Detect conversion failure, emit message.
+ * Continue with unconverted name.
+ */
+ if (fn == NULL)
+ {
Info(slide, 0x401, ((char *)slide,
- LoadFarString(UFilenameTooLongTrunc)));
- error = PK_WARN;
+ LoadFarString(UFilenameCorrupt)));
+ error = PK_ERR;
+ }
+ else
+ {
+ /* make sure filename is short enough */
+ if (strlen(fn) >= FILNAMSIZ) {
+ fn[FILNAMSIZ - 1] = '\0';
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(UFilenameTooLongTrunc)));
+ error = PK_WARN;
+ }
+ /* replace filename with converted UTF-8 */
+ strcpy(G.filename, fn);
+ free(fn);
}
- /* replace filename with converted UTF-8 */
- strcpy(G.filename, fn);
- free(fn);
}
# endif /* UNICODE_WCHAR */
if (G.unipath_filename != G.filename_full)
--- a/process.c
+++ b/process.c
@@ -222,6 +222,8 @@
"\nwarning: Unicode Path version > 1\n";
static ZCONST char Far UnicodeMismatchError[] =
"\nwarning: Unicode Path checksum invalid\n";
+ static ZCONST char Far UFilenameTooLongTrunc[] =
+ "warning: filename too long (P1) -- truncating.\n";
#endif
@@ -1915,7 +1917,7 @@
Sets both local header and central header fields. Not terribly clever,
but it means that this procedure is only called in one place.
- 2014-12-05 SMS.
+ 2014-12-05 SMS. (oCERT.org report.) CVE-2014-8141.
Added checks to ensure that enough data are available before calling
makeint64() or makelong(). Replaced various sizeof() values with
simple ("4" or "8") constants. (The Zip64 structures do not depend
@@ -1947,9 +1949,10 @@
ef_len - EB_HEADSIZE));
break;
}
+
if (eb_id == EF_PKSZ64)
{
- int offset = EB_HEADSIZE;
+ unsigned offset = EB_HEADSIZE;
if ((G.crec.ucsize == Z64FLGL) || (G.lrec.ucsize == Z64FLGL))
{
@@ -2046,7 +2049,7 @@
}
if (eb_id == EF_UNIPATH) {
- int offset = EB_HEADSIZE;
+ unsigned offset = EB_HEADSIZE;
ush ULen = eb_len - 5;
ulg chksum = CRCVAL_INITIAL;
@@ -2504,16 +2507,17 @@
int state_dependent;
int wsize = 0;
int max_bytes = MB_CUR_MAX;
- char buf[9];
+ char buf[ MB_CUR_MAX+ 1]; /* ("+1" not really needed?) */
char *buffer = NULL;
char *local_string = NULL;
+ size_t buffer_size; /* CVE-2022-0529 */
for (wsize = 0; wide_string[wsize]; wsize++) ;
if (max_bytes < MAX_ESCAPE_BYTES)
max_bytes = MAX_ESCAPE_BYTES;
-
- if ((buffer = (char *)malloc(wsize * max_bytes + 1)) == NULL) {
+ buffer_size = wsize * max_bytes + 1; /* Reused below. */
+ if ((buffer = (char *)malloc( buffer_size)) == NULL) {
return NULL;
}
@@ -2551,8 +2555,28 @@
} else {
/* no MB for this wide */
/* use escape for wide character */
- char *escape_string = wide_to_escape_string(wide_string[i]);
- strcat(buffer, escape_string);
+ size_t buffer_len;
+ size_t escape_string_len;
+ char *escape_string;
+ int err_msg = 0;
+
+ escape_string = wide_to_escape_string(wide_string[i]);
+ buffer_len = strlen( buffer);
+ escape_string_len = strlen( escape_string);
+
+ /* Append escape string, as space allows. */
+ /* 2022-07-18 SMS, et al. CVE-2022-0529 */
+ if (escape_string_len > buffer_size- buffer_len- 1)
+ {
+ escape_string_len = buffer_size- buffer_len- 1;
+ if (err_msg == 0)
+ {
+ err_msg = 1;
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString( UFilenameTooLongTrunc)));
+ }
+ }
+ strncat( buffer, escape_string, escape_string_len);
free(escape_string);
}
}
@@ -2604,9 +2628,18 @@
ZCONST char *utf8_string;
int escape_all;
{
- zwchar *wide = utf8_to_wide_string(utf8_string);
- char *loc = wide_to_local_string(wide, escape_all);
- free(wide);
+ zwchar *wide;
+ char *loc = NULL;
+
+ wide = utf8_to_wide_string( utf8_string);
+
+ /* 2022-07-25 SMS, et al. CVE-2022-0530 */
+ if (wide != NULL)
+ {
+ loc = wide_to_local_string( wide, escape_all);
+ free( wide);
+ }
+
return loc;
}