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;
 }
 
