1ed299
diff --git a/fileio.c b/fileio.c
1ed299
index 03fc4be..2a61a30 100644
1ed299
--- a/fileio.c
1ed299
+++ b/fileio.c
1ed299
@@ -176,6 +176,8 @@ static ZCONST char Far FilenameTooLongTrunc[] =
1ed299
 #endif
1ed299
 static ZCONST char Far ExtraFieldTooLong[] =
1ed299
   "warning:  extra field too long (%d).  Ignoring...\n";
1ed299
+static ZCONST char Far ExtraFieldCorrupt[] =
1ed299
+  "warning:  extra field (type: 0x%04x) corrupt.  Continuing...\n";
1ed299
 
1ed299
 #ifdef WINDLL
1ed299
    static ZCONST char Far DiskFullQuery[] =
1ed299
@@ -2300,7 +2302,13 @@ int do_string(__G__ length, option)   /* return PK-type error code */
1ed299
               length = length2;
1ed299
             }
1ed299
             /* Looks like here is where extra fields are read */
1ed299
-            getZip64Data(__G__ G.extra_field, length);
1ed299
+            if (getZip64Data(__G__ G.extra_field, length) != PK_COOL)
1ed299
+            {
1ed299
+                Info(slide, 0x401, ((char *)slide,
1ed299
+                 LoadFarString( ExtraFieldCorrupt), EF_PKSZ64));
1ed299
+                error = PK_WARN;
1ed299
+            }
1ed299
+
1ed299
 #ifdef UNICODE_SUPPORT
1ed299
             G.unipath_filename = NULL;
1ed299
             if (G.UzO.U_flag < 2) {
1ed299
diff --git a/process.c b/process.c
1ed299
index be6e006..0d57ab4 100644
1ed299
--- a/process.c
1ed299
+++ b/process.c
1ed299
@@ -1,5 +1,5 @@
1ed299
 /*
1ed299
-  Copyright (c) 1990-2009 Info-ZIP.  All rights reserved.
1ed299
+  Copyright (c) 1990-2014 Info-ZIP.  All rights reserved.
1ed299
 
1ed299
   See the accompanying file LICENSE, version 2009-Jan-02 or later
1ed299
   (the contents of which are also included in unzip.h) for terms of use.
1ed299
@@ -1894,48 +1894,83 @@ int getZip64Data(__G__ ef_buf, ef_len)
1ed299
     and a 4-byte version of disk start number.
1ed299
     Sets both local header and central header fields.  Not terribly clever,
1ed299
     but it means that this procedure is only called in one place.
1ed299
+
1ed299
+    2014-12-05 SMS.
1ed299
+    Added checks to ensure that enough data are available before calling
1ed299
+    makeint64() or makelong().  Replaced various sizeof() values with
1ed299
+    simple ("4" or "8") constants.  (The Zip64 structures do not depend
1ed299
+    on our variable sizes.)  Error handling is crude, but we should now
1ed299
+    stay within the buffer.
1ed299
   ---------------------------------------------------------------------------*/
1ed299
 
1ed299
+#define Z64FLGS 0xffff
1ed299
+#define Z64FLGL 0xffffffff
1ed299
+
1ed299
     if (ef_len == 0 || ef_buf == NULL)
1ed299
         return PK_COOL;
1ed299
 
1ed299
     Trace((stderr,"\ngetZip64Data: scanning extra field of length %u\n",
1ed299
       ef_len));
1ed299
 
1ed299
-    while (ef_len >= EB_HEADSIZE) {
1ed299
+    while (ef_len >= EB_HEADSIZE)
1ed299
+    {
1ed299
         eb_id = makeword(EB_ID + ef_buf);
1ed299
         eb_len = makeword(EB_LEN + ef_buf);
1ed299
 
1ed299
-        if (eb_len > (ef_len - EB_HEADSIZE)) {
1ed299
-            /* discovered some extra field inconsistency! */
1ed299
+        if (eb_len > (ef_len - EB_HEADSIZE))
1ed299
+        {
1ed299
+            /* Extra block length exceeds remaining extra field length. */
1ed299
             Trace((stderr,
1ed299
               "getZip64Data: block length %u > rest ef_size %u\n", eb_len,
1ed299
               ef_len - EB_HEADSIZE));
1ed299
             break;
1ed299
         }
1ed299
-        if (eb_id == EF_PKSZ64) {
1ed299
 
1ed299
+        if (eb_id == EF_PKSZ64)
1ed299
+        {
1ed299
           int offset = EB_HEADSIZE;
1ed299
 
1ed299
-          if (G.crec.ucsize == 0xffffffff || G.lrec.ucsize == 0xffffffff){
1ed299
-            G.lrec.ucsize = G.crec.ucsize = makeint64(offset + ef_buf);
1ed299
-            offset += sizeof(G.crec.ucsize);
1ed299
+          if ((G.crec.ucsize == Z64FLGL) || (G.lrec.ucsize == Z64FLGL))
1ed299
+          {
1ed299
+            if (offset+ 8 > ef_len)
1ed299
+              return PK_ERR;
1ed299
+
1ed299
+            G.crec.ucsize = G.lrec.ucsize = makeint64(offset + ef_buf);
1ed299
+            offset += 8;
1ed299
           }
1ed299
-          if (G.crec.csize == 0xffffffff || G.lrec.csize == 0xffffffff){
1ed299
-            G.csize = G.lrec.csize = G.crec.csize = makeint64(offset + ef_buf);
1ed299
-            offset += sizeof(G.crec.csize);
1ed299
+
1ed299
+          if ((G.crec.csize == Z64FLGL) || (G.lrec.csize == Z64FLGL))
1ed299
+          {
1ed299
+            if (offset+ 8 > ef_len)
1ed299
+              return PK_ERR;
1ed299
+
1ed299
+            G.csize = G.crec.csize = G.lrec.csize = makeint64(offset + ef_buf);
1ed299
+            offset += 8;
1ed299
           }
1ed299
-          if (G.crec.relative_offset_local_header == 0xffffffff){
1ed299
+
1ed299
+          if (G.crec.relative_offset_local_header == Z64FLGL)
1ed299
+          {
1ed299
+            if (offset+ 8 > ef_len)
1ed299
+              return PK_ERR;
1ed299
+
1ed299
             G.crec.relative_offset_local_header = makeint64(offset + ef_buf);
1ed299
-            offset += sizeof(G.crec.relative_offset_local_header);
1ed299
+            offset += 8;
1ed299
           }
1ed299
-          if (G.crec.disk_number_start == 0xffff){
1ed299
+
1ed299
+          if (G.crec.disk_number_start == Z64FLGS)
1ed299
+          {
1ed299
+            if (offset+ 4 > ef_len)
1ed299
+              return PK_ERR;
1ed299
+
1ed299
             G.crec.disk_number_start = (zuvl_t)makelong(offset + ef_buf);
1ed299
-            offset += sizeof(G.crec.disk_number_start);
1ed299
+            offset += 4;
1ed299
           }
1ed299
+#if 0
1ed299
+          break;                /* Expect only one EF_PKSZ64 block. */
1ed299
+#endif /* 0 */
1ed299
         }
1ed299
 
1ed299
-        /* Skip this extra field block */
1ed299
+        /* Skip this extra field block. */
1ed299
         ef_buf += (eb_len + EB_HEADSIZE);
1ed299
         ef_len -= (eb_len + EB_HEADSIZE);
1ed299
     }