6733959: Insufficient checks for "Main-Class" manifest entry in JAR files
Summary: Fixes a buffer overrun problem with a very long Main-Class attribute.
Reviewed-by: darcy
--- a/jdk/src/share/bin/emessages.h Wed Oct 01 10:01:45 2008 +0800
+++ b/jdk/src/share/bin/emessages.h Thu Sep 04 09:43:32 2008 -0700
@@ -54,6 +54,7 @@
#define CLS_ERROR2 "Error: Failed to load Main Class: %s\n%s"
#define CLS_ERROR3 "Error: No main method found in specified class.\n" GEN_ERROR
#define CLS_ERROR4 "Error: Main method not public\n" GEN_ERROR
+#define CLS_ERROR5 "Error: main-class: attribute exceeds system limits of %d bytes\n" GEN_ERROR
#define CFG_WARN1 "Warning: %s VM not supported; %s VM will be used"
#define CFG_WARN2 "Warning: No leading - on line %d of `%s'"
--- a/jdk/src/share/bin/java.c Wed Oct 01 10:01:45 2008 +0800
+++ b/jdk/src/share/bin/java.c Thu Sep 04 09:43:32 2008 -0700
@@ -987,8 +987,14 @@
* to avoid locating, expanding and parsing the manifest extra
* times.
*/
- if (info.main_class != NULL)
- (void)JLI_StrCat(env_entry, info.main_class);
+ if (info.main_class != NULL) {
+ if (JLI_StrLen(info.main_class) <= MAXNAMELEN) {
+ (void)JLI_StrCat(env_entry, info.main_class);
+ } else {
+ ReportErrorMessage(CLS_ERROR5, MAXNAMELEN);
+ exit(1);
+ }
+ }
(void)putenv(env_entry);
ExecJRE(jre, new_argv);
JLI_FreeManifest();
--- a/jdk/test/tools/launcher/MultipleJRE.sh Wed Oct 01 10:01:45 2008 +0800
+++ b/jdk/test/tools/launcher/MultipleJRE.sh Thu Sep 04 09:43:32 2008 -0700
@@ -1,14 +1,14 @@
# @test MultipleJRE.sh
-# @bug 4811102 4953711 4955505 4956301 4991229 4998210 5018605 6387069
+# @bug 4811102 4953711 4955505 4956301 4991229 4998210 5018605 6387069 6733959
# @build PrintVersion
# @build UglyPrintVersion
+# @build ZipMeUp
# @run shell MultipleJRE.sh
# @summary Verify Multiple JRE version support
# @author Joseph E. Kowalski
-
#
-# Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved.
+# Copyright 2003-2008 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
@@ -49,11 +49,26 @@
exit 1
fi
+JAVAEXE="$TESTJAVA/bin/java"
JAVA="$TESTJAVA/bin/java -classpath $TESTCLASSES"
JAR="$TESTJAVA/bin/jar"
OS=`uname -s`;
#
+# Tests whether we are on windows (true) or not.
+#
+IsWindows() {
+ case "$OS" in
+ Windows* | CYGWIN* )
+ printf "true"
+ ;;
+ * )
+ printf "false"
+ ;;
+ esac
+}
+
+#
# Shell routine to test for the proper rejection of syntactically incorrect
# version specifications.
#
@@ -139,7 +154,6 @@
$PACKAGE/UglyPrintVersion.class
}
-
#
# Constructs a jar file with a fair number of "zip directory" entries and
# the MANIFEST.MF entry at or near the end of that directory to validate
@@ -262,6 +276,29 @@
fi
}
+# Tests very long Main-Class attribute in the jar
+TestLongMainClass() {
+ JVER=$1
+ if [ "$JVER" = "mklink" ]; then
+ JVER=XX
+ JDKXX=jdk/j2re$JVER
+ rm -rf jdk
+ mkdir jdk
+ ln -s $TESTJAVA $JDKXX
+ JAVA_VERSION_PATH="`pwd`/jdk"
+ export JAVA_VERSION_PATH
+ fi
+ $JAVAEXE -cp $TESTCLASSES ZipMeUp UglyBetty.jar 4097
+ message="`$JAVAEXE -version:$JVER -jar UglyBetty.jar 2>&1`"
+ echo $message | grep "Error: main-class: attribute exceeds system limits" > /dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ printf "Long manifest test did not get expected error"
+ exit 1
+ fi
+ unset JAVA_VERSION_PATH
+ rm -rf jdk
+}
+
#
# Main test sequence starts here
#
@@ -280,14 +317,11 @@
LaunchVM "" "${RELEASE}"
CreateJar "" "0"
LaunchVM "" "${RELEASE}"
-case "$OS" in
- Windows* | CYGWIN* )
- MAXIMUM_PATH=255;
- ;;
- *)
- MAXIMUM_PATH=1024;
- ;;
-esac
+if [ `IsWindows` = "true" ]; then
+ MAXIMUM_PATH=255;
+else
+ MAXIMUM_PATH=1024;
+fi
PATH_LENGTH=`printf "%s" "$UGLYCLASS" | wc -c`
if [ ${PATH_LENGTH} -lt ${MAXIMUM_PATH} ]; then
@@ -346,7 +380,6 @@
LaunchVM "" "${RELEASE}"
fi
-
#
# Throw some syntactically challenged (illegal) version specifiers at
# the interface. Failure (of the launcher) is success for the test.
@@ -357,15 +390,28 @@
TestSyntax "1.2+.3" # Embedded modifier
TestSyntax "1.2.4+&1.2*&1++" # Long and invalid
+# On windows we see if there is another jre installed, usually
+# there is, then we test using that, otherwise links are created
+# to get through to SelectVersion.
+if [ `IsWindows` = "false" ]; then
+ TestLongMainClass "mklink"
+else
+ $JAVAEXE -version:1.0+
+ if [ $? -eq 0 ]; then
+ TestLongMainClass "1.0+"
+ else
+ printf "Warning: TestLongMainClass skipped as there is no"
+ printf "viable MJRE installed.\n"
+ fi
+fi
+
#
# Because scribbling in the registry can be rather destructive, only a
# subset of the tests are run on Windows.
#
-case "$OS" in
- Windows* | CYGWIN* )
- exit 0;
- ;;
-esac
+if [ `IsWindows` = "true" ]; then
+ exit 0;
+fi
#
# Additional version specifiers containing spaces. (Sigh, unable to
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/launcher/ZipMeUp.java Thu Sep 04 09:43:32 2008 -0700
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2008 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.
+ */
+
+/**
+ * A simple class to create our erring Jar with a very long Main-Class
+ * attribute in the manifest.
+ */
+import java.io.ByteArrayOutputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.zip.CRC32;
+import java.util.zip.CheckedOutputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+public class ZipMeUp {
+
+ static final CRC32 crc = new CRC32();
+
+ private static String SOME_KLASS = ".Some";
+
+ static byte[] getManifestAsBytes(int nchars) throws IOException {
+ crc.reset();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ CheckedOutputStream cos = new CheckedOutputStream(baos, crc);
+ PrintStream ps = new PrintStream(cos);
+ ps.println("Manifest-Version: 1.0");
+ ps.print("Main-Class: ");
+ for (int i = 0 ; i < nchars - SOME_KLASS.length() ; i++) {
+ ps.print(i%10);
+ }
+ ps.println(SOME_KLASS);
+ cos.flush();
+ cos.close();
+ ps.close();
+ return baos.toByteArray();
+ }
+
+ /**
+ * The arguments are: filename_to_create length
+ * @param args
+ * @throws java.lang.Exception
+ */
+ public static void main(String...args) throws Exception {
+ FileOutputStream fos = new FileOutputStream(args[0]);
+ ZipOutputStream zos = new ZipOutputStream(fos);
+ byte[] manifest = getManifestAsBytes(Integer.parseInt(args[1]));
+ ZipEntry ze = new ZipEntry("META-INF/MANIFEST.MF");
+ ze.setMethod(ZipEntry.STORED);
+ ze.setSize(manifest.length);
+ ze.setCompressedSize(manifest.length);
+ ze.setCrc(crc.getValue());
+ ze.setTime(System.currentTimeMillis());
+ zos.putNextEntry(ze);
+ zos.write(manifest);
+ zos.flush();
+
+ // add a zero length class
+ ze = new ZipEntry(SOME_KLASS + ".class");
+ ze.setMethod(ZipEntry.STORED);
+ ze.setSize(0);
+ ze.setCompressedSize(0);
+ ze.setCrc(0);
+ ze.setTime(System.currentTimeMillis());
+ zos.putNextEntry(ze);
+ zos.flush();
+ zos.closeEntry();
+ zos.close();
+ System.exit(0);
+ }
+}