# HG changeset patch # User michaelm # Date 1383302456 0 # Node ID 458e5fe61d94b73db6b1b2821092a6aff13d5d6f # Parent c31a79eedba256f61771de7e0e209fb0be3d9af5 8011786: Better applet networking Summary: add checkListen() to client socket binds and new interpretation for port number 0 in SocketPermission Reviewed-by: chegar, alanb diff -r c31a79eedba2 -r 458e5fe61d94 src/share/classes/java/lang/SecurityManager.java --- a/src/share/classes/java/lang/SecurityManager.java Mon Oct 14 18:35:40 2013 -0700 +++ b/src/share/classes/java/lang/SecurityManager.java Fri Nov 01 10:40:56 2013 +0000 @@ -1131,12 +1131,8 @@ * @see #checkPermission(java.security.Permission) checkPermission */ public void checkListen(int port) { - if (port == 0) { - checkPermission(SecurityConstants.LOCAL_LISTEN_PERMISSION); - } else { - checkPermission(new SocketPermission("localhost:"+port, - SecurityConstants.SOCKET_LISTEN_ACTION)); - } + checkPermission(new SocketPermission("localhost:"+port, + SecurityConstants.SOCKET_LISTEN_ACTION)); } /** diff -r c31a79eedba2 -r 458e5fe61d94 src/share/classes/java/net/Socket.java --- a/src/share/classes/java/net/Socket.java Mon Oct 14 18:35:40 2013 -0700 +++ b/src/share/classes/java/net/Socket.java Fri Nov 01 10:40:56 2013 +0000 @@ -624,6 +624,10 @@ InetAddress addr = epoint.getAddress(); int port = epoint.getPort(); checkAddress (addr, "bind"); + SecurityManager security = System.getSecurityManager(); + if (security != null) { + security.checkListen(port); + } getImpl().bind (addr, port); bound = true; } diff -r c31a79eedba2 -r 458e5fe61d94 src/share/classes/java/net/SocketPermission.java --- a/src/share/classes/java/net/SocketPermission.java Mon Oct 14 18:35:40 2013 -0700 +++ b/src/share/classes/java/net/SocketPermission.java Fri Nov 01 10:40:56 2013 +0000 @@ -34,6 +34,9 @@ import java.net.InetAddress; import java.security.Permission; import java.security.PermissionCollection; +import java.security.PrivilegedAction; +import java.security.AccessController; +import java.security.Security; import java.io.Serializable; import java.io.ObjectStreamField; import java.io.ObjectOutputStream; @@ -176,6 +179,7 @@ private static final int PORT_MIN = 0; private static final int PORT_MAX = 65535; private static final int PRIV_PORT_MAX = 1023; + private static final int DEF_EPH_LOW = 49152; // the actions mask private transient int mask; @@ -226,6 +230,14 @@ private static Debug debug = null; private static boolean debugInit = false; + // ephemeral port range for this system + private static final int ephemeralLow = initEphemeralPorts( + "low", DEF_EPH_LOW + ); + private static final int ephemeralHigh = initEphemeralPorts( + "high", PORT_MAX + ); + static { Boolean tmp = java.security.AccessController.doPrivileged( new sun.security.action.GetBooleanAction("sun.net.trustNameService")); @@ -362,6 +374,14 @@ } /** + * Returns true if the permission has specified zero + * as its value (or lower bound) signifying the ephemeral range + */ + private boolean includesEphemerals() { + return portrange[0] == 0; + } + + /** * Initialize the SocketPermission object. We don't do any DNS lookups * as this point, instead we hold off until the implies method is * called. @@ -853,10 +873,21 @@ int i,j; if ((that.mask & RESOLVE) != that.mask) { - // check port range + + // check simple port range if ((that.portrange[0] < this.portrange[0]) || (that.portrange[1] > this.portrange[1])) { + + // if either includes the ephemeral range, do full check + if (this.includesEphemerals() || that.includesEphemerals()) { + if (!inRange(this.portrange[0], this.portrange[1], + that.portrange[0], that.portrange[1])) + { + return false; + } + } else { return false; + } } } @@ -1165,6 +1196,86 @@ init(getName(),getMask(actions)); } + /** + * Check the system/security property for the ephemeral port range + * for this system. The suffix is either "high" or "low" + */ + private static int initEphemeralPorts( + final String suffix, final int defval + ) + { + return AccessController.doPrivileged( + new PrivilegedAction(){ + public Integer run() { + int val = Integer.getInteger( + "jdk.net.ephemeralPortRange."+suffix, -1 + ); + if (val != -1) { + return val; + } else { + String prop = Security.getProperty( + "network.ephemeralPortRange."+suffix + ); + try { + val = Integer.parseInt(prop); + } catch (NumberFormatException e) { + // shouldn't happen + return defval; + } + } + return val; + } + } + ); + } + + /** + * Check if the target range is within the policy range + * together with the ephemeral range for this platform + * (if policy includes ephemeral range) + */ + private static boolean inRange( + int policyLow, int policyHigh, int targetLow, int targetHigh + ) + { + if (targetLow == 0) { + // check policy includes ephemeral range + if (!inRange(policyLow, policyHigh, ephemeralLow, ephemeralHigh)) { + return false; + } + if (targetHigh == 0) { + // nothing left to do + return true; + } + // continue check with first real port number + targetLow = 1; + } + + if (policyLow == 0 && policyHigh == 0) { + // ephemeral range only + return targetLow >= ephemeralLow && targetHigh <= ephemeralHigh; + } + + if (policyLow != 0) { + // simple check of policy only + return targetLow >= policyLow && targetHigh <= policyHigh; + } + + // policyLow == 0 which means possibly two ranges to check + + // first check if policy and ephem range overlap/contiguous + + if (policyHigh >= ephemeralLow - 1) { + return targetHigh <= ephemeralHigh; + } + + // policy and ephem range do not overlap + + // target range must lie entirely inside policy range or eph range + + return (targetLow <= policyHigh && targetHigh <= policyHigh) || + (targetLow >= ephemeralLow && targetHigh <= ephemeralHigh); + } /* public String toString() { diff -r c31a79eedba2 -r 458e5fe61d94 src/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java --- a/src/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java Mon Oct 14 18:35:40 2013 -0700 +++ b/src/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java Fri Nov 01 10:40:56 2013 +0000 @@ -428,6 +428,10 @@ throw new AlreadyBoundException(); InetSocketAddress isa = (local == null) ? new InetSocketAddress(0) : Net.checkAddress(local); + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkListen(isa.getPort()); + } NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort()); Net.bind(fd, isa.getAddress(), isa.getPort()); localAddress = Net.localAddress(fd); diff -r c31a79eedba2 -r 458e5fe61d94 src/share/classes/sun/nio/ch/SocketChannelImpl.java --- a/src/share/classes/sun/nio/ch/SocketChannelImpl.java Mon Oct 14 18:35:40 2013 -0700 +++ b/src/share/classes/sun/nio/ch/SocketChannelImpl.java Fri Nov 01 10:40:56 2013 +0000 @@ -572,6 +572,10 @@ throw new AlreadyBoundException(); InetSocketAddress isa = (local == null) ? new InetSocketAddress(0) : Net.checkAddress(local); + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkListen(isa.getPort()); + } NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort()); Net.bind(fd, isa.getAddress(), isa.getPort()); localAddress = Net.localAddress(fd); diff -r c31a79eedba2 -r 458e5fe61d94 src/share/classes/sun/security/util/SecurityConstants.java --- a/src/share/classes/sun/security/util/SecurityConstants.java Mon Oct 14 18:35:40 2013 -0700 +++ b/src/share/classes/sun/security/util/SecurityConstants.java Fri Nov 01 10:40:56 2013 +0000 @@ -257,5 +257,5 @@ // java.lang.SecurityManager public static final SocketPermission LOCAL_LISTEN_PERMISSION = - new SocketPermission("localhost:1024-", SOCKET_LISTEN_ACTION); + new SocketPermission("localhost:0", SOCKET_LISTEN_ACTION); } diff -r c31a79eedba2 -r 458e5fe61d94 src/share/lib/security/java.policy --- a/src/share/lib/security/java.policy Mon Oct 14 18:35:40 2013 -0700 +++ b/src/share/lib/security/java.policy Fri Nov 01 10:40:56 2013 +0000 @@ -2,48 +2,51 @@ // Standard extensions get all permissions by default grant codeBase "file:${{java.ext.dirs}}/*" { - permission java.security.AllPermission; + permission java.security.AllPermission; }; // default permissions granted to all domains -grant { - // Allows any thread to stop itself using the java.lang.Thread.stop() - // method that takes no argument. - // Note that this permission is granted by default only to remain - // backwards compatible. - // It is strongly recommended that you either remove this permission - // from this policy file or further restrict it to code sources - // that you specify, because Thread.stop() is potentially unsafe. - // See the API specification of java.lang.Thread.stop() for more +grant { + // Allows any thread to stop itself using the java.lang.Thread.stop() + // method that takes no argument. + // Note that this permission is granted by default only to remain + // backwards compatible. + // It is strongly recommended that you either remove this permission + // from this policy file or further restrict it to code sources + // that you specify, because Thread.stop() is potentially unsafe. + // See the API specification of java.lang.Thread.stop() for more // information. - permission java.lang.RuntimePermission "stopThread"; + permission java.lang.RuntimePermission "stopThread"; + + // allows anyone to listen on dynamic ports + permission java.net.SocketPermission "localhost:0", "listen"; - // allows anyone to listen on un-privileged ports - permission java.net.SocketPermission "localhost:1024-", "listen"; + // permission for standard RMI registry port + permission java.net.SocketPermission "localhost:1099", "listen"; - // "standard" properies that can be read by anyone + // "standard" properies that can be read by anyone - permission java.util.PropertyPermission "java.version", "read"; - permission java.util.PropertyPermission "java.vendor", "read"; - permission java.util.PropertyPermission "java.vendor.url", "read"; - permission java.util.PropertyPermission "java.class.version", "read"; - permission java.util.PropertyPermission "os.name", "read"; - permission java.util.PropertyPermission "os.version", "read"; - permission java.util.PropertyPermission "os.arch", "read"; - permission java.util.PropertyPermission "file.separator", "read"; - permission java.util.PropertyPermission "path.separator", "read"; - permission java.util.PropertyPermission "line.separator", "read"; + permission java.util.PropertyPermission "java.version", "read"; + permission java.util.PropertyPermission "java.vendor", "read"; + permission java.util.PropertyPermission "java.vendor.url", "read"; + permission java.util.PropertyPermission "java.class.version", "read"; + permission java.util.PropertyPermission "os.name", "read"; + permission java.util.PropertyPermission "os.version", "read"; + permission java.util.PropertyPermission "os.arch", "read"; + permission java.util.PropertyPermission "file.separator", "read"; + permission java.util.PropertyPermission "path.separator", "read"; + permission java.util.PropertyPermission "line.separator", "read"; - permission java.util.PropertyPermission "java.specification.version", "read"; - permission java.util.PropertyPermission "java.specification.vendor", "read"; - permission java.util.PropertyPermission "java.specification.name", "read"; + permission java.util.PropertyPermission "java.specification.version", "read"; + permission java.util.PropertyPermission "java.specification.vendor", "read"; + permission java.util.PropertyPermission "java.specification.name", "read"; - permission java.util.PropertyPermission "java.vm.specification.version", "read"; - permission java.util.PropertyPermission "java.vm.specification.vendor", "read"; - permission java.util.PropertyPermission "java.vm.specification.name", "read"; - permission java.util.PropertyPermission "java.vm.version", "read"; - permission java.util.PropertyPermission "java.vm.vendor", "read"; - permission java.util.PropertyPermission "java.vm.name", "read"; + permission java.util.PropertyPermission "java.vm.specification.version", "read"; + permission java.util.PropertyPermission "java.vm.specification.vendor", "read"; + permission java.util.PropertyPermission "java.vm.specification.name", "read"; + permission java.util.PropertyPermission "java.vm.version", "read"; + permission java.util.PropertyPermission "java.vm.vendor", "read"; + permission java.util.PropertyPermission "java.vm.name", "read"; }; diff -r c31a79eedba2 -r 458e5fe61d94 src/share/lib/security/java.security --- a/src/share/lib/security/java.security Mon Oct 14 18:35:40 2013 -0700 +++ b/src/share/lib/security/java.security Fri Nov 01 10:40:56 2013 +0000 @@ -428,3 +428,19 @@ # Example: # jdk.tls.disabledAlgorithms=MD5, SHA1, DSA, RSA keySize < 2048 +# +# Default ephemeral port ranges (operating system specific) +# used by java.net.SocketPermission to interpret the meaning of the special +# port value zero, as in the following example: +# +# SocketPermission("localhost:0" , "listen"); +# +# These can be overridden by the system properties: +# +# jdk.net.ephemeralPortRange.low and +# jdk.net.ephemeralPortRange.high +# +# respectively. +# +network.ephemeralPortRange.low=32768 +network.ephemeralPortRange.high=65535 diff -r c31a79eedba2 -r 458e5fe61d94 src/share/lib/security/java.security-macosx --- a/src/share/lib/security/java.security-macosx Mon Oct 14 18:35:40 2013 -0700 +++ b/src/share/lib/security/java.security-macosx Fri Nov 01 10:40:56 2013 +0000 @@ -431,3 +431,21 @@ # Example: # jdk.tls.disabledAlgorithms=MD5, SHA1, DSA, RSA keySize < 2048 + +# +# Default ephemeral port ranges (operating system specific) +# used by java.net.SocketPermission to interpret the meaning of the special +# port value zero, as in the following example: +# +# SocketPermission("localhost:0" , "listen"); +# +# These can be overridden by the system properties: +# +# jdk.net.ephemeralPortRange.low and +# jdk.net.ephemeralPortRange.high +# +# respectively. +# +network.ephemeralPortRange.low=49152 +network.ephemeralPortRange.high=65535 + diff -r c31a79eedba2 -r 458e5fe61d94 src/share/lib/security/java.security-solaris --- a/src/share/lib/security/java.security-solaris Mon Oct 14 18:35:40 2013 -0700 +++ b/src/share/lib/security/java.security-solaris Fri Nov 01 10:40:56 2013 +0000 @@ -429,4 +429,21 @@ # # Example: # jdk.tls.disabledAlgorithms=MD5, SHA1, DSA, RSA keySize < 2048 -i + + +# +# Default ephemeral port ranges (operating system specific) +# used by java.net.SocketPermission to interpret the meaning of the special +# port value zero, as in the following example: +# +# SocketPermission("localhost:0" , "listen"); +# +# These can be overridden by the system properties: +# +# jdk.net.ephemeralPortRange.low and +# jdk.net.ephemeralPortRange.high +# +# respectively. +# +network.ephemeralPortRange.low=32768 +network.ephemeralPortRange.high=65535 diff -r c31a79eedba2 -r 458e5fe61d94 src/share/lib/security/java.security-windows --- a/src/share/lib/security/java.security-windows Mon Oct 14 18:35:40 2013 -0700 +++ b/src/share/lib/security/java.security-windows Fri Nov 01 10:40:56 2013 +0000 @@ -431,3 +431,19 @@ # Example: # jdk.tls.disabledAlgorithms=MD5, SHA1, DSA, RSA keySize < 2048 +# +# Default ephemeral port ranges (operating system specific) +# used by java.net.SocketPermission to interpret the meaning of the special +# port value zero, as in the following example: +# +# SocketPermission("localhost:0" , "listen"); +# +# These can be overridden by the system properties: +# +# jdk.net.ephemeralPortRange.low and +# jdk.net.ephemeralPortRange.high +# +# respectively. +# +network.ephemeralPortRange.low=49152 +network.ephemeralPortRange.high=65535 diff -r c31a79eedba2 -r 458e5fe61d94 src/solaris/classes/sun/nio/ch/SctpChannelImpl.java --- a/src/solaris/classes/sun/nio/ch/SctpChannelImpl.java Mon Oct 14 18:35:40 2013 -0700 +++ b/src/solaris/classes/sun/nio/ch/SctpChannelImpl.java Fri Nov 01 10:40:56 2013 +0000 @@ -180,6 +180,10 @@ SctpNet.throwAlreadyBoundException(); InetSocketAddress isa = (local == null) ? new InetSocketAddress(0) : Net.checkAddress(local); + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkListen(isa.getPort()); + } Net.bind(fd, isa.getAddress(), isa.getPort()); InetSocketAddress boundIsa = Net.localAddress(fd); port = boundIsa.getPort();