diff -r fda2b44112c7 -r e91bfaf4360d jdk/src/share/classes/java/net/SocketPermission.java --- a/jdk/src/share/classes/java/net/SocketPermission.java Thu Oct 24 10:02:26 2013 -0700 +++ b/jdk/src/share/classes/java/net/SocketPermission.java Thu Oct 24 20:39:21 2013 +0100 @@ -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; @@ -89,6 +92,9 @@ * form "N-", where N is a port number, signifies all ports * numbered N and above, while a specification of the * form "-N" indicates all ports numbered N and below. + * The special port value {@code 0} refers to the entire ephemeral + * port range. This is a fixed range of ports a system may use to + * allocate dynamic ports from. The actual range may be system dependent. *

* The possible ways to connect to the host are *

@@ -97,7 +103,8 @@
  * listen
  * resolve
  * 
- * The "listen" action is only meaningful when used with "localhost". + * The "listen" action is only meaningful when used with "localhost" and + * means the ability to bind to a specified port. * The "resolve" action is implied when any of the other actions are present. * The action "resolve" refers to host/ip name service lookups. *

@@ -176,6 +183,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 +234,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")); @@ -360,6 +376,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. @@ -850,10 +874,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; + } } } @@ -1168,6 +1203,83 @@ 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(String suffix, 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() {