aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Clausecker <fuz@FreeBSD.org>2026-08-14 09:56:03 +0000
committerRobert Clausecker <fuz@FreeBSD.org>2026-08-15 19:34:20 +0000
commit720785f14ad0d6244f8295885be22f72cbb4e385 (patch)
treeb8f5f82deaadd09f2d54fac6625b20c5b2504a1e
parent9ecd12491de6f966d30840a4b4c34f187cf30432 (diff)
archivers/zip: fix command injection vulnerability
Insufficient quoting in the -T option gave rise to the possibility of a command injection. Apply a fix from the Debian project. Reported by: nimaje (via IRC) See also: https://sintonen.fi/advisories/infozip-test-option-command-injection.txt MFH: 2026Q3 (cherry picked from commit 7a7406eab8d872fe5549010305c451e0959db57c)
-rw-r--r--archivers/zip/Makefile2
-rw-r--r--archivers/zip/files/patch-zip.c227
2 files changed, 224 insertions, 5 deletions
diff --git a/archivers/zip/Makefile b/archivers/zip/Makefile
index eb392156abf8..8deeb930dd21 100644
--- a/archivers/zip/Makefile
+++ b/archivers/zip/Makefile
@@ -1,6 +1,6 @@
PORTNAME= zip
PORTVERSION= 3.0
-PORTREVISION= 5
+PORTREVISION= 6
CATEGORIES= archivers
MASTER_SITES= SF/info${PORTNAME}/Zip%203.x%20%28latest%29/${PORTVERSION}
DISTNAME= ${PORTNAME}${PORTVERSION:S/.//g}
diff --git a/archivers/zip/files/patch-zip.c b/archivers/zip/files/patch-zip.c
index d81182e3baf1..fb7e7a7e2a03 100644
--- a/archivers/zip/files/patch-zip.c
+++ b/archivers/zip/files/patch-zip.c
@@ -12,9 +12,22 @@ Forwarded: https://sourceforge.net/p/infozip/bugs/81/
strlen(unzip_path) + strlen(zipname) + " " + "'" + "'" + '\0'
The additional space required in the `cmd` buffer is 4, not 3.
+From: Paul Marquess <pmqs@outlook.com>
+Subject: Fix command injection issue
+Bug-Debian: https://bugs.debian.org/1143866
+X-Debian-version: 3.0-16
+
--- zip.c.orig 2008-07-05 16:34:06 UTC
+++ zip.c
-@@ -1028,7 +1028,7 @@ local void help_extended()
+@@ -122,6 +122,7 @@ local int finish OF((int));
+
+ local void freeup OF((void));
+ local int finish OF((int));
++local char *quote_arg(char *instring);
+ #if (!defined(MACOS) && !defined(WINDLL))
+ local void handler OF((int));
+ local void license OF((void));
+@@ -1028,7 +1029,7 @@ local void help_extended()
for (i = 0; i < sizeof(text)/sizeof(char *); i++)
{
@@ -23,7 +36,7 @@ The additional space required in the `cmd` buffer is 4, not 3.
putchar('\n');
}
#ifdef DOS
-@@ -1225,7 +1225,7 @@ local void version_info()
+@@ -1225,7 +1226,7 @@ local void version_info()
CR_MAJORVER, CR_MINORVER, CR_BETA_VER, CR_VERSION_DATE);
for (i = 0; i < sizeof(cryptnote)/sizeof(char *); i++)
{
@@ -32,12 +45,218 @@ The additional space required in the `cmd` buffer is 4, not 3.
putchar('\n');
}
++i; /* crypt support means there IS at least one compilation option */
-@@ -1437,7 +1437,7 @@ local void check_zipfile(zipname, zippath)
+@@ -1323,6 +1324,134 @@ local int check_unzip_version(unzippath)
+ return 1;
+ }
+
++
++/* quote_arg()
++ *
++ * Add quotation and/or escapes to a shell (VMS: DCL) argument string
++ * appropriate to the local operating system or shell (Unix, Windows,
++ * etc.). This is mainly used to build the command line to pass to
++ * UnZip (or other application when -TT used) to test an archive.
++ * Return malloc()'d result.
++ *
++ * All: Add " at beginning and end.
++ * MSDOS: % -> "^%"
++ * " -> \""
++ * Unix: ! -> "'!'"
++ * $ -> \$
++ * \ -> \\
++ * ` -> \`
++ * Non-VMS: " -> \"
++ * VMS: " -> """
++ *
++ * On VMS, quoted double apostrophes are also special. Currently not
++ * handled. (How? Quotation marks are needed for (upper-)case
++ * preservation. Double apostrophes in quotation marks are interpreted
++ * (symbol evaluation). SMS sees no way to handle "fr''ed". "fr'""'ed"
++ * becomes >fr'"'ed<, for example.) Not a problem for file specs, but
++ * imposes a restriction on passwords.
++ */
++#ifndef NO_PROTO
++local char *quote_arg(char *instring)
++#else
++local char *quote_arg(instring)
++ char *instring;
++#endif
++{
++ int i;
++ int j;
++ char *tempstring;
++ char *outstring;
++ char c;
++
++ if (instring == NULL)
++ return NULL;
++
++# ifdef MSDOS
++# define QA_FACTOR 4 /* Worst case (MSDOS): % -> "^%" */
++
++# else /* not MSDOS */
++# ifdef VMS
++# define QA_FACTOR 3 /* Worst case (VMS): " -> """ */
++
++# else /* not MSDOS or VMS */
++# define QA_FACTOR 5 /* Worst case (Unix): ! -> "'!'" */
++# endif /* VMS [else] */
++# endif /* MSDOS [else] */
++
++# define QA_INCR 2 /* Surrounding quotation marks. */
++
++ i = QA_FACTOR * (int)strlen(instring) + QA_INCR + 1;
++ if ((tempstring = (char *)malloc(i)) == NULL) {
++ ZIPERR(ZE_MEM, "quote_arg");
++ }
++
++ j = 0;
++
++ tempstring[j++] = '\"'; /* Surrounding quotation mark (start). */
++
++ for (i = 0; instring[i]; i++) {
++ c = instring[i];
++
++# ifdef MSDOS /* or Windows */
++ if (c == '%') /* Percent. */
++ {
++ tempstring[j++] = '"'; /* Add (closing) quotation mark. */
++ tempstring[j++] = '^'; /* Add caret escape. */
++ tempstring[j++] = '%'; /* Original character (%). */
++ c = '"'; /* Prepare (re-opening) quotation mark. */
++ }
++ else if (c == '"') /* Quotation mark. */
++ {
++ tempstring[j++] = '\\'; /* Add backslash (escape). */
++ tempstring[j++] = '"'; /* Add quote (acts as closing and literal). */
++ }
++# else /* not def MSDOS */
++
++# ifdef VMS
++ if (c == '"') /* Quotation mark. */
++ {
++ tempstring[j++] = '"'; /* Add two quotation marks. */
++ tempstring[j++] = '"';
++ }
++# else /* not def VMS */
++
++ /* UNIX is default for others */
++
++ if (c == '"') /* Quotation mark. */
++ {
++ tempstring[j++] = '\\'; /* Add backslash (escape). */
++ }
++ else if (c == '!') /* Exclamation. (Inefficient.) */
++ {
++ tempstring[j++] = '"'; /* Add (closing) quotation mark. */
++ tempstring[j++] = '\''; /* Add (opening) apostrophe. */
++ tempstring[j++] = '!'; /* Original character (!). */
++ tempstring[j++] = '\''; /* Add (closing) apostrophe. */
++ c = '"'; /* Prepare (re-opening) quotation mark. */
++ }
++ else if ((c == '$') || /* Dollar sign. */
++ (c == '`') || /* Grave accent (backtick). */
++ (c == '\\')) /* Backslash. */
++ {
++ tempstring[j++] = '\\'; /* Add backslash (escape). */
++ }
++
++# endif /* def VMS [else] */
++# endif /* def MSDOS [else] */
++
++ tempstring[j++] = c; /* Original (or other last) character. */
++ }
++
++ tempstring[j++] = '\"'; /* Surrounding quotation mark (end). */
++
++ tempstring[j] = '\0';
++ /* outstring = string_dup(tempstring, "quote_arg", NO_FLUFF); */
++ outstring = strdup(tempstring);
++ free(tempstring);
++
++ return outstring;
++}
++
+ local void check_zipfile(zipname, zippath)
+ char *zipname;
+ char *zippath;
+@@ -1424,11 +1553,15 @@ local void check_zipfile(zipname, zippath)
+
+ #else /* (MSDOS && !__GO32__) || __human68k__ */
+ char *cmd;
++ char *qzipname;
+ int result;
+
+ /* Tell picky compilers to shut up about unused variables */
+ zippath = zippath;
+
++ /* Quote each arg (and add appropriate escapes). */
++ qzipname = quote_arg(zipname);
++
+ if (unzip_path) {
+ /* user gave us a path to some unzip (may not be UnZip) */
+ char *here;
+@@ -1437,7 +1570,7 @@ local void check_zipfile(zipname, zippath)
/* Replace first {} with archive name. If no {} append name to string. */
here = strstr(unzip_path, "{}");
- if ((cmd = malloc(strlen(unzip_path) + strlen(zipname) + 3)) == NULL) {
-+ if ((cmd = malloc(strlen(unzip_path) + strlen(zipname) + 4)) == NULL) {
++ if ((cmd = malloc(strlen(unzip_path) + strlen(qzipname) + 4)) == NULL) {
+ ziperr(ZE_MEM, "building command string for testing archive");
+ }
+
+@@ -1447,32 +1580,20 @@ local void check_zipfile(zipname, zippath)
+ strcpy(cmd, unzip_path);
+ cmd[len] = '\0';
+ strcat(cmd, " ");
+-# ifdef UNIX
+- strcat(cmd, "'"); /* accept space or $ in name */
+- strcat(cmd, zipname);
+- strcat(cmd, "'");
+-# else
+- strcat(cmd, zipname);
+-# endif
++ strcat(cmd, qzipname);
+ strcat(cmd, " ");
+ strcat(cmd, here + 2);
+ } else {
+ /* No {} so append temp name to end */
+ strcpy(cmd, unzip_path);
+ strcat(cmd, " ");
+-# ifdef UNIX
+- strcat(cmd, "'"); /* accept space or $ in name */
+- strcat(cmd, zipname);
+- strcat(cmd, "'");
+-# else
+- strcat(cmd, zipname);
+-# endif
++ strcat(cmd, qzipname);
+ }
+ free(unzip_path);
+ unzip_path = NULL;
+
+ } else {
+- if ((cmd = malloc(20 + strlen(zipname))) == NULL) {
++ if ((cmd = malloc(20 + strlen(qzipname))) == NULL) {
ziperr(ZE_MEM, "building command string for testing archive");
}
+@@ -1484,14 +1605,11 @@ local void check_zipfile(zipname, zippath)
+ if (check_unzip_version("unzip") == 0)
+ ZIPERR(ZE_TEST, zipfile);
+
+-# ifdef UNIX
+- strcat(cmd, "'"); /* accept space or $ in name */
+- strcat(cmd, zipname);
+- strcat(cmd, "'");
+-# else
+- strcat(cmd, zipname);
+-# endif
++ strcat(cmd, qzipname);
+ }
++
++ if (qzipname)
++ free(qzipname);
+
+ result = system(cmd);
+ # ifdef VMS