aboutsummaryrefslogtreecommitdiffstats
path: root/netx
diff options
context:
space:
mode:
authorJiri Vanek <[email protected]>2013-04-17 14:22:01 +0200
committerJiri Vanek <[email protected]>2013-04-17 14:22:01 +0200
commit72ac500dc654bbc82332712022cca573db0bc3e6 (patch)
tree2c6e9d8702ba39d30f0daad5d00dd9edbfcb5a10 /netx
parent8b462c07f200a80028ffc59027a291837fcf2f1b (diff)
Fixed gifar vulnereability with automated testcase
Diffstat (limited to 'netx')
-rw-r--r--netx/net/sourceforge/jnlp/Launcher.java2
-rw-r--r--netx/net/sourceforge/jnlp/resources/Messages.properties1
-rw-r--r--netx/net/sourceforge/jnlp/resources/Messages_cs_CZ.properties1
-rw-r--r--netx/net/sourceforge/jnlp/runtime/Boot.java4
-rw-r--r--netx/net/sourceforge/jnlp/runtime/CachedJarFileCallback.java12
-rw-r--r--netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java4
-rw-r--r--netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java22
-rw-r--r--netx/net/sourceforge/jnlp/tools/JarCertVerifier.java2
-rw-r--r--netx/net/sourceforge/jnlp/util/InvalidJarHeaderException.java49
-rw-r--r--netx/net/sourceforge/jnlp/util/JarFile.java153
10 files changed, 238 insertions, 12 deletions
diff --git a/netx/net/sourceforge/jnlp/Launcher.java b/netx/net/sourceforge/jnlp/Launcher.java
index c6712cd..11ca09f 100644
--- a/netx/net/sourceforge/jnlp/Launcher.java
+++ b/netx/net/sourceforge/jnlp/Launcher.java
@@ -30,7 +30,7 @@ import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
-import java.util.jar.JarFile;
+import net.sourceforge.jnlp.util.JarFile;
import net.sourceforge.jnlp.cache.CacheUtil;
import net.sourceforge.jnlp.cache.UpdatePolicy;
diff --git a/netx/net/sourceforge/jnlp/resources/Messages.properties b/netx/net/sourceforge/jnlp/resources/Messages.properties
index b372336..792bc64 100644
--- a/netx/net/sourceforge/jnlp/resources/Messages.properties
+++ b/netx/net/sourceforge/jnlp/resources/Messages.properties
@@ -191,6 +191,7 @@ BOStrict = Enables strict checking of JNLP file format.
BOViewer = Shows the trusted certificate viewer.
BXnofork = Do not create another JVM.
BXclearcache= Clean the JNLP application cache.
+BXignoreheaders= Skip jar header verification.
BOHelp = Print this message and exit.
# Cache
diff --git a/netx/net/sourceforge/jnlp/resources/Messages_cs_CZ.properties b/netx/net/sourceforge/jnlp/resources/Messages_cs_CZ.properties
index c6da0a5..e8570ff 100644
--- a/netx/net/sourceforge/jnlp/resources/Messages_cs_CZ.properties
+++ b/netx/net/sourceforge/jnlp/resources/Messages_cs_CZ.properties
@@ -188,6 +188,7 @@ BOStrict= Zapne striktn\u00ed kontrolu souborov\u00e9ho form\u00e1tu JNLP.
BOViewer= Zobraz\u00ed prohl\u00ed\u017ee\u010d d\u016fv\u011bryhodn\u00fdch certifik\u00e1t\u016f.
BXnofork= Zak\u00e1\u017ee vytv\u00e1\u0159en\u00ed jin\u00fdch prost\u0159ed\u00ed JVM.
BXclearcache= Vy\u010dist\u00ed vyrovn\u00e1vac\u00ed pam\u011b\u0165 aplikace JNLP.
+BXignoreheaders= Nebude prov\u00e1d\u011bt verifikaci hlavi\u010dek soubor\u016f jar.
BOHelp= Vyp\u00ed\u0161e zadanou zpr\u00e1vu do konzole a ukon\u010d\u00ed aplikaci.
# Cache
diff --git a/netx/net/sourceforge/jnlp/runtime/Boot.java b/netx/net/sourceforge/jnlp/runtime/Boot.java
index cd7d71a..ecedcfa 100644
--- a/netx/net/sourceforge/jnlp/runtime/Boot.java
+++ b/netx/net/sourceforge/jnlp/runtime/Boot.java
@@ -102,6 +102,7 @@ public final class Boot implements PrivilegedAction<Void> {
+ " -strict " + R("BOStrict") + "\n"
+ " -Xnofork " + R("BXnofork") + "\n"
+ " -Xclearcache " + R("BXclearcache") + "\n"
+ + " -Xignoreheaders " + R("BXignoreheaders") + "\n"
+ " -help " + R("BOHelp") + "\n";
private static final String doubleArgs = "-basedir -jnlp -arg -param -property -update";
@@ -159,6 +160,9 @@ public final class Boot implements PrivilegedAction<Void> {
if (null != getOption("-Xtrustall")) {
JNLPRuntime.setTrustAll(true);
}
+ if (null != getOption("-Xignoreheaders")) {
+ JNLPRuntime.setIgnoreHeaders(true);
+ }
JNLPRuntime.setInitialArgments(Arrays.asList(argsIn));
diff --git a/netx/net/sourceforge/jnlp/runtime/CachedJarFileCallback.java b/netx/net/sourceforge/jnlp/runtime/CachedJarFileCallback.java
index 48364df..7824881 100644
--- a/netx/net/sourceforge/jnlp/runtime/CachedJarFileCallback.java
+++ b/netx/net/sourceforge/jnlp/runtime/CachedJarFileCallback.java
@@ -49,7 +49,7 @@ import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
-import java.util.jar.JarFile;
+import net.sourceforge.jnlp.util.JarFile;
import net.sourceforge.jnlp.util.UrlUtils;
@@ -81,7 +81,7 @@ final class CachedJarFileCallback implements URLJarFileCallBack {
}
@Override
- public JarFile retrieve(URL url) throws IOException {
+ public java.util.jar.JarFile retrieve(URL url) throws IOException {
URL localUrl = mapping.get(url);
if (localUrl == null) {
@@ -122,8 +122,8 @@ final class CachedJarFileCallback implements URLJarFileCallBack {
/*
* This method is a copy of URLJarFile.retrieve() without the callback check.
*/
- private JarFile cacheJarFile(URL url) throws IOException {
- JarFile result = null;
+ private java.util.jar.JarFile cacheJarFile(URL url) throws IOException {
+ java.util.jar.JarFile result = null;
final int BUF_SIZE = 2048;
@@ -132,9 +132,9 @@ final class CachedJarFileCallback implements URLJarFileCallBack {
try {
result =
- AccessController.doPrivileged(new PrivilegedExceptionAction<JarFile>() {
+ AccessController.doPrivileged(new PrivilegedExceptionAction<java.util.jar.JarFile>() {
@Override
- public JarFile run() throws IOException {
+ public java.util.jar.JarFile run() throws IOException {
OutputStream out = null;
File tmpFile = null;
try {
diff --git a/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java b/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java
index 983979e..e790746 100644
--- a/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java
+++ b/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java
@@ -60,7 +60,7 @@ import java.util.TreeSet;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;
import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
+import net.sourceforge.jnlp.util.JarFile;
import java.util.jar.Manifest;
import net.sourceforge.jnlp.security.appletextendedsecurity.UnsignedAppletTrustConfirmation;
@@ -678,7 +678,7 @@ public class JNLPClassLoader extends URLClassLoader {
//to read the cacerts or trusted.certs files.
e.printStackTrace();
throw new LaunchException(null, null, R("LSFatal"),
- R("LCInit"), R("LFatalVerification"), R("LFatalVerificationInfo"));
+ R("LCInit"), R("LFatalVerification"), R("LFatalVerificationInfo") + ": " +e.getMessage());
}
//Case when at least one jar has some signing
diff --git a/netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java b/netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java
index add5035..a392d15 100644
--- a/netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java
+++ b/netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java
@@ -87,7 +87,7 @@ import sun.net.www.protocol.jar.URLJarFile;
* @version $Revision: 1.19 $
*/
public class JNLPRuntime {
-
+
static {
loadResources();
}
@@ -142,8 +142,16 @@ public class JNLPRuntime {
/** set to false to indicate another JVM should not be spawned, even if necessary */
private static boolean forksAllowed = true;
- /** all security dialogs will be consumed and pretented as beeing verified by user and allowed.*/
+ /** all security dialogs will be consumed and pretented as being verified by user and allowed.*/
private static boolean trustAll=false;
+ /**
+ * Header is not checked and so eg. gifar exploit is possible
+ * @see http://en.wikipedia.org/wiki/Gifar for this kind of attack.
+ * However if jar file is a bit corrupted, then it sometimes can work so
+ * this switch can disable the header check.
+ *
+ */
+ private static boolean ignoreHeaders=false;
/** contains the arguments passed to the jnlp runtime */
private static List<String> initialArguments;
@@ -776,4 +784,14 @@ public class JNLPRuntime {
return trustAll;
}
+ public static boolean isIgnoreHeaders() {
+ return ignoreHeaders;
+ }
+
+ public static void setIgnoreHeaders(boolean ignoreHeaders) {
+ JNLPRuntime.ignoreHeaders = ignoreHeaders;
+ }
+
+
+
}
diff --git a/netx/net/sourceforge/jnlp/tools/JarCertVerifier.java b/netx/net/sourceforge/jnlp/tools/JarCertVerifier.java
index 17c2a93..db9699d 100644
--- a/netx/net/sourceforge/jnlp/tools/JarCertVerifier.java
+++ b/netx/net/sourceforge/jnlp/tools/JarCertVerifier.java
@@ -41,7 +41,7 @@ import java.util.List;
import java.util.Map;
import java.util.Vector;
import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
+import net.sourceforge.jnlp.util.JarFile;
import net.sourceforge.jnlp.JARDesc;
import net.sourceforge.jnlp.JNLPFile;
diff --git a/netx/net/sourceforge/jnlp/util/InvalidJarHeaderException.java b/netx/net/sourceforge/jnlp/util/InvalidJarHeaderException.java
new file mode 100644
index 0000000..66efdda
--- /dev/null
+++ b/netx/net/sourceforge/jnlp/util/InvalidJarHeaderException.java
@@ -0,0 +1,49 @@
+/*
+Copyright (C) 2012 Red Hat, Inc.
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+package net.sourceforge.jnlp.util;
+
+/**
+ * Thrown from net.sourceforge.jnlp.utilJArFile when verification of headers fails
+ *
+ */
+public class InvalidJarHeaderException extends RuntimeException{
+
+ public InvalidJarHeaderException(String string) {
+ super(string);
+ }
+
+}
diff --git a/netx/net/sourceforge/jnlp/util/JarFile.java b/netx/net/sourceforge/jnlp/util/JarFile.java
new file mode 100644
index 0000000..8eee518
--- /dev/null
+++ b/netx/net/sourceforge/jnlp/util/JarFile.java
@@ -0,0 +1,153 @@
+/*
+ Copyright (C) 2012 Red Hat, Inc.
+
+ This file is part of IcedTea.
+
+ IcedTea is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ IcedTea 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 for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with IcedTea; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+package net.sourceforge.jnlp.util;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.zip.ZipFile;
+import net.sourceforge.jnlp.runtime.JNLPRuntime;
+
+public class JarFile extends java.util.jar.JarFile {
+
+ public JarFile(String name) throws IOException {
+ super(name);
+ verifyZipHeader(new File(name));
+ }
+
+ /**
+ */
+ public JarFile(String name, boolean verify) throws IOException {
+ super(name, verify);
+ verifyZipHeader(new File(name));
+ }
+
+ /**
+ */
+ public JarFile(File file) throws IOException {
+ super(file);
+ verifyZipHeader(file);
+ }
+
+ /**
+ */
+ public JarFile(File file, boolean verify) throws IOException {
+ super(file, verify);
+ verifyZipHeader(file);
+ }
+
+ /*
+ */
+ public JarFile(File file, boolean verify, int mode) throws IOException {
+ super(file, verify, mode);
+ verifyZipHeader(file);
+ }
+
+
+
+
+ /**
+ * According to specification -
+ * http://www.pkware.com/documents/casestudies/APPNOTE.TXT or just google
+ * around zip header all entries in zip-compressed must start with well
+ * known "PK" which is defined as hexa x50 x4b x03 x04, which in decimal are
+ * 80 75 3 4.
+ *
+ * Note - this is not file-header, it is item-header.
+ *
+ * Actually most of compressing formats have some n-bytes header se eg:
+ * http://www.gzip.org/zlib/rfc-gzip.html#header-trailer for ID1 and ID2 so
+ * in case that some differently compressed jars will come to play, this is
+ * the palce where to fix it.
+ *
+ */
+ private static final byte[] ZIP_LOCAL_FILE_HEADER_SIGNATURE = new byte[]{80, 75, 3, 4};
+
+ /**
+ * This method is checking first four bytes of jar-file against
+ * ZIP_LOCAL_FILE_HEADER_SIGNATURE
+ *
+ * Although zip specification allows to skip all corrupted entries, it is
+ * not safe for jars. If first four bytes of file are not zip
+ * ZIP_LOCAL_FILE_HEADER_SIGNATURE then exception is thrown
+ *
+ * As noted, ZIP_LOCAL_FILE_HEADER_SIGNATURE is not ile-header, but is item-header.
+ * Possible attack is using the fact that entries without header are considered
+ * corrupted and so can be ignoered. However, for other they can have some meaning.
+ *
+ * So for our purposes we must insists on first record to be valid.
+ *
+ * @param file
+ * @throws IOException, InvalidJarHeaderException
+ */
+ public static void verifyZipHeader(File file) throws IOException {
+ if (!JNLPRuntime.isIgnoreHeaders()) {
+ InputStream s = new FileInputStream(file);
+ try {
+ byte[] buffer = new byte[ZIP_LOCAL_FILE_HEADER_SIGNATURE.length];
+ /*
+ * for case that new byte[] will accidently initialize same
+ * sequence as zip header and during the read the buffer will not be filled
+ */
+ for (int i = 0; i < buffer.length; i++) {
+ buffer[i] = 0;
+ }
+ int toRead = ZIP_LOCAL_FILE_HEADER_SIGNATURE.length;
+ int readSoFar = 0;
+ int n = 0;
+ /*
+ * this is used instead of s.read(buffer) for case of block and
+ * so returned not-fully-filled dbuffer
+ */
+ while ((n = s.read(buffer, readSoFar, buffer.length - readSoFar)) != -1) {
+ readSoFar += n;
+ if (readSoFar == toRead) {
+ break;
+ }
+ }
+ for (int i = 0; i < buffer.length; i++) {
+ if (buffer[i] != ZIP_LOCAL_FILE_HEADER_SIGNATURE[i]) {
+ throw new InvalidJarHeaderException("Jar " + file.getName() + " do not heave valid header. You can skip this check by -Xignoreheaders");
+ }
+ }
+ } finally {
+ s.close();
+ }
+ }
+ }
+}