unzip/CVE-2019-13232-fur2.patch
2020-03-02 21:33:36 +08:00

338 lines
13 KiB
Diff

From b701988480151e6693343ecdb246092824604c61 Mon Sep 17 00:00:00 2001
From: wangshouping <wangshouping@huawei.com>
Date: Tue, 11 Feb 2020 19:07:28 -0500
Subject: [PATCH] add param to limit the number of overlap files
Signed-off-by: wangshouping <wangshouping@huawei.com>
---
extract.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++--------------
man/unzip.1 | 8 +++--
unzip.c | 84 +++++++++++++++++++++++++++++++++++++++-----
unzip.h | 1 +
unzip.txt | 6 +++-
5 files changed, 176 insertions(+), 37 deletions(-)
diff --git a/extract.c b/extract.c
index 3a01d13..031efdb 100644
--- a/extract.c
+++ b/extract.c
@@ -340,23 +340,32 @@ 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) */
+ unsigned long count;
} 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)
+static size_t cover_find(cover, val, op)
cover_t *cover;
bound_t val;
+ int op;
{
size_t lo = 0, hi = cover->num;
+ bound_t tmp_val;
while (lo < hi) {
size_t mid = (lo + hi) >> 1;
- if (val < cover->span[mid].beg)
- hi = mid;
- else
- lo = mid + 1;
+ if (!op) {
+ tmp_val = cover->span[mid].beg;
+ } else {
+ tmp_val = cover->span[mid].end;
+ }
+ if (val < tmp_val) {
+ hi = mid;
+ } else {
+ lo = mid + 1;
+ }
}
return hi;
}
@@ -366,10 +375,16 @@ static int cover_within(cover, val)
cover_t *cover;
bound_t val;
{
- size_t pos = cover_find(cover, val);
+ size_t pos = cover_find(cover, val, 0);
return pos > 0 && val < cover->span[pos - 1].end;
}
+static int is_exceed_max_overlaps(cover, val)
+ cover_t *cover;
+{
+ return cover->count >= G.UzO.max_overlaps;
+}
+
/*
* 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
@@ -387,7 +402,8 @@ static int cover_add(cover, beg, end)
bound_t beg;
bound_t end;
{
- size_t pos;
+ size_t pos_beg;
+ size_t pos_end;
int prec, foll;
if (beg >= end)
@@ -396,31 +412,76 @@ static int cover_add(cover, beg, end)
/* 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;
+ pos_beg = cover_find(cover, beg, 0);
+ pos_end = cover_find(cover, end, 1);
/* Check for adjacencies. */
- prec = pos > 0 && beg == cover->span[pos - 1].end;
- foll = pos < cover->num && end == cover->span[pos].beg;
+ prec = pos_beg > 0 && beg <= cover->span[pos_beg - 1].end;
+ foll = pos_beg < cover->num && end >= cover->span[pos_beg].beg;
if (prec && foll) {
+ if (beg < cover->span[pos_beg - 1].end || end > cover->span[pos_beg].beg) {
+ cover->count++;
+ }
+
/* 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));
+ if (end <= cover->span[pos_beg].end) {
+ cover->span[pos_beg - 1].end = cover->span[pos_beg].end;
+ cover->num--;
+ memmove(cover->span + pos_beg, cover->span + pos_beg + 1,
+ (cover->num - pos_beg) * sizeof(span_t));
+ } else {
+ if (pos_end == cover->num) {
+ cover->span[pos_beg - 1].end = end;
+ cover->num = cover->num - (pos_end - pos_beg);
+ } else if (end >= cover->span[pos_end].beg) {
+ cover->span[pos_beg - 1].end = cover->span[pos_end].end;
+ memmove(cover->span + pos_beg, cover->span + pos_end + 1,
+ (cover->num - 1 - pos_end) * sizeof(span_t));
+ cover->num = cover->num - (pos_end - pos_beg) - 1;
+ } else {
+ cover->span[pos_beg - 1].end = end;
+ memmove(cover->span + pos_beg, cover->span + pos_end,
+ (cover->num - 1 - pos_end + 1) * sizeof(span_t));
+ cover->num = cover->num - (pos_end - pos_beg);
+ }
+ }
}
- else if (prec)
+ 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)
+ if (beg < cover->span[pos_beg - 1].end) {
+ cover->count++;
+ }
+ if (end > cover->span[pos_beg - 1].end) {
+ cover->span[pos_beg - 1].end = end;
+ }
+ }
+ else if (foll) {
+ if (end > cover->span[pos_beg].beg) {
+ cover->count++;
+ }
/* The new span is adjacent only to the following span. Extend the
beginning of the following span. */
- cover->span[pos].beg = beg;
+ cover->span[pos_beg].beg = beg;
+ if (end > cover->span[pos_beg].end) {
+ if (pos_end == cover->num) {
+ cover->span[pos_beg].end = end;
+ cover->num = cover->num - (pos_end - pos_beg) + 1;
+ } else if (end >= cover->span[pos_end].beg) {
+ cover->span[pos_beg].end = cover->span[pos_end].end;
+ memmove(cover->span + pos_beg + 1, cover->span + pos_end + 1,
+ (cover->num - 1 - pos_end) * sizeof(span_t));
+ cover->num = cover->num - (pos_end - pos_beg);
+ } else {
+ cover->span[pos_beg].end = end;
+ memmove(cover->span + pos_beg + 1, cover->span + pos_end,
+ (cover->num - 1 - pos_end + 1) * sizeof(span_t));
+ cover->num = cover->num - (pos_end - pos_beg) + 1;
+ }
+ }
+ }
else {
/* The new span has gaps between both the preceding and the following
spans. Assure that there is room and insert the span. */
@@ -432,11 +493,11 @@ static int cover_add(cover, beg, end)
cover->span = span;
cover->max = max;
}
- memmove(cover->span + pos + 1, cover->span + pos,
- (cover->num - pos) * sizeof(span_t));
+ memmove(cover->span + pos_beg + 1, cover->span + pos_beg,
+ (cover->num - pos_beg) * sizeof(span_t));
cover->num++;
- cover->span[pos].beg = beg;
- cover->span[pos].end = end;
+ cover->span[pos_beg].beg = beg;
+ cover->span[pos_beg].end = end;
}
return 0;
}
@@ -511,6 +572,7 @@ int extract_or_test_files(__G) /* return PK-type error code */
((cover_t *)G.cover)->max = 0;
}
((cover_t *)G.cover)->num = 0;
+ ((cover_t *)G.cover)->count = 0;
if (cover_add((cover_t *)G.cover,
G.extra_bytes + G.ecrec.offset_start_central_directory,
G.extra_bytes + G.ecrec.offset_start_central_directory +
@@ -1218,7 +1280,7 @@ static int extract_or_test_entrylist(__G__ numchunk,
/* seek_zipf(__G__ pInfo->offset); */
request = G.pInfo->offset + G.extra_bytes;
- if (cover_within((cover_t *)G.cover, request)) {
+ if (is_exceed_max_overlaps((cover_t *)G.cover)) {
Info(slide, 0x401, ((char *)slide,
LoadFarString(OverlappedComponents)));
return PK_BOMB;
diff --git a/man/unzip.1 b/man/unzip.1
index 21816d1..a637a14 100644
--- a/man/unzip.1
+++ b/man/unzip.1
@@ -25,7 +25,7 @@
unzip \- list, test and extract compressed files in a ZIP archive
.PD
.SH SYNOPSIS
-\fBunzip\fP [\fB\-Z\fP] [\fB\-cflptTuvz\fP[\fBabjnoqsCDKLMUVWX$/:^\fP]]
+\fBunzip\fP [\fB\-Z\fP] [\fB\-cflptTuvz\fP[\fBabjnoqsCDKLMUVWX$/:^\fP][\fB\-g num\fP]]
\fIfile\fP[\fI.zip\fP] [\fIfile(s)\fP\ .\|.\|.]
[\fB\-x\fP\ \fIxfile(s)\fP\ .\|.\|.] [\fB\-d\fP\ \fIexdir\fP]
.PD
@@ -195,6 +195,10 @@ but will be in future releases.
.TP
.B \-z
display only the archive comment.
+.IP \fB\-g\fP\ \fInum\fP
+limit the number of overlap files. When the number of
+overlap files exceeds the num we set, it is a bomb. the num
+is a decimal number.
.PD
.\" =========================================================================
.SH MODIFIERS
diff --git a/unzip.c b/unzip.c
index 5b7d288..8c4c37e 100644
--- a/unzip.c
+++ b/unzip.c
@@ -601,7 +601,7 @@ Latest sources and executables are at ftp://ftp.info-zip.org/pub/infozip/ ;\
\n file[.zip] may be a wildcard. %s\n";
#else /* !VM_CMS */
static ZCONST char Far UnzipUsageLine2[] = "\
-Usage: unzip %s[-opts[modifiers]] file[.zip] [list] [-x xlist] [-d exdir]\n \
+Usage: unzip %s[-opts[modifiers][-g num]] file[.zip] [list] [-x xlist] [-d exdir]\n \
Default action is to extract files in list, except those in xlist, to exdir;\n\
file[.zip] may be a wildcard. %s\n";
#endif /* ?VM_CMS */
@@ -647,7 +648,8 @@ static ZCONST char Far UnzipUsageLine3[] = "\n\
-f freshen existing files, create none -t test compressed archive data\n\
-u update files, create if necessary -z display archive comment only\n\
-v list verbosely/show version info %s\n\
- -x exclude files that follow (in xlist) -d extract files into exdir\n";
+ -x exclude files that follow (in xlist) -d extract files into exdir\n\
+ -g limit the number of overlap files\n";
#endif /* ?VM_CMS */
#endif /* ?MACOS */
@@ -1367,7 +1414,7 @@ int uz_opts(__G__ pargc, pargv)
extern char OEM_CP[MAX_CP_NAME];
extern char ISO_CP[MAX_CP_NAME];
#endif
-
+ uO.max_overlaps = (unsigned long)(-1); /* if not set, uncheck overlaps */
while (++argv, (--argc > 0 && *argv != NULL && **argv == '-')) {
s = *argv + 1;
while ((c = *s++) != 0) { /* "!= 0": prevent Turbo C warning */
@@ -1528,6 +1575,26 @@ int uz_opts(__G__ pargc, pargv)
uO.acorn_nfs_ext = TRUE;
break;
#endif /* RISCOS || ACORN_FTYPE_NFS */
+#ifdef UNIX
+ case('g'): /* set overlap entries */
+ if (negative) { // invalid param, eg: --g
+ Info(slide, 0x401, ((char *)slide,
+ "error: invalid param, eg: unzip --g"));
+ return(PK_PARAM);
+ } else {
+ if (argc > 1) {
+ char *leftover;
+ --argc;
+ ++argv;
+ uO.max_overlaps = strtoul(*argv, &leftover, 10);
+ } else { /* else pwdarg points at decryption password */
+ Info(slide, 0x401, ((char *)slide,
+ "error: invalid param, -g need add decimal number"));
+ return(PK_PARAM);
+ }
+ }
+ break;
+#endif
case ('h'): /* just print help message and quit */
if (showhelp == 0) {
#ifndef SFX
@@ -2235,6 +2302,7 @@ static void help_extended(__G)
" information. Also can be added to other list commands for more",
" verbose output.",
" -z Display only archive comment.",
+ " -g Limit the number of overlap files.",
"",
"unzip modifiers:",
" -a Convert text files to local OS format. Convert line ends, EOF",
diff --git a/unzip.h b/unzip.h
index ed24a5b..a7e8a64 100644
--- a/unzip.h
+++ b/unzip.h
@@ -560,6 +560,7 @@ typedef struct _UzpOpts {
int cflxflag; /* -^: allow control chars in extracted filenames */
#endif
#endif /* !FUNZIP */
+ unsigned long max_overlaps; /* Maximum number of overlaps allowed */
} UzpOpts;
/* intended to be a private struct: */
diff --git a/unzip.txt b/unzip.txt
index e8e9719..6594ee6 100644
--- a/unzip.txt
+++ b/unzip.txt
@@ -4,7 +4,7 @@ NAME
unzip - list, test and extract compressed files in a ZIP archive
SYNOPSIS
- unzip [-Z] [-cflptTuvz[abjnoqsCDKLMUVWX$/:^]] file[.zip] [file(s) ...]
+ unzip [-Z] [-cflptTuvz[abjnoqsCDKLMUVWX$/:^][-g num]] file[.zip] [file(s) ...]
[-x xfile(s) ...] [-d exdir]
DESCRIPTION
@@ -177,6 +177,10 @@ OPTIONS
implemented but will be in future releases.
-z display only the archive comment.
+ -g num
+ limit the number of overlap files. When the number of overlap f-
+ iles exceeds the num we set, it is a bomb. the num is a decimal
+ number.
MODIFIERS
-a convert text files. Ordinarily all files are extracted exactly
--
1.8.3.1