changeset 3848:2c2395fb6d85

6842838: 64-bit failure in handling invalid manifest in launcher. Summary: Don't compare with hard-coded 32-bit -1 when checking zip fields. Reviewed-by: ksrini
author kevinw
date Mon, 14 Sep 2009 20:55:08 +0100
parents 821abab95d38
children 4932fc1ba4cd
files jdk/src/share/bin/parse_manifest.c jdk/test/tools/launcher/6842838/CreateBadJar.java jdk/test/tools/launcher/6842838/Test6842838.sh
diffstat 3 files changed, 244 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/jdk/src/share/bin/parse_manifest.c	Mon Sep 14 17:47:26 2009 +0100
+++ b/jdk/src/share/bin/parse_manifest.c	Mon Sep 14 20:55:08 2009 +0100
@@ -59,7 +59,7 @@
     char        *out;
     z_stream    zs;
 
-    if (entry->csize == 0xffffffff || entry->isize == 0xffffffff)
+    if (entry->csize == (size_t) -1 || entry->isize == (size_t) -1 )
         return (NULL);
     if (lseek(fd, entry->offset, SEEK_SET) < (off_t)0)
         return (NULL);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/launcher/6842838/CreateBadJar.java	Mon Sep 14 20:55:08 2009 +0100
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * Borrowing significantly from Martin Buchholz's CorruptedZipFiles.java
+ *
+ * Needed a way of testing the checks for corrupt zip/jar entry in
+ * inflate_file from file j2se/src/share/bin/parse_manifest.c
+ * and running them with the 64-bit launcher. e.g.
+ * sparcv9/bin/java -jar badjar.jar
+ *
+ * Run from a script driver Test6842838.sh as we want to specifically run
+ * bin/sparcv9/java, the 64-bit launcher.
+ *
+ * So this program will create a zip file and damage it in the way
+ * required to tickle this bug.
+ *
+ * It will cause a buffer overrun: but that will not always crash.
+ * Use libumem preloaded by the script driver in order to
+ * abort quickly when the overrun happens.  That makes the test
+ * Solaris-specific.
+ */
+
+import java.util.*;
+import java.util.zip.*;
+import java.io.*;
+import static java.lang.System.*;
+import static java.util.zip.ZipFile.*;
+
+public class CreateBadJar {
+
+public static void main(String [] arguments) {
+
+        if (arguments.length != 2) {
+            throw new RuntimeException("Arguments: jarfilename entryname");
+        }
+        String outFile = arguments[0];
+        String entryName = arguments[1];
+
+        try {
+        // If the named file doesn't exist, create it.
+        // If it does, we are expecting it to contain the named entry, for
+        // alteration.
+        if (!new File(outFile).exists()) {
+          System.out.println("Creating file " + outFile);
+
+          // Create the requested zip/jar file.
+          ZipOutputStream zos = null;
+          zos = new ZipOutputStream(
+            new FileOutputStream(outFile));
+
+          ZipEntry e = new ZipEntry(entryName);
+          zos.putNextEntry(e);
+          for (int j=0; j<50000; j++) {
+            zos.write((int)'a');
+          }
+          zos.closeEntry();
+          zos.close();
+          zos = null;
+        }
+
+        // Read it.
+        int len = (int)(new File(outFile).length());
+        byte[] good = new byte[len];
+        FileInputStream fis = new FileInputStream(outFile);
+        fis.read(good);
+        fis.close();
+        fis = null;
+
+        int endpos = len - ENDHDR;
+        int cenpos = u16(good, endpos+ENDOFF);
+        if (u32(good, cenpos) != CENSIG) throw new RuntimeException("Where's CENSIG?");
+
+        byte[] bad;
+        bad = good.clone();
+
+        // Corrupt it...
+        int pos = findInCEN(bad, cenpos, entryName);
+
+        // What bad stuff are we doing to it?
+        // Store a 32-bit -1 in uncomp size.
+        bad[pos+0x18]=(byte)0xff;
+        bad[pos+0x19]=(byte)0xff;
+        bad[pos+0x1a]=(byte)0xff;
+        bad[pos+0x1b]=(byte)0xff;
+
+        // Bad work complete, delete the original.
+        new File(outFile).delete();
+
+        // Write it.
+        FileOutputStream fos = new FileOutputStream(outFile);
+        fos.write(bad);
+        fos.close();
+        fos = null;
+
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+}
+
+        /*
+         * Scan Central Directory File Headers looking for the named entry.
+         */
+
+    static int findInCEN(byte[] bytes, int cenpos, String entryName) {
+        int pos = cenpos;
+        int nextPos = 0;
+        String filename = null;
+        do {
+            if (nextPos != 0) {
+                pos = nextPos;
+            }
+            System.out.println("entry at pos = " + pos);
+            if (u32(bytes, pos) != CENSIG) throw new RuntimeException ("entry not found in CEN or premature end...");
+
+            int csize = u32(bytes, pos+0x14);          // +0x14 1 dword csize
+            int uncompsize = u32(bytes, pos+0x18);     // +0x18 1 dword uncomp size
+            int filenameLength = u16(bytes, pos+0x1c); // +0x1c 1 word length of filename
+            int extraLength = u16(bytes, pos+0x1e);    // +0x1e 1 world length of extra field
+            int commentLength = u16(bytes, pos+0x20);  // +0x20 1 world length of file comment
+            filename = new String(bytes, pos+0x2e, filenameLength); // +0x2e chars of filename
+            int offset = u32(bytes, pos+0x2a);         // +0x2a chars of filename
+
+            System.out.println("filename = " + filename + "\ncsize = " + csize +
+                               " uncomp.size = " + uncompsize +" file offset = " + offset);
+            nextPos =  pos + 0x2e + filenameLength + extraLength + commentLength;
+
+        } while (!filename.equals(entryName));
+
+        System.out.println("entry found at pos = " + pos);
+        return pos;
+    }
+
+    static int u8(byte[] data, int offset) {
+        return data[offset]&0xff;
+    }
+
+    static int u16(byte[] data, int offset) {
+        return u8(data,offset) + (u8(data,offset+1)<<8);
+    }
+
+    static int u32(byte[] data, int offset) {
+        return u16(data,offset) + (u16(data,offset+2)<<16);
+    }
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/launcher/6842838/Test6842838.sh	Mon Sep 14 20:55:08 2009 +0100
@@ -0,0 +1,75 @@
+#!/bin/sh -x
+
+#
+# @test @(#)Test6842838.sh
+# @bug 6842838
+# @summary Test 6842838 64-bit launcher failure due to corrupt jar
+# @run shell Test6842838.sh
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc.  All Rights Reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+# CA 95054 USA or visit www.sun.com if you need additional information or
+# have any questions.
+#
+
+if [ "${TESTSRC}" = "" ]
+then TESTSRC=.
+fi
+
+if [ "${TESTJAVA}" = "" ]
+then
+  PARENT=`dirname \`which java\``
+  TESTJAVA=`dirname ${PARENT}`
+  echo "TESTJAVA not set, selecting " ${TESTJAVA}
+  echo "If this is incorrect, try setting the variable manually."
+fi
+
+if [ "${TESTCLASSES}" = "" ]
+then
+  echo "TESTCLASSES not set.  Test cannot execute.  Failed."
+  exit 1
+fi
+
+# set platform-dependent variables
+OS=`uname -s`
+case "$OS" in
+  SunOS )
+    NULL=/dev/null
+    PS=":"
+    FS="/"
+    JAVA_EXE=${TESTJAVA}${FS}bin${FS}sparcv9${FS}java
+    ;;
+  * )
+    echo "Only testing on sparcv9 (use libumem to reliably catch buffer overrun)"
+    exit 0;
+    ;;
+esac
+
+BADFILE=newbadjar.jar
+
+${JAVA_EXE} -version
+rm -f ${BADFILE}
+${TESTJAVA}/bin/javac CreateBadJar.java
+${JAVA_EXE} CreateBadJar ${BADFILE} "META-INF/MANIFEST.MF"
+LD_PRELOAD=/lib/64/libumem.so ${JAVA_EXE} -jar ${BADFILE} > test.out 2>&1
+
+grep "Invalid or corrupt jarfile" test.out
+exit $?