# HG changeset patch # User Andrew John Hughes # Date 1292529092 0 # Node ID 6f7d633c355a5d076fa6e6c30efb6602c7da7903 # Parent af20d64bc8b903a48719190ca57e83d3310d1fe0 RH663680, CVE-2010-4351: JNLP SecurityManager bypass 2010-12-16 Omair Majid RH663680, CVE-2010-4351: * NEWS: List issue. * rt/net/sourceforge/jnlp/runtime/JNLPSecurityManager.java: Make sure SecurityException is thrown if necessary. diff -r af20d64bc8b9 -r 6f7d633c355a ChangeLog --- a/ChangeLog Thu Dec 16 19:41:01 2010 +0000 +++ b/ChangeLog Thu Dec 16 19:51:32 2010 +0000 @@ -1,3 +1,10 @@ +2010-12-16 Omair Majid + + RH663680, CVE-2010-4351: + * NEWS: List issue. + * rt/net/sourceforge/jnlp/runtime/JNLPSecurityManager.java: + Make sure SecurityException is thrown if necessary. + 2010-12-16 Andrew John Hughes * NEWS: Fix issue placement. diff -r af20d64bc8b9 -r 6f7d633c355a NEWS --- a/NEWS Thu Dec 16 19:41:01 2010 +0000 +++ b/NEWS Thu Dec 16 19:51:32 2010 +0000 @@ -8,7 +8,9 @@ CVE-XXXX-YYYY: http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=XXXX-YYYY -New in release 1.7.7 (201X-XX-XX): +New in release 1.7.7 (2011-01-12): +* Security updates + - RH663680, CVE-2010-4351: IcedTea JNLP SecurityManager bypass * Backports - S6438179, RH569121: XToolkit.isTraySupported() result has nothing to do with the system tray - S4356282: RFE: JDK should support OpenType/CFF fonts diff -r af20d64bc8b9 -r 6f7d633c355a rt/net/sourceforge/jnlp/runtime/JNLPSecurityManager.java --- a/rt/net/sourceforge/jnlp/runtime/JNLPSecurityManager.java Thu Dec 16 19:41:01 2010 +0000 +++ b/rt/net/sourceforge/jnlp/runtime/JNLPSecurityManager.java Thu Dec 16 19:51:32 2010 +0000 @@ -188,21 +188,21 @@ * Return the current Application, or null. */ protected ApplicationInstance getApplication(Class stack[], int maxDepth) { - if (maxDepth <= 0) - maxDepth = stack.length; + if (maxDepth <= 0) + maxDepth = stack.length; - // this needs to be tightened up - for (int i=0; i < stack.length && i < maxDepth; i++) { - if (stack[i].getClassLoader() instanceof JNLPClassLoader) { - JNLPClassLoader loader = (JNLPClassLoader) stack[i].getClassLoader(); + // this needs to be tightened up + for (int i=0; i < stack.length && i < maxDepth; i++) { + if (stack[i].getClassLoader() instanceof JNLPClassLoader) { + JNLPClassLoader loader = (JNLPClassLoader) stack[i].getClassLoader(); - if (loader != null && loader.getApplication() != null) { - return loader.getApplication(); - } - } - } + if (loader != null && loader.getApplication() != null) { + return loader.getApplication(); + } + } + } - return null; + return null; } /** @@ -227,17 +227,17 @@ // Enable this manually -- it'll produce too much output for -verbose // otherwise. - // if (true) - // System.out.println("Checking permission: " + perm.toString()); + // if (true) + // System.out.println("Checking permission: " + perm.toString()); - if (!JNLPRuntime.isWebstartApplication() && - ("setPolicy".equals(name) || "setSecurityManager".equals(name))) + if (!JNLPRuntime.isWebstartApplication() && + ("setPolicy".equals(name) || "setSecurityManager".equals(name))) throw new SecurityException(R("RCantReplaceSM")); try { // deny all permissions to stopped applications - // The call to getApplication() below might not work if an - // application hasn't been fully initialized yet. + // The call to getApplication() below might not work if an + // application hasn't been fully initialized yet. // if (JNLPRuntime.isDebug()) { // if (!"getClassLoader".equals(name)) { // ApplicationInstance app = getApplication(); @@ -245,95 +245,97 @@ // throw new SecurityException(R("RDenyStopped")); // } // } - - try { - super.checkPermission(perm); - } catch (SecurityException se) { + + try { + super.checkPermission(perm); + } catch (SecurityException se) { - //This section is a special case for dealing with SocketPermissions. - if (JNLPRuntime.isDebug()) - System.err.println("Requesting permission: " + perm.toString()); + //This section is a special case for dealing with SocketPermissions. + if (JNLPRuntime.isDebug()) + System.err.println("Requesting permission: " + perm.toString()); + + //Change this SocketPermission's action to connect and accept + //(and resolve). This is to avoid asking for connect permission + //on every address resolve. + Permission tmpPerm = null; + if (perm instanceof SocketPermission) { + tmpPerm = new SocketPermission(perm.getName(), + SecurityConstants.SOCKET_CONNECT_ACCEPT_ACTION); - //Change this SocketPermission's action to connect and accept - //(and resolve). This is to avoid asking for connect permission - //on every address resolve. - Permission tmpPerm = null; - if (perm instanceof SocketPermission) { - tmpPerm = new SocketPermission(perm.getName(), - SecurityConstants.SOCKET_CONNECT_ACCEPT_ACTION); - - // before proceeding, check if we are trying to connect to same origin - ApplicationInstance app = getApplication(); - JNLPFile file = app.getJNLPFile(); + // before proceeding, check if we are trying to connect to same origin + ApplicationInstance app = getApplication(); + JNLPFile file = app.getJNLPFile(); + + String srcHost = file.getSourceLocation().getAuthority(); + String destHost = name; + + // host = abc.xyz.com or abc.xyz.com: + if (destHost.indexOf(':') >= 0) + destHost = destHost.substring(0, destHost.indexOf(':')); - String srcHost = file.getSourceLocation().getAuthority(); - String destHost = name; - - // host = abc.xyz.com or abc.xyz.com: - if (destHost.indexOf(':') >= 0) - destHost = destHost.substring(0, destHost.indexOf(':')); - - // host = abc.xyz.com - String[] hostComponents = destHost.split("\\."); - - int length = hostComponents.length; - if (length >= 2) { - - // address is in xxx.xxx.xxx format - destHost = hostComponents[length -2] + "." + hostComponents[length -1]; - - // host = xyz.com i.e. origin - boolean isDestHostName = false; + // host = abc.xyz.com + String[] hostComponents = destHost.split("\\."); + + int length = hostComponents.length; + if (length >= 2) { + + // address is in xxx.xxx.xxx format + destHost = hostComponents[length -2] + "." + hostComponents[length -1]; + + // host = xyz.com i.e. origin + boolean isDestHostName = false; - // make sure that it is not an ip address - try { - Integer.parseInt(hostComponents[length -1]); - } catch (NumberFormatException e) { - isDestHostName = true; - } + // make sure that it is not an ip address + try { + Integer.parseInt(hostComponents[length -1]); + } catch (NumberFormatException e) { + isDestHostName = true; + } - if (isDestHostName) { - // okay, destination is hostname. Now figure out if it is a subset of origin - if (srcHost.endsWith(destHost)) { - addPermission(tmpPerm); - return; - } - } - } + if (isDestHostName) { + // okay, destination is hostname. Now figure out if it is a subset of origin + if (srcHost.endsWith(destHost)) { + addPermission(tmpPerm); + return; + } + } + } - } else if (perm instanceof SecurityPermission) { + } else if (perm instanceof SecurityPermission) { + tmpPerm = perm; - // JCE's initialization requires putProviderProperty permission - if (perm.equals(new SecurityPermission("putProviderProperty.SunJCE"))) { - if (inTrustedCallChain("com.sun.crypto.provider.SunJCE", "run")) { - return; - } - } + // JCE's initialization requires putProviderProperty permission + if (perm.equals(new SecurityPermission("putProviderProperty.SunJCE"))) { + if (inTrustedCallChain("com.sun.crypto.provider.SunJCE", "run")) { + return; + } + } - } else if (perm instanceof RuntimePermission) { + } else if (perm instanceof RuntimePermission) { + tmpPerm = perm; - // KeyGenerator's init method requires internal spec access - if (perm.equals(new SecurityPermission("accessClassInPackage.sun.security.internal.spec"))) { - if (inTrustedCallChain("javax.crypto.KeyGenerator", "init")) { - return; - } - } + // KeyGenerator's init method requires internal spec access + if (perm.equals(new SecurityPermission("accessClassInPackage.sun.security.internal.spec"))) { + if (inTrustedCallChain("javax.crypto.KeyGenerator", "init")) { + return; + } + } - } else { - tmpPerm = perm; - } + } else { + tmpPerm = perm; + } - if (tmpPerm != null) { - //askPermission will only prompt the user on SocketPermission - //meaning we're denying all other SecurityExceptions that may arise. - if (askPermission(tmpPerm)) { - addPermission(tmpPerm); - //return quietly. - } else { - throw se; - } - } - } + if (tmpPerm != null) { + //askPermission will only prompt the user on SocketPermission + //meaning we're denying all other SecurityExceptions that may arise. + if (askPermission(tmpPerm)) { + addPermission(tmpPerm); + //return quietly. + } else { + throw se; + } + } + } } catch (SecurityException ex) { if (JNLPRuntime.isDebug()) { @@ -343,18 +345,18 @@ } } - /** - * Returns weather the given class and method are in the current stack, + /** + * Returns weather the given class and method are in the current stack, * and whether or not everything upto then is trusted - * + * * @param className The name of the class to look for in the stack * @param methodName The name of the method for the given class to look for in the stack * @return Weather or not class::method() are in the chain, and everything upto there is trusted */ private boolean inTrustedCallChain(String className, String methodName) { - + StackTraceElement[] stack = Thread.currentThread().getStackTrace(); - + for (int i=0; i < stack.length; i++) { // Everything up to the desired class/method must be trusted @@ -367,49 +369,49 @@ return true; } } - + return false; } - + /** * Asks the user whether or not to grant permission. * @param perm the permission to be granted * @return true if the permission was granted, false otherwise. */ - private boolean askPermission(Permission perm) { - - ApplicationInstance app = getApplication(); - if (app != null && !app.isSigned()) { - if (perm instanceof SocketPermission - && ServiceUtil.checkAccess(SecurityWarningDialog.AccessType.NETWORK, perm.getName())) { - return true; - } - } + private boolean askPermission(Permission perm) { - return false; + ApplicationInstance app = getApplication(); + if (app != null && !app.isSigned()) { + if (perm instanceof SocketPermission + && ServiceUtil.checkAccess(SecurityWarningDialog.AccessType.NETWORK, perm.getName())) { + return true; + } + } + + return false; } /** * Adds a permission to the JNLPClassLoader. * @param perm the permission to add to the JNLPClassLoader */ - private void addPermission(Permission perm) { - if (JNLPRuntime.getApplication().getClassLoader() instanceof JNLPClassLoader) { + private void addPermission(Permission perm) { + if (JNLPRuntime.getApplication().getClassLoader() instanceof JNLPClassLoader) { - JNLPClassLoader cl = (JNLPClassLoader) JNLPRuntime.getApplication().getClassLoader(); - cl.addPermission(perm); - if (JNLPRuntime.isDebug()) { - if (cl.getPermissions(null).implies(perm)) - System.err.println("Added permission: " + perm.toString()); - else - System.err.println("Unable to add permission: " + perm.toString()); - } - } else { - if (JNLPRuntime.isDebug()) - System.err.println("Unable to add permission: " + perm + ", classloader not JNLP."); - } + JNLPClassLoader cl = (JNLPClassLoader) JNLPRuntime.getApplication().getClassLoader(); + cl.addPermission(perm); + if (JNLPRuntime.isDebug()) { + if (cl.getPermissions(null).implies(perm)) + System.err.println("Added permission: " + perm.toString()); + else + System.err.println("Unable to add permission: " + perm.toString()); + } + } else { + if (JNLPRuntime.isDebug()) + System.err.println("Unable to add permission: " + perm + ", classloader not JNLP."); + } } - + /** * Checks whether the window can be displayed without an applet * warning banner, and adds the window to the list of windows to @@ -418,7 +420,7 @@ public boolean checkTopLevelWindow(Object window) { ApplicationInstance app = getApplication(); - // remember window -> application mapping for focus, close on exit + // remember window -> application mapping for focus, close on exit if (app != null && window instanceof Window) { Window w = (Window) window; @@ -439,7 +441,7 @@ // todo: set awt.appletWarning to custom message // todo: logo on with glass pane on JFrame/JWindow? - + return super.checkTopLevelWindow(window); } @@ -458,16 +460,16 @@ */ public void checkExit(int status) { - // applets are not allowed to exit, but the plugin main class (primordial loader) is + // applets are not allowed to exit, but the plugin main class (primordial loader) is Class stack[] = getClassContext(); if (!exitAllowed) { - for (int i=0; i < stack.length; i++) - if (stack[i].getClassLoader() != null) - throw new AccessControlException("Applets may not call System.exit()"); + for (int i=0; i < stack.length; i++) + if (stack[i].getClassLoader() != null) + throw new AccessControlException("Applets may not call System.exit()"); } - super.checkExit(status); - + super.checkExit(status); + boolean realCall = (stack[1] == Runtime.class); if (isExitClass(stack)) // either exitClass called or no exitClass set @@ -498,9 +500,9 @@ } protected void disableExit() { - exitAllowed = false; + exitAllowed = false; } - + }