Merge
diff --git a/make/rmic/Rmic-java.rmi.gmk b/make/rmic/Rmic-java.rmi.gmk
index c9b024e..7a7a464 100644
--- a/make/rmic/Rmic-java.rmi.gmk
+++ b/make/rmic/Rmic-java.rmi.gmk
@@ -40,16 +40,9 @@
RUN_V12 := true))
GENCLASSES += $(RMI_12)
-$(eval $(call SetupRMICompilation,RMI_11, \
- CLASSES := sun.rmi.registry.RegistryImpl \
- sun.rmi.transport.DGCImpl, \
- CLASSES_DIR := $(CLASSES_DIR)/java.rmi, \
- STUB_CLASSES_DIR := $(STUB_CLASSES_DIR)/java.rmi, \
- RUN_V11 := true))
-GENCLASSES += $(RMI_11)
################################################################################
-all: $(RMI_11) $(RMI_12)
+all: $(RMI_12)
.PHONY: all
diff --git a/src/java.base/share/classes/java/security/CodeSource.java b/src/java.base/share/classes/java/security/CodeSource.java
index 93d9983..818716f 100644
--- a/src/java.base/share/classes/java/security/CodeSource.java
+++ b/src/java.base/share/classes/java/security/CodeSource.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, 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
@@ -560,6 +560,7 @@
{
CertificateFactory cf;
Hashtable<String, CertificateFactory> cfs = null;
+ List<java.security.cert.Certificate> certList = null;
ois.defaultReadObject(); // location
@@ -569,7 +570,7 @@
// we know of 3 different cert types: X.509, PGP, SDSI, which
// could all be present in the stream at the same time
cfs = new Hashtable<>(3);
- this.certs = new java.security.cert.Certificate[size];
+ certList = new ArrayList<>(size > 20 ? 20 : size);
}
for (int i = 0; i < size; i++) {
@@ -600,13 +601,17 @@
ois.readFully(encoded);
ByteArrayInputStream bais = new ByteArrayInputStream(encoded);
try {
- this.certs[i] = cf.generateCertificate(bais);
+ certList.add(cf.generateCertificate(bais));
} catch (CertificateException ce) {
throw new IOException(ce.getMessage());
}
bais.close();
}
+ if (certList != null) {
+ this.certs = certList.toArray(
+ new java.security.cert.Certificate[size]);
+ }
// Deserialize array of code signers (if any)
try {
this.signers = ((CodeSigner[])ois.readObject()).clone();
diff --git a/src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java b/src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java
index ceb9bf2..092b1b2 100644
--- a/src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java
+++ b/src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java
@@ -35,6 +35,9 @@
package java.util.concurrent;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.ConcurrentModificationException;
import java.util.HashSet;
@@ -584,6 +587,9 @@
private static final RuntimePermission shutdownPerm =
new RuntimePermission("modifyThread");
+ /* The context to be used when executing the finalizer, or null. */
+ private final AccessControlContext acc;
+
/**
* Class Worker mainly maintains interrupt control state for
* threads running tasks, along with other minor bookkeeping.
@@ -1326,6 +1332,9 @@
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
+ this.acc = System.getSecurityManager() == null ?
+ null :
+ AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
@@ -1491,6 +1500,9 @@
* Invokes {@code shutdown} when this executor is no longer
* referenced and it has no threads.
*
+ * <p>This method is invoked with privileges that are restricted by
+ * the security context of the caller that invokes the constructor.
+ *
* @deprecated The {@code finalize} method has been deprecated.
* Subclasses that override {@code finalize} in order to perform cleanup
* should be modified to use alternative cleanup mechanisms and
@@ -1502,7 +1514,13 @@
*/
@Deprecated(since="9")
protected void finalize() {
- shutdown();
+ SecurityManager sm = System.getSecurityManager();
+ if (sm == null || acc == null) {
+ shutdown();
+ } else {
+ PrivilegedAction<Void> pa = () -> { shutdown(); return null; };
+ AccessController.doPrivileged(pa, acc);
+ }
}
/**
diff --git a/src/java.base/share/classes/java/util/jar/JarVerifier.java b/src/java.base/share/classes/java/util/jar/JarVerifier.java
index 2d0f5eb..240b174 100644
--- a/src/java.base/share/classes/java/util/jar/JarVerifier.java
+++ b/src/java.base/share/classes/java/util/jar/JarVerifier.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, 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
@@ -180,10 +180,12 @@
// only set the jev object for entries that have a signature
// (either verified or not)
- if (sigFileSigners.get(name) != null ||
- verifiedSigners.get(name) != null) {
- mev.setEntry(name, je);
- return;
+ if (!name.equals(JarFile.MANIFEST_NAME)) {
+ if (sigFileSigners.get(name) != null ||
+ verifiedSigners.get(name) != null) {
+ mev.setEntry(name, je);
+ return;
+ }
}
// don't compute the digest for this entry
diff --git a/src/java.base/share/classes/sun/nio/ch/AsynchronousChannelGroupImpl.java b/src/java.base/share/classes/sun/nio/ch/AsynchronousChannelGroupImpl.java
index 117df24..8a88ddc 100644
--- a/src/java.base/share/classes/sun/nio/ch/AsynchronousChannelGroupImpl.java
+++ b/src/java.base/share/classes/sun/nio/ch/AsynchronousChannelGroupImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2017, 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
@@ -246,13 +246,16 @@
abstract void shutdownHandlerTasks();
private void shutdownExecutors() {
- AccessController.doPrivileged(new PrivilegedAction<>() {
- public Void run() {
- pool.executor().shutdown();
- timeoutExecutor.shutdown();
- return null;
- }
- });
+ AccessController.doPrivileged(
+ new PrivilegedAction<>() {
+ public Void run() {
+ pool.executor().shutdown();
+ timeoutExecutor.shutdown();
+ return null;
+ }
+ },
+ null,
+ new RuntimePermission("modifyThread"));
}
@Override
diff --git a/src/java.base/share/classes/sun/security/pkcs/PKCS8Key.java b/src/java.base/share/classes/sun/security/pkcs/PKCS8Key.java
index 7cdc167..ee2c6e3 100644
--- a/src/java.base/share/classes/sun/security/pkcs/PKCS8Key.java
+++ b/src/java.base/share/classes/sun/security/pkcs/PKCS8Key.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2017, 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
@@ -32,6 +32,7 @@
import java.security.KeyRep;
import java.security.PrivateKey;
import java.security.KeyFactory;
+import java.security.MessageDigest;
import java.security.Security;
import java.security.Provider;
import java.security.InvalidKeyException;
@@ -419,18 +420,9 @@
// that encoding
byte[] b2 = ((Key)object).getEncoded();
- // do the comparison
- int i;
- if (b1.length != b2.length)
- return false;
- for (i = 0; i < b1.length; i++) {
- if (b1[i] != b2[i]) {
- return false;
- }
- }
- return true;
+ // time-constant comparison
+ return MessageDigest.isEqual(b1, b2);
}
-
return false;
}
diff --git a/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java b/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java
index 6efd90d..18e32fc 100644
--- a/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java
+++ b/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java
@@ -323,6 +323,12 @@
data = content.getContentBytes();
}
+ Timestamp timestamp = null;
+ try {
+ timestamp = getTimestamp();
+ } catch (Exception ignore) {
+ }
+
ConstraintsParameters cparams =
new ConstraintsParameters(timestamp);
String digestAlgname = getDigestAlgorithmId().getName();
diff --git a/src/java.base/share/classes/sun/security/provider/DSA.java b/src/java.base/share/classes/sun/security/provider/DSA.java
index 5763e65..9fc4785 100644
--- a/src/java.base/share/classes/sun/security/provider/DSA.java
+++ b/src/java.base/share/classes/sun/security/provider/DSA.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2017, 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
@@ -64,6 +64,13 @@
/* Are we debugging? */
private static final boolean debug = false;
+ /* The number of bits used in exponent blinding */
+ private static final int BLINDING_BITS = 7;
+
+ /* The constant component of the exponent blinding value */
+ private static final BigInteger BLINDING_CONSTANT =
+ BigInteger.valueOf(1 << BLINDING_BITS);
+
/* The parameter object */
private DSAParams params;
@@ -368,8 +375,19 @@
return null;
}
+
private BigInteger generateR(BigInteger p, BigInteger q, BigInteger g,
BigInteger k) {
+
+ // exponent blinding to hide information from timing channel
+ SecureRandom random = getSigningRandom();
+ // start with a random blinding component
+ BigInteger blindingValue = new BigInteger(BLINDING_BITS, random);
+ // add the fixed blinding component
+ blindingValue = blindingValue.add(BLINDING_CONSTANT);
+ // replace k with a blinded value that is congruent (mod q)
+ k = k.add(q.multiply(blindingValue));
+
BigInteger temp = g.modPow(k, p);
return temp.mod(q);
}
@@ -434,43 +452,8 @@
byte[] kValue = new byte[(q.bitLength() + 7)/8 + 8];
random.nextBytes(kValue);
- BigInteger k = new BigInteger(1, kValue).mod(
+ return new BigInteger(1, kValue).mod(
q.subtract(BigInteger.ONE)).add(BigInteger.ONE);
-
- // Using an equivalent exponent of fixed length (same as q or 1 bit
- // less than q) to keep the kG timing relatively constant.
- //
- // Note that this is an extra step on top of the approach defined in
- // FIPS 186-4 AppendixB.2.1 so as to make a fixed length K.
- k = k.add(q).divide(BigInteger.TWO);
-
- // An alternative implementation based on FIPS 186-4 AppendixB2.2
- // with fixed-length K.
- //
- // Please keep it here as we may need to switch to it in the future.
- //
- // SecureRandom random = getSigningRandom();
- // byte[] kValue = new byte[(q.bitLength() + 7)/8];
- // BigInteger d = q.subtract(BigInteger.TWO);
- // BigInteger k;
- // do {
- // random.nextBytes(kValue);
- // BigInteger c = new BigInteger(1, kValue);
- // if (c.compareTo(d) <= 0) {
- // k = c.add(BigInteger.ONE);
- // // Using an equivalent exponent of fixed length to keep
- // // the g^k timing relatively constant.
- // //
- // // Note that this is an extra step on top of the approach
- // // defined in FIPS 186-4 AppendixB.2.2 so as to make a
- // // fixed length K.
- // if (k.bitLength() >= q.bitLength()) {
- // break;
- // }
- // }
- // } while (true);
-
- return k;
}
// Use the application-specified SecureRandom Object if provided.
diff --git a/src/java.base/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java b/src/java.base/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java
index 11d8a06..5f825ff 100644
--- a/src/java.base/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java
+++ b/src/java.base/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java
@@ -344,7 +344,7 @@
// add the algorithm checker
checkers.add(new AlgorithmChecker(builder.trustAnchor,
- buildParams.date(), null));
+ buildParams.date(), buildParams.variant()));
BasicChecker basicChecker = null;
if (nextState.keyParamsNeeded()) {
diff --git a/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java b/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java
index 9051b39..b763f7a 100644
--- a/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java
+++ b/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java
@@ -703,7 +703,6 @@
private int minSize; // the minimal available key size
private int maxSize; // the maximal available key size
private int prohibitedSize = -1; // unavailable key sizes
- private int size;
public KeySizeConstraint(String algo, Operator operator, int length) {
algorithm = algo;
@@ -761,8 +760,9 @@
return;
}
throw new CertPathValidatorException(
- "Algorithm constraints check failed on keysize limits. "
- + algorithm + " " + size + "bit key" + extendedMsg(cp),
+ "Algorithm constraints check failed on keysize limits. " +
+ algorithm + " " + KeyUtil.getKeySize(key) + "bit key" +
+ extendedMsg(cp),
null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
}
}
@@ -789,7 +789,7 @@
return true;
}
- size = KeyUtil.getKeySize(key);
+ int size = KeyUtil.getKeySize(key);
if (size == 0) {
return false; // we don't allow any key of size 0.
} else if (size > 0) {
diff --git a/src/java.base/share/classes/sun/security/util/HostnameChecker.java b/src/java.base/share/classes/sun/security/util/HostnameChecker.java
index 145dff2..b14d36b 100644
--- a/src/java.base/share/classes/sun/security/util/HostnameChecker.java
+++ b/src/java.base/share/classes/sun/security/util/HostnameChecker.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2017, 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
@@ -32,6 +32,7 @@
import java.security.cert.*;
import java.util.*;
import javax.security.auth.x500.X500Principal;
+import javax.net.ssl.SNIHostName;
import sun.net.util.IPAddressUtil;
import sun.security.ssl.ClientKeyExchangeService;
@@ -201,6 +202,15 @@
private void matchDNS(String expectedName, X509Certificate cert,
boolean chainsToPublicCA)
throws CertificateException {
+ // Check that the expected name is a valid domain name.
+ try {
+ // Using the checking implemented in SNIHostName
+ SNIHostName sni = new SNIHostName(expectedName);
+ } catch (IllegalArgumentException iae) {
+ throw new CertificateException(
+ "Illegal given domain name: " + expectedName, iae);
+ }
+
Collection<List<?>> subjAltNames = cert.getSubjectAlternativeNames();
if (subjAltNames != null) {
boolean foundDNS = false;
@@ -277,6 +287,19 @@
if (hasIllegalWildcard(name, template, chainsToPublicCA)) {
return false;
}
+
+ // check the validity of the domain name template.
+ try {
+ // Replacing wildcard character '*' with 'x' so as to check
+ // the domain name template validity.
+ //
+ // Using the checking implemented in SNIHostName
+ SNIHostName sni = new SNIHostName(template.replace('*', 'x'));
+ } catch (IllegalArgumentException iae) {
+ // It would be nice to add debug log if not matching.
+ return false;
+ }
+
if (checkType == TYPE_TLS) {
return matchAllWildcards(name, template);
} else if (checkType == TYPE_LDAP) {
diff --git a/src/java.base/share/classes/sun/security/util/ManifestEntryVerifier.java b/src/java.base/share/classes/sun/security/util/ManifestEntryVerifier.java
index 19cc730..6284047 100644
--- a/src/java.base/share/classes/sun/security/util/ManifestEntryVerifier.java
+++ b/src/java.base/share/classes/sun/security/util/ManifestEntryVerifier.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, 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
@@ -107,6 +107,8 @@
/* get the headers from the manifest for this entry */
/* if there aren't any, we can't verify any digests for this entry */
+ skip = false;
+
Attributes attr = man.getAttributes(name);
if (attr == null) {
// ugh. we should be able to remove this at some point.
@@ -141,7 +143,6 @@
}
if (digest != null) {
- skip = false;
digest.reset();
digests.add(digest);
manifestHashes.add(
@@ -197,6 +198,10 @@
return null;
}
+ if (digests.isEmpty()) {
+ throw new SecurityException("digest missing for " + name);
+ }
+
if (signers != null)
return signers;
diff --git a/src/java.base/share/conf/security/java.security b/src/java.base/share/conf/security/java.security
index a564f7c..5ddf619 100644
--- a/src/java.base/share/conf/security/java.security
+++ b/src/java.base/share/conf/security/java.security
@@ -545,21 +545,21 @@
# jdkCA
# This constraint prohibits the specified algorithm only if the
# algorithm is used in a certificate chain that terminates at a marked
-# trust anchor in the lib/security/cacerts keystore. If the jdkCA
-# constraint is not set, then all chains using the specified algorithm
+# trust anchor in the lib/security/cacerts keystore. If the jdkCA
+# constraint is not set, then all chains using the specified algorithm
# are restricted. jdkCA may only be used once in a DisabledAlgorithm
# expression.
-# Example: To apply this constraint to SHA-1 certificates, include
-# the following: "SHA1 jdkCA"
+# Example: To apply this constraint to SHA-1 certificates, include
+# the following: "SHA1 jdkCA"
#
# DenyAfterConstraint:
# denyAfter YYYY-MM-DD
# This constraint prohibits a certificate with the specified algorithm
# from being used after the date regardless of the certificate's
-# validity. JAR files that are signed and timestamped before the
+# validity. JAR files that are signed and timestamped before the
# constraint date with certificates containing the disabled algorithm
-# will not be restricted. The date is processed in the UTC timezone.
-# This constraint can only be used once in a DisabledAlgorithm
+# will not be restricted. The date is processed in the UTC timezone.
+# This constraint can only be used once in a DisabledAlgorithm
# expression.
# Example: To deny usage of RSA 2048 bit certificates after Feb 3 2020,
# use the following: "RSA keySize == 2048 & denyAfter 2020-02-03"
diff --git a/src/java.base/share/native/libverify/check_code.c b/src/java.base/share/native/libverify/check_code.c
index b278f25..e78627c 100644
--- a/src/java.base/share/native/libverify/check_code.c
+++ b/src/java.base/share/native/libverify/check_code.c
@@ -459,6 +459,8 @@
static fullinfo_type cp_index_to_class_fullinfo(context_type *, int, int);
+static const char* get_result_signature(const char* signature);
+
static char signature_to_fieldtype(context_type *context,
const char **signature_p, fullinfo_type *info);
@@ -2789,7 +2791,7 @@
operand);
const char *result_signature;
check_and_push(context, signature, VM_STRING_UTF);
- result_signature = strchr(signature, JVM_SIGNATURE_ENDFUNC);
+ result_signature = get_result_signature(signature);
if (result_signature++ == NULL) {
CCerror(context, "Illegal signature %s", signature);
}
@@ -3712,6 +3714,42 @@
longjmp(context->jump_buffer, 1);
}
+/*
+ * Need to scan the entire signature to find the result type because
+ * types in the arg list and the result type could contain embedded ')'s.
+ */
+static const char* get_result_signature(const char* signature) {
+ const char *p;
+ for (p = signature; *p != JVM_SIGNATURE_ENDFUNC; p++) {
+ switch (*p) {
+ case JVM_SIGNATURE_BOOLEAN:
+ case JVM_SIGNATURE_BYTE:
+ case JVM_SIGNATURE_CHAR:
+ case JVM_SIGNATURE_SHORT:
+ case JVM_SIGNATURE_INT:
+ case JVM_SIGNATURE_FLOAT:
+ case JVM_SIGNATURE_DOUBLE:
+ case JVM_SIGNATURE_LONG:
+ case JVM_SIGNATURE_FUNC: /* ignore initial (, if given */
+ break;
+ case JVM_SIGNATURE_CLASS:
+ while (*p != JVM_SIGNATURE_ENDCLASS) p++;
+ break;
+ case JVM_SIGNATURE_ARRAY:
+ while (*p == JVM_SIGNATURE_ARRAY) p++;
+ /* If an array of classes, skip over class name, too. */
+ if (*p == JVM_SIGNATURE_CLASS) {
+ while (*p != JVM_SIGNATURE_ENDCLASS) p++;
+ }
+ break;
+ default:
+ /* Indicate an error. */
+ return NULL;
+ }
+ }
+ return p++; /* skip over ')'. */
+}
+
static char
signature_to_fieldtype(context_type *context,
const char **signature_p, fullinfo_type *full_info_p)
diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java
index 3a1b4c1..e744095 100644
--- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java
+++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java
@@ -392,6 +392,17 @@
}
}
+ private void skipPastImage(int imageIndex) {
+ cbLock.lock();
+ try {
+ gotoImage(imageIndex);
+ skipImage();
+ } catch (IOException | IndexOutOfBoundsException e) {
+ } finally {
+ cbLock.unlock();
+ }
+ }
+
@SuppressWarnings("fallthrough")
private int getNumImagesOnThread(boolean allowSearch)
throws IOException {
@@ -1340,7 +1351,8 @@
* just a 1-line intermediate data transfer buffer that will not
* affect the acceleration of the resulting image.
*/
- boolean aborted = readImage(structPointer,
+ boolean aborted = readImage(imageIndex,
+ structPointer,
buffer.getData(),
numRasterBands,
srcBands,
@@ -1502,7 +1514,8 @@
/**
* Returns {@code true} if the read was aborted.
*/
- private native boolean readImage(long structPointer,
+ private native boolean readImage(int imageIndex,
+ long structPointer,
byte [] buffer,
int numRasterBands,
int [] srcBands,
diff --git a/src/java.desktop/share/classes/javax/imageio/spi/ServiceRegistry.java b/src/java.desktop/share/classes/javax/imageio/spi/ServiceRegistry.java
index 0d87431..ae3b643 100644
--- a/src/java.desktop/share/classes/javax/imageio/spi/ServiceRegistry.java
+++ b/src/java.desktop/share/classes/javax/imageio/spi/ServiceRegistry.java
@@ -26,6 +26,9 @@
package javax.imageio.spi;
import java.io.File;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
@@ -755,13 +758,14 @@
Class<?> category;
- // Provider Objects organized by partial oridering
- PartiallyOrderedSet<Object> poset = new PartiallyOrderedSet<>();
+ // Provider Objects organized by partial ordering
+ final PartiallyOrderedSet<Object> poset = new PartiallyOrderedSet<>();
// Class -> Provider Object of that class
// No way to express heterogeneous map, we want
// Map<Class<T>, T>, where T is ?
- Map<Class<?>, Object> map = new HashMap<>();
+ final Map<Class<?>, Object> map = new HashMap<>();
+ final Map<Class<?>, AccessControlContext> accMap = new HashMap<>();
public SubRegistry(ServiceRegistry registry, Class<?> category) {
this.registry = registry;
@@ -776,6 +780,7 @@
deregisterServiceProvider(oprovider);
}
map.put(provider.getClass(), provider);
+ accMap.put(provider.getClass(), AccessController.getContext());
poset.add(provider);
if (provider instanceof RegisterableService) {
RegisterableService rs = (RegisterableService)provider;
@@ -800,6 +805,7 @@
if (provider == oprovider) {
map.remove(provider.getClass());
+ accMap.remove(provider.getClass());
poset.remove(provider);
if (provider instanceof RegisterableService) {
RegisterableService rs = (RegisterableService)provider;
@@ -849,10 +855,17 @@
if (provider instanceof RegisterableService) {
RegisterableService rs = (RegisterableService)provider;
- rs.onDeregistration(registry, category);
+ AccessControlContext acc = accMap.get(provider.getClass());
+ if (acc != null || System.getSecurityManager() == null) {
+ AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
+ rs.onDeregistration(registry, category);
+ return null;
+ }, acc);
+ }
}
}
poset.clear();
+ accMap.clear();
}
@SuppressWarnings("deprecation")
diff --git a/src/java.desktop/share/classes/sun/awt/image/ImageWatched.java b/src/java.desktop/share/classes/sun/awt/image/ImageWatched.java
index b740aa1..07d9646 100644
--- a/src/java.desktop/share/classes/sun/awt/image/ImageWatched.java
+++ b/src/java.desktop/share/classes/sun/awt/image/ImageWatched.java
@@ -29,6 +29,10 @@
import java.awt.Image;
import java.awt.image.ImageObserver;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
public abstract class ImageWatched {
public static Link endlink = new Link();
@@ -85,16 +89,26 @@
}
}
+ static class AccWeakReference<T> extends WeakReference<T> {
+
+ private final AccessControlContext acc;
+
+ AccWeakReference(T ref) {
+ super(ref);
+ acc = AccessController.getContext();
+ }
+ }
+
/*
* Standard Link implementation to manage a Weak Reference
* to an ImageObserver.
*/
public static class WeakLink extends Link {
- private WeakReference<ImageObserver> myref;
+ private final AccWeakReference<ImageObserver> myref;
private Link next;
public WeakLink(ImageObserver obs, Link next) {
- myref = new WeakReference<ImageObserver>(obs);
+ myref = new AccWeakReference<ImageObserver>(obs);
this.next = next;
}
@@ -120,6 +134,19 @@
return this;
}
+ private static boolean update(ImageObserver iw, AccessControlContext acc,
+ Image img, int info,
+ int x, int y, int w, int h) {
+
+ if (acc != null || System.getSecurityManager() != null) {
+ return AccessController.doPrivileged(
+ (PrivilegedAction<Boolean>) () -> {
+ return iw.imageUpdate(img, info, x, y, w, h);
+ }, acc);
+ }
+ return false;
+ }
+
public boolean newInfo(Image img, int info,
int x, int y, int w, int h)
{
@@ -129,7 +156,7 @@
if (myiw == null) {
// My referent is null so we must prune in a second pass.
ret = true;
- } else if (myiw.imageUpdate(img, info, x, y, w, h) == false) {
+ } else if (update(myiw, myref.acc, img, info, x, y, w, h) == false) {
// My referent has lost interest so clear it and ask
// for a pruning pass to remove it later.
myref.clear();
diff --git a/src/java.desktop/share/native/libjavajpeg/imageioJPEG.c b/src/java.desktop/share/native/libjavajpeg/imageioJPEG.c
index 7fe4bd9..d0c60b9 100644
--- a/src/java.desktop/share/native/libjavajpeg/imageioJPEG.c
+++ b/src/java.desktop/share/native/libjavajpeg/imageioJPEG.c
@@ -72,6 +72,7 @@
static jmethodID JPEGImageReader_pushBackID;
static jmethodID JPEGImageReader_passStartedID;
static jmethodID JPEGImageReader_passCompleteID;
+static jmethodID JPEGImageReader_skipPastImageID;
static jmethodID JPEGImageWriter_writeOutputDataID;
static jmethodID JPEGImageWriter_warningOccurredID;
static jmethodID JPEGImageWriter_warningWithMessageID;
@@ -1472,6 +1473,10 @@
cls,
"pushBack",
"(I)V"));
+ CHECK_NULL(JPEGImageReader_skipPastImageID = (*env)->GetMethodID(env,
+ cls,
+ "skipPastImage",
+ "(I)V"));
CHECK_NULL(JPEGQTable_tableID = (*env)->GetFieldID(env,
qTableClass,
"qTable",
@@ -1853,6 +1858,7 @@
Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_readImage
(JNIEnv *env,
jobject this,
+ jint imageIndex,
jlong ptr,
jbyteArray buffer,
jint numBands,
@@ -2181,12 +2187,23 @@
* We are done, but we might not have read all the lines, or all
* the passes, so use jpeg_abort instead of jpeg_finish_decompress.
*/
- if (cinfo->output_scanline == cinfo->output_height) {
- // if ((cinfo->output_scanline == cinfo->output_height) &&
- //(jpeg_input_complete(cinfo))) { // We read the whole file
- jpeg_finish_decompress(cinfo);
- } else {
+ if ((cinfo->output_scanline != cinfo->output_height) ||
+ data->abortFlag == JNI_TRUE)
+ {
jpeg_abort_decompress(cinfo);
+ } else if ((!jpeg_input_complete(cinfo)) &&
+ (progressive &&
+ (cinfo->input_scan_number > maxProgressivePass))) {
+ /* We haven't reached EOI, but we need to skip to there */
+ (*cinfo->src->term_source) (cinfo);
+ /* We can use jpeg_abort to release memory and reset global_state */
+ jpeg_abort((j_common_ptr) cinfo);
+ (*env)->CallVoidMethod(env,
+ this,
+ JPEGImageReader_skipPastImageID,
+ imageIndex);
+ } else {
+ jpeg_finish_decompress(cinfo);
}
free(scanLinePtr);
diff --git a/src/java.naming/share/classes/com/sun/jndi/ldap/LdapClient.java b/src/java.naming/share/classes/com/sun/jndi/ldap/LdapClient.java
index c615971..125530f 100644
--- a/src/java.naming/share/classes/com/sun/jndi/ldap/LdapClient.java
+++ b/src/java.naming/share/classes/com/sun/jndi/ldap/LdapClient.java
@@ -1234,6 +1234,7 @@
static final int LDAP_REF_FOLLOW = 0x01; // follow referrals
static final int LDAP_REF_THROW = 0x02; // throw referral ex.
static final int LDAP_REF_IGNORE = 0x03; // ignore referrals
+ static final int LDAP_REF_FOLLOW_SCHEME = 0x04; // follow referrals of the same scheme
static final String LDAP_URL = "ldap://"; // LDAPv3
static final String LDAPS_URL = "ldaps://"; // LDAPv3
diff --git a/src/java.naming/share/classes/com/sun/jndi/ldap/LdapCtx.java b/src/java.naming/share/classes/com/sun/jndi/ldap/LdapCtx.java
index 6484c39..88185a0 100644
--- a/src/java.naming/share/classes/com/sun/jndi/ldap/LdapCtx.java
+++ b/src/java.naming/share/classes/com/sun/jndi/ldap/LdapCtx.java
@@ -2414,6 +2414,9 @@
// First determine the referral mode
if (ref != null) {
switch (ref) {
+ case "follow-scheme":
+ handleReferrals = LdapClient.LDAP_REF_FOLLOW_SCHEME;
+ break;
case "follow":
handleReferrals = LdapClient.LDAP_REF_FOLLOW;
break;
@@ -2979,8 +2982,23 @@
r = new LdapReferralException(resolvedName, resolvedObj, remainName,
msg, envprops, fullDN, handleReferrals, reqCtls);
// only one set of URLs is present
- r.setReferralInfo(res.referrals == null ? null :
- res.referrals.elementAt(0), false);
+ Vector<String> refs;
+ if (res.referrals == null) {
+ refs = null;
+ } else if (handleReferrals == LdapClient.LDAP_REF_FOLLOW_SCHEME) {
+ refs = new Vector<>();
+ for (String s : res.referrals.elementAt(0)) {
+ if (s.startsWith("ldap:")) {
+ refs.add(s);
+ }
+ }
+ if (refs.isEmpty()) {
+ refs = null;
+ }
+ } else {
+ refs = res.referrals.elementAt(0);
+ }
+ r.setReferralInfo(refs, false);
if (hopCount > 1) {
r.setHopCount(hopCount);
diff --git a/src/java.naming/share/classes/com/sun/jndi/ldap/LdapReferralException.java b/src/java.naming/share/classes/com/sun/jndi/ldap/LdapReferralException.java
index 62437c7..eb74e63 100644
--- a/src/java.naming/share/classes/com/sun/jndi/ldap/LdapReferralException.java
+++ b/src/java.naming/share/classes/com/sun/jndi/ldap/LdapReferralException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2017, 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
@@ -117,7 +117,8 @@
// If following referral, request controls are passed to referral ctx
this.reqCtls =
- (handleReferrals == LdapClient.LDAP_REF_FOLLOW ? reqCtls : null);
+ (handleReferrals == LdapClient.LDAP_REF_FOLLOW ||
+ handleReferrals == LdapClient.LDAP_REF_FOLLOW_SCHEME ? reqCtls : null);
}
/**
diff --git a/src/java.naming/share/classes/javax/naming/directory/BasicAttribute.java b/src/java.naming/share/classes/javax/naming/directory/BasicAttribute.java
index 41ab918..868fac6 100644
--- a/src/java.naming/share/classes/javax/naming/directory/BasicAttribute.java
+++ b/src/java.naming/share/classes/javax/naming/directory/BasicAttribute.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2017, 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
@@ -515,7 +515,7 @@
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject(); // read in the attrID
int n = s.readInt(); // number of values
- values = new Vector<>(n);
+ values = new Vector<>(Math.min(1024, n));
while (--n >= 0) {
values.addElement(s.readObject());
}
diff --git a/src/java.naming/share/classes/sun/security/provider/certpath/ldap/LDAPCertStoreImpl.java b/src/java.naming/share/classes/sun/security/provider/certpath/ldap/LDAPCertStoreImpl.java
index 1b9a2b0..8813ff6 100644
--- a/src/java.naming/share/classes/sun/security/provider/certpath/ldap/LDAPCertStoreImpl.java
+++ b/src/java.naming/share/classes/sun/security/provider/certpath/ldap/LDAPCertStoreImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, 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
@@ -186,7 +186,7 @@
*/
Hashtable<?,?> currentEnv = ctx.getEnvironment();
if (currentEnv.get(Context.REFERRAL) == null) {
- ctx.addToEnvironment(Context.REFERRAL, "follow");
+ ctx.addToEnvironment(Context.REFERRAL, "follow-scheme");
}
} catch (NamingException e) {
if (debug != null) {
diff --git a/src/java.rmi/share/classes/java/rmi/activation/ActivationID.java b/src/java.rmi/share/classes/java/rmi/activation/ActivationID.java
index 13b3a06..a7b2f99 100644
--- a/src/java.rmi/share/classes/java/rmi/activation/ActivationID.java
+++ b/src/java.rmi/share/classes/java/rmi/activation/ActivationID.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, 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
@@ -40,6 +40,12 @@
import java.rmi.server.RemoteObjectInvocationHandler;
import java.rmi.server.RemoteRef;
import java.rmi.server.UID;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.Permissions;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.security.ProtectionDomain;
/**
* Activation makes use of special identifiers to denote remote
@@ -81,6 +87,14 @@
/** indicate compatibility with the Java 2 SDK v1.2 version of class */
private static final long serialVersionUID = -4608673054848209235L;
+ /** an AccessControlContext with no permissions */
+ private static final AccessControlContext NOPERMS_ACC;
+ static {
+ Permissions perms = new Permissions();
+ ProtectionDomain[] pd = { new ProtectionDomain(null, perms) };
+ NOPERMS_ACC = new AccessControlContext(pd);
+ }
+
/**
* The constructor for <code>ActivationID</code> takes a single
* argument, activator, that specifies a remote reference to the
@@ -116,13 +130,19 @@
try {
MarshalledObject<? extends Remote> mobj =
activator.activate(this, force);
- return mobj.get();
- } catch (RemoteException e) {
- throw e;
- } catch (IOException e) {
- throw new UnmarshalException("activation failed", e);
- } catch (ClassNotFoundException e) {
- throw new UnmarshalException("activation failed", e);
+ return AccessController.doPrivileged(
+ new PrivilegedExceptionAction<Remote>() {
+ public Remote run() throws IOException, ClassNotFoundException {
+ return mobj.get();
+ }
+ }, NOPERMS_ACC);
+ } catch (PrivilegedActionException pae) {
+ Exception ex = pae.getException();
+ if (ex instanceof RemoteException) {
+ throw (RemoteException) ex;
+ } else {
+ throw new UnmarshalException("activation failed", ex);
+ }
}
}
diff --git a/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl.java b/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl.java
index 6b75a2a..af012fa 100644
--- a/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl.java
+++ b/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl.java
@@ -75,6 +75,10 @@
* registry.
*
* The LocateRegistry class is used to obtain registry for different hosts.
+ * <p>
+ * The default RegistryImpl exported restricts access to clients on the local host
+ * for the methods {@link #bind}, {@link #rebind}, {@link #unbind} by checking
+ * the client host in the skeleton.
*
* @see java.rmi.registry.LocateRegistry
*/
@@ -144,13 +148,27 @@
RMIServerSocketFactory ssf)
throws RemoteException
{
+ this(port, csf, ssf, RegistryImpl::registryFilter);
+ }
+
+
+ /**
+ * Construct a new RegistryImpl on the specified port with the
+ * given custom socket factory pair and ObjectInputFilter.
+ */
+ public RegistryImpl(int port,
+ RMIClientSocketFactory csf,
+ RMIServerSocketFactory ssf,
+ ObjectInputFilter serialFilter)
+ throws RemoteException
+ {
if (port == Registry.REGISTRY_PORT && System.getSecurityManager() != null) {
// grant permission for default port only.
try {
AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
public Void run() throws RemoteException {
LiveRef lref = new LiveRef(id, port, csf, ssf);
- setup(new UnicastServerRef2(lref, RegistryImpl::registryFilter));
+ setup(new UnicastServerRef2(lref, serialFilter));
return null;
}
}, null, new SocketPermission("localhost:"+port, "listen,accept"));
@@ -226,7 +244,8 @@
public void bind(String name, Remote obj)
throws RemoteException, AlreadyBoundException, AccessException
{
- checkAccess("Registry.bind");
+ // The access check preventing remote access is done in the skeleton
+ // and is not applicable to local access.
synchronized (bindings) {
Remote curr = bindings.get(name);
if (curr != null)
@@ -243,7 +262,8 @@
public void unbind(String name)
throws RemoteException, NotBoundException, AccessException
{
- checkAccess("Registry.unbind");
+ // The access check preventing remote access is done in the skeleton
+ // and is not applicable to local access.
synchronized (bindings) {
Remote obj = bindings.get(name);
if (obj == null)
@@ -259,7 +279,8 @@
public void rebind(String name, Remote obj)
throws RemoteException, AccessException
{
- checkAccess("Registry.rebind");
+ // The access check preventing remote access is done in the skeleton
+ // and is not applicable to local access.
bindings.put(name, obj);
}
@@ -312,7 +333,7 @@
if (clientHost.isAnyLocalAddress()) {
throw new AccessException(
- "Registry." + op + " disallowed; origin unknown");
+ op + " disallowed; origin unknown");
}
try {
@@ -335,7 +356,7 @@
// must have been an IOException
throw new AccessException(
- "Registry." + op + " disallowed; origin " +
+ op + " disallowed; origin " +
clientHost + " is non-local host");
}
}
@@ -344,8 +365,7 @@
* Local call from this VM: allow access.
*/
} catch (java.net.UnknownHostException ex) {
- throw new AccessException("Registry." + op +
- " disallowed; origin is unknown host");
+ throw new AccessException(op + " disallowed; origin is unknown host");
}
}
diff --git a/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl_Skel.java b/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl_Skel.java
new file mode 100644
index 0000000..842d477
--- /dev/null
+++ b/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl_Skel.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2017, 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.io.IOException;
+import java.io.InputStream;
+import java.rmi.AccessException;
+import java.rmi.server.RemoteCall;
+
+import sun.rmi.transport.Connection;
+import sun.rmi.transport.StreamRemoteCall;
+import sun.rmi.transport.tcp.TCPConnection;
+
+/**
+ * Skeleton to dispatch RegistryImpl methods.
+ * Originally generated by RMIC but frozen to match the stubs.
+ */
+@SuppressWarnings({"deprecation", "serial"})
+public final class RegistryImpl_Skel
+ implements java.rmi.server.Skeleton {
+ private static final java.rmi.server.Operation[] operations = {
+ new java.rmi.server.Operation("void bind(java.lang.String, java.rmi.Remote)"),
+ new java.rmi.server.Operation("java.lang.String list()[]"),
+ new java.rmi.server.Operation("java.rmi.Remote lookup(java.lang.String)"),
+ new java.rmi.server.Operation("void rebind(java.lang.String, java.rmi.Remote)"),
+ new java.rmi.server.Operation("void unbind(java.lang.String)")
+ };
+
+ private static final long interfaceHash = 4905912898345647071L;
+
+ public java.rmi.server.Operation[] getOperations() {
+ return operations.clone();
+ }
+
+ public void dispatch(java.rmi.Remote obj, java.rmi.server.RemoteCall call, int opnum, long hash)
+ throws java.lang.Exception {
+ if (hash != interfaceHash)
+ throw new java.rmi.server.SkeletonMismatchException("interface hash mismatch");
+
+ sun.rmi.registry.RegistryImpl server = (sun.rmi.registry.RegistryImpl) obj;
+ switch (opnum) {
+ case 0: // bind(String, Remote)
+ {
+ // Check access before reading the arguments
+ RegistryImpl.checkAccess("Registry.bind");
+
+ java.lang.String $param_String_1;
+ java.rmi.Remote $param_Remote_2;
+ try {
+ java.io.ObjectInput in = call.getInputStream();
+ $param_String_1 = (java.lang.String) in.readObject();
+ $param_Remote_2 = (java.rmi.Remote) in.readObject();
+ } catch (java.io.IOException | java.lang.ClassNotFoundException e) {
+ throw new java.rmi.UnmarshalException("error unmarshalling arguments", e);
+ } finally {
+ call.releaseInputStream();
+ }
+ server.bind($param_String_1, $param_Remote_2);
+ try {
+ call.getResultStream(true);
+ } catch (java.io.IOException e) {
+ throw new java.rmi.MarshalException("error marshalling return", e);
+ }
+ break;
+ }
+
+ case 1: // list()
+ {
+ call.releaseInputStream();
+ java.lang.String[] $result = server.list();
+ try {
+ java.io.ObjectOutput out = call.getResultStream(true);
+ out.writeObject($result);
+ } catch (java.io.IOException e) {
+ throw new java.rmi.MarshalException("error marshalling return", e);
+ }
+ break;
+ }
+
+ case 2: // lookup(String)
+ {
+ java.lang.String $param_String_1;
+ try {
+ java.io.ObjectInput in = call.getInputStream();
+ $param_String_1 = (java.lang.String) in.readObject();
+ } catch (java.io.IOException | java.lang.ClassNotFoundException e) {
+ throw new java.rmi.UnmarshalException("error unmarshalling arguments", e);
+ } finally {
+ call.releaseInputStream();
+ }
+ java.rmi.Remote $result = server.lookup($param_String_1);
+ try {
+ java.io.ObjectOutput out = call.getResultStream(true);
+ out.writeObject($result);
+ } catch (java.io.IOException e) {
+ throw new java.rmi.MarshalException("error marshalling return", e);
+ }
+ break;
+ }
+
+ case 3: // rebind(String, Remote)
+ {
+ // Check access before reading the arguments
+ RegistryImpl.checkAccess("Registry.rebind");
+
+ java.lang.String $param_String_1;
+ java.rmi.Remote $param_Remote_2;
+ try {
+ java.io.ObjectInput in = call.getInputStream();
+ $param_String_1 = (java.lang.String) in.readObject();
+ $param_Remote_2 = (java.rmi.Remote) in.readObject();
+ } catch (java.io.IOException | java.lang.ClassNotFoundException e) {
+ throw new java.rmi.UnmarshalException("error unmarshalling arguments", e);
+ } finally {
+ call.releaseInputStream();
+ }
+ server.rebind($param_String_1, $param_Remote_2);
+ try {
+ call.getResultStream(true);
+ } catch (java.io.IOException e) {
+ throw new java.rmi.MarshalException("error marshalling return", e);
+ }
+ break;
+ }
+
+ case 4: // unbind(String)
+ {
+ // Check access before reading the arguments
+ RegistryImpl.checkAccess("Registry.unbind");
+
+ java.lang.String $param_String_1;
+ try {
+ java.io.ObjectInput in = call.getInputStream();
+ $param_String_1 = (java.lang.String) in.readObject();
+ } catch (java.io.IOException | java.lang.ClassNotFoundException e) {
+ throw new java.rmi.UnmarshalException("error unmarshalling arguments", e);
+ } finally {
+ call.releaseInputStream();
+ }
+ server.unbind($param_String_1);
+ try {
+ call.getResultStream(true);
+ } catch (java.io.IOException e) {
+ throw new java.rmi.MarshalException("error marshalling return", e);
+ }
+ break;
+ }
+
+ default:
+ throw new java.rmi.UnmarshalException("invalid method number");
+ }
+ }
+}
diff --git a/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl_Stub.java b/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl_Stub.java
new file mode 100644
index 0000000..f857486
--- /dev/null
+++ b/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl_Stub.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2017, 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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;
+/**
+ * Stubs to invoke RegistryImpl remote methods.
+ * Originally generated from RMIC but frozen to match RegistryImpl_Skel.
+ */
+@SuppressWarnings({"deprecation", "serial"})
+public final class RegistryImpl_Stub
+ extends java.rmi.server.RemoteStub
+ implements java.rmi.registry.Registry, java.rmi.Remote {
+ private static final java.rmi.server.Operation[] operations = {
+ new java.rmi.server.Operation("void bind(java.lang.String, java.rmi.Remote)"),
+ new java.rmi.server.Operation("java.lang.String list()[]"),
+ new java.rmi.server.Operation("java.rmi.Remote lookup(java.lang.String)"),
+ new java.rmi.server.Operation("void rebind(java.lang.String, java.rmi.Remote)"),
+ new java.rmi.server.Operation("void unbind(java.lang.String)")
+ };
+
+ private static final long interfaceHash = 4905912898345647071L;
+
+ // constructors
+ public RegistryImpl_Stub() {
+ super();
+ }
+
+ public RegistryImpl_Stub(java.rmi.server.RemoteRef ref) {
+ super(ref);
+ }
+
+ // methods from remote interfaces
+
+ // implementation of bind(String, Remote)
+ public void bind(java.lang.String $param_String_1, java.rmi.Remote $param_Remote_2)
+ throws java.rmi.AccessException, java.rmi.AlreadyBoundException, java.rmi.RemoteException {
+ try {
+ java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 0, interfaceHash);
+ try {
+ java.io.ObjectOutput out = call.getOutputStream();
+ out.writeObject($param_String_1);
+ out.writeObject($param_Remote_2);
+ } catch (java.io.IOException e) {
+ throw new java.rmi.MarshalException("error marshalling arguments", e);
+ }
+ ref.invoke(call);
+ ref.done(call);
+ } catch (java.lang.RuntimeException e) {
+ throw e;
+ } catch (java.rmi.RemoteException e) {
+ throw e;
+ } catch (java.rmi.AlreadyBoundException e) {
+ throw e;
+ } catch (java.lang.Exception e) {
+ throw new java.rmi.UnexpectedException("undeclared checked exception", e);
+ }
+ }
+
+ // implementation of list()
+ public java.lang.String[] list()
+ throws java.rmi.AccessException, java.rmi.RemoteException {
+ try {
+ java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 1, interfaceHash);
+ ref.invoke(call);
+ java.lang.String[] $result;
+ try {
+ java.io.ObjectInput in = call.getInputStream();
+ $result = (java.lang.String[]) in.readObject();
+ } catch (java.io.IOException e) {
+ throw new java.rmi.UnmarshalException("error unmarshalling return", e);
+ } catch (java.lang.ClassNotFoundException e) {
+ throw new java.rmi.UnmarshalException("error unmarshalling return", e);
+ } finally {
+ ref.done(call);
+ }
+ return $result;
+ } catch (java.lang.RuntimeException e) {
+ throw e;
+ } catch (java.rmi.RemoteException e) {
+ throw e;
+ } catch (java.lang.Exception e) {
+ throw new java.rmi.UnexpectedException("undeclared checked exception", e);
+ }
+ }
+
+ // implementation of lookup(String)
+ public java.rmi.Remote lookup(java.lang.String $param_String_1)
+ throws java.rmi.AccessException, java.rmi.NotBoundException, java.rmi.RemoteException {
+ try {
+ java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 2, interfaceHash);
+ try {
+ java.io.ObjectOutput out = call.getOutputStream();
+ out.writeObject($param_String_1);
+ } catch (java.io.IOException e) {
+ throw new java.rmi.MarshalException("error marshalling arguments", e);
+ }
+ ref.invoke(call);
+ java.rmi.Remote $result;
+ try {
+ java.io.ObjectInput in = call.getInputStream();
+ $result = (java.rmi.Remote) in.readObject();
+ } catch (java.io.IOException e) {
+ throw new java.rmi.UnmarshalException("error unmarshalling return", e);
+ } catch (java.lang.ClassNotFoundException e) {
+ throw new java.rmi.UnmarshalException("error unmarshalling return", e);
+ } finally {
+ ref.done(call);
+ }
+ return $result;
+ } catch (java.lang.RuntimeException e) {
+ throw e;
+ } catch (java.rmi.RemoteException e) {
+ throw e;
+ } catch (java.rmi.NotBoundException e) {
+ throw e;
+ } catch (java.lang.Exception e) {
+ throw new java.rmi.UnexpectedException("undeclared checked exception", e);
+ }
+ }
+
+ // implementation of rebind(String, Remote)
+ public void rebind(java.lang.String $param_String_1, java.rmi.Remote $param_Remote_2)
+ throws java.rmi.AccessException, java.rmi.RemoteException {
+ try {
+ java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 3, interfaceHash);
+ try {
+ java.io.ObjectOutput out = call.getOutputStream();
+ out.writeObject($param_String_1);
+ out.writeObject($param_Remote_2);
+ } catch (java.io.IOException e) {
+ throw new java.rmi.MarshalException("error marshalling arguments", e);
+ }
+ ref.invoke(call);
+ ref.done(call);
+ } catch (java.lang.RuntimeException e) {
+ throw e;
+ } catch (java.rmi.RemoteException e) {
+ throw e;
+ } catch (java.lang.Exception e) {
+ throw new java.rmi.UnexpectedException("undeclared checked exception", e);
+ }
+ }
+
+ // implementation of unbind(String)
+ public void unbind(java.lang.String $param_String_1)
+ throws java.rmi.AccessException, java.rmi.NotBoundException, java.rmi.RemoteException {
+ try {
+ java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 4, interfaceHash);
+ try {
+ java.io.ObjectOutput out = call.getOutputStream();
+ out.writeObject($param_String_1);
+ } catch (java.io.IOException e) {
+ throw new java.rmi.MarshalException("error marshalling arguments", e);
+ }
+ ref.invoke(call);
+ ref.done(call);
+ } catch (java.lang.RuntimeException e) {
+ throw e;
+ } catch (java.rmi.RemoteException e) {
+ throw e;
+ } catch (java.rmi.NotBoundException e) {
+ throw e;
+ } catch (java.lang.Exception e) {
+ throw new java.rmi.UnexpectedException("undeclared checked exception", e);
+ }
+ }
+}
diff --git a/src/java.rmi/share/classes/sun/rmi/server/Activation.java b/src/java.rmi/share/classes/sun/rmi/server/Activation.java
index a6ebbca..6c60f46 100644
--- a/src/java.rmi/share/classes/sun/rmi/server/Activation.java
+++ b/src/java.rmi/share/classes/sun/rmi/server/Activation.java
@@ -30,6 +30,7 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.OutputStream;
import java.io.PrintStream;
@@ -105,7 +106,6 @@
import sun.rmi.log.ReliableLog;
import sun.rmi.registry.RegistryImpl;
import sun.rmi.runtime.NewThreadAction;
-import sun.rmi.server.UnicastServerRef;
import sun.rmi.transport.LiveRef;
import sun.security.provider.PolicyFile;
import com.sun.rmi.rmid.ExecPermission;
@@ -375,6 +375,7 @@
throw new AccessException(
"binding ActivationSystem is disallowed");
} else {
+ RegistryImpl.checkAccess("ActivationSystem.bind");
super.bind(name, obj);
}
}
@@ -386,6 +387,7 @@
throw new AccessException(
"unbinding ActivationSystem is disallowed");
} else {
+ RegistryImpl.checkAccess("ActivationSystem.unbind");
super.unbind(name);
}
}
@@ -398,6 +400,7 @@
throw new AccessException(
"binding ActivationSystem is disallowed");
} else {
+ RegistryImpl.checkAccess("ActivationSystem.rebind");
super.rebind(name, obj);
}
}
@@ -488,6 +491,33 @@
}
+ /**
+ * SameHostOnlyServerRef checks that access is from a local client
+ * before the parameters are deserialized. The unmarshalCustomCallData
+ * hook is used to check the network address of the caller
+ * with RegistryImpl.checkAccess().
+ * The kind of access is retained for an exception if one is thrown.
+ */
+ static class SameHostOnlyServerRef extends UnicastServerRef {
+ private static final long serialVersionUID = 1234L;
+ private String accessKind; // an exception message
+
+ /**
+ * Construct a new SameHostOnlyServerRef from a LiveRef.
+ * @param lref a LiveRef
+ */
+ SameHostOnlyServerRef(LiveRef lref, String accessKind) {
+ super(lref);
+ this.accessKind = accessKind;
+ }
+
+ @Override
+ protected void unmarshalCustomCallData(ObjectInput in) throws IOException, ClassNotFoundException {
+ RegistryImpl.checkAccess(accessKind);
+ super.unmarshalCustomCallData(in);
+ }
+ }
+
class ActivationSystemImpl
extends RemoteServer
implements ActivationSystem
@@ -505,7 +535,8 @@
* 'this' can be exported.
*/
LiveRef lref = new LiveRef(new ObjID(4), port, null, ssf);
- UnicastServerRef uref = new UnicastServerRef(lref);
+ UnicastServerRef uref = new SameHostOnlyServerRef(lref,
+ "ActivationSystem.nonLocalAccess");
ref = uref;
uref.exportObject(this, null);
}
@@ -514,8 +545,8 @@
throws ActivationException, UnknownGroupException, RemoteException
{
checkShutdown();
- RegistryImpl.checkAccess("ActivationSystem.registerObject");
-
+ // RegistryImpl.checkAccess() is done in the SameHostOnlyServerRef
+ // during unmarshallCustomData and is not applicable to local access.
ActivationGroupID groupID = desc.getGroupID();
ActivationID id = new ActivationID(activatorStub);
getGroupEntry(groupID).registerObject(id, desc, true);
@@ -526,7 +557,8 @@
throws ActivationException, UnknownObjectException, RemoteException
{
checkShutdown();
- RegistryImpl.checkAccess("ActivationSystem.unregisterObject");
+ // RegistryImpl.checkAccess() is done in the SameHostOnlyServerRef
+ // during unmarshallCustomData and is not applicable to local access.
getGroupEntry(id).unregisterObject(id, true);
}
@@ -534,7 +566,8 @@
throws ActivationException, RemoteException
{
checkShutdown();
- RegistryImpl.checkAccess("ActivationSystem.registerGroup");
+ // RegistryImpl.checkAccess() is done in the SameHostOnlyServerRef
+ // during unmarshallCustomData and is not applicable to local access.
checkArgs(desc, null);
ActivationGroupID id = new ActivationGroupID(systemStub);
@@ -551,7 +584,8 @@
throws ActivationException, UnknownGroupException, RemoteException
{
checkShutdown();
- RegistryImpl.checkAccess("ActivationSystem.activeGroup");
+ // RegistryImpl.checkAccess() is done in the SameHostOnlyServerRef
+ // during unmarshallCustomData and is not applicable to local access.
getGroupEntry(id).activeGroup(group, incarnation);
return monitor;
@@ -561,7 +595,8 @@
throws ActivationException, UnknownGroupException, RemoteException
{
checkShutdown();
- RegistryImpl.checkAccess("ActivationSystem.unregisterGroup");
+ // RegistryImpl.checkAccess() is done in the SameHostOnlyServerRef
+ // during unmarshallCustomData and is not applicable to local access.
// remove entry before unregister so state is updated before
// logged
@@ -573,7 +608,8 @@
throws ActivationException, UnknownObjectException, RemoteException
{
checkShutdown();
- RegistryImpl.checkAccess("ActivationSystem.setActivationDesc");
+ // RegistryImpl.checkAccess() is done in the SameHostOnlyServerRef
+ // during unmarshallCustomData and is not applicable to local access.
if (!getGroupID(id).equals(desc.getGroupID())) {
throw new ActivationException(
@@ -587,8 +623,8 @@
throws ActivationException, UnknownGroupException, RemoteException
{
checkShutdown();
- RegistryImpl.checkAccess(
- "ActivationSystem.setActivationGroupDesc");
+ // RegistryImpl.checkAccess() is done in the SameHostOnlyServerRef
+ // during unmarshallCustomData and is not applicable to local access.
checkArgs(desc, null);
return getGroupEntry(id).setActivationGroupDesc(id, desc, true);
@@ -598,7 +634,8 @@
throws ActivationException, UnknownObjectException, RemoteException
{
checkShutdown();
- RegistryImpl.checkAccess("ActivationSystem.getActivationDesc");
+ // RegistryImpl.checkAccess() is done in the SameHostOnlyServerRef
+ // during unmarshallCustomData and is not applicable to local access.
return getGroupEntry(id).getActivationDesc(id);
}
@@ -607,8 +644,8 @@
throws ActivationException, UnknownGroupException, RemoteException
{
checkShutdown();
- RegistryImpl.checkAccess
- ("ActivationSystem.getActivationGroupDesc");
+ // RegistryImpl.checkAccess() is done in the SameHostOnlyServerRef
+ // during unmarshallCustomData and is not applicable to local access.
return getGroupEntry(id).desc;
}
@@ -618,7 +655,8 @@
* the activation daemon and exits the activation daemon.
*/
public void shutdown() throws AccessException {
- RegistryImpl.checkAccess("ActivationSystem.shutdown");
+ // RegistryImpl.checkAccess() is done in the SameHostOnlyServerRef
+ // during unmarshallCustomData and is not applicable to local access.
Object lock = startupLock;
if (lock != null) {
diff --git a/src/java.rmi/share/classes/sun/rmi/server/UnicastRef.java b/src/java.rmi/share/classes/sun/rmi/server/UnicastRef.java
index a581235..6b9aec5 100644
--- a/src/java.rmi/share/classes/sun/rmi/server/UnicastRef.java
+++ b/src/java.rmi/share/classes/sun/rmi/server/UnicastRef.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2017, 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
@@ -32,7 +32,6 @@
import java.rmi.MarshalException;
import java.rmi.Remote;
import java.rmi.RemoteException;
-import java.rmi.ServerException;
import java.rmi.UnmarshalException;
import java.rmi.server.Operation;
import java.rmi.server.RemoteCall;
@@ -187,14 +186,11 @@
return returnValue;
- } catch (IOException e) {
+ } catch (IOException | ClassNotFoundException e) {
+ // disable saving any refs in the inputStream for GC
+ ((StreamRemoteCall)call).discardPendingRefs();
clientRefLog.log(Log.BRIEF,
- "IOException unmarshalling return: ", e);
- throw new UnmarshalException("error unmarshalling return", e);
- } catch (ClassNotFoundException e) {
- clientRefLog.log(Log.BRIEF,
- "ClassNotFoundException unmarshalling return: ", e);
-
+ e.getClass().getName() + " unmarshalling return: ", e);
throw new UnmarshalException("error unmarshalling return", e);
} finally {
try {
diff --git a/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef.java b/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef.java
index 65437b7..f0a4e0f 100644
--- a/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef.java
+++ b/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2017, 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
@@ -33,6 +33,7 @@
import java.io.ObjectStreamClass;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.rmi.AccessException;
import java.rmi.MarshalException;
import java.rmi.Remote;
import java.rmi.RemoteException;
@@ -57,6 +58,7 @@
import java.util.concurrent.atomic.AtomicInteger;
import sun.rmi.runtime.Log;
import sun.rmi.transport.LiveRef;
+import sun.rmi.transport.StreamRemoteCall;
import sun.rmi.transport.Target;
import sun.rmi.transport.tcp.TCPTransport;
@@ -287,21 +289,26 @@
try {
in = call.getInputStream();
num = in.readInt();
- if (num >= 0) {
- if (skel != null) {
- oldDispatch(obj, call, num);
- return;
- } else {
- throw new UnmarshalException(
- "skeleton class not found but required " +
- "for client version");
- }
- }
- op = in.readLong();
} catch (Exception readEx) {
throw new UnmarshalException("error unmarshalling call header",
readEx);
}
+ if (num >= 0) {
+ if (skel != null) {
+ oldDispatch(obj, call, num);
+ return;
+ } else {
+ throw new UnmarshalException(
+ "skeleton class not found but required " +
+ "for client version");
+ }
+ }
+ try {
+ op = in.readLong();
+ } catch (Exception readEx) {
+ throw new UnmarshalException("error unmarshalling call header",
+ readEx);
+ }
/*
* Since only system classes (with null class loaders) will be on
@@ -328,10 +335,14 @@
try {
unmarshalCustomCallData(in);
params = unmarshalParameters(obj, method, marshalStream);
- } catch (java.io.IOException e) {
- throw new UnmarshalException(
- "error unmarshalling arguments", e);
- } catch (ClassNotFoundException e) {
+ } catch (AccessException aex) {
+ // For compatibility, AccessException is not wrapped in UnmarshalException
+ // disable saving any refs in the inputStream for GC
+ ((StreamRemoteCall) call).discardPendingRefs();
+ throw aex;
+ } catch (java.io.IOException | ClassNotFoundException e) {
+ // disable saving any refs in the inputStream for GC
+ ((StreamRemoteCall) call).discardPendingRefs();
throw new UnmarshalException(
"error unmarshalling arguments", e);
} finally {
@@ -365,6 +376,7 @@
*/
}
} catch (Throwable e) {
+ Throwable origEx = e;
logCallException(e);
ObjectOutput out = call.getResultStream(false);
@@ -380,6 +392,12 @@
clearStackTraces(e);
}
out.writeObject(e);
+
+ // AccessExceptions should cause Transport.serviceCall
+ // to flag the connection as unusable.
+ if (origEx instanceof AccessException) {
+ throw new IOException("Connection is not reusable", origEx);
+ }
} finally {
call.releaseInputStream(); // in case skeleton doesn't
call.releaseOutputStream();
@@ -408,62 +426,41 @@
* Handle server-side dispatch using the RMI 1.1 stub/skeleton
* protocol, given a non-negative operation number that has
* already been read from the call stream.
+ * Exceptions are handled by the caller to be sent to the remote client.
*
* @param obj the target remote object for the call
* @param call the "remote call" from which operation and
* method arguments can be obtained.
* @param op the operation number
- * @exception IOException if unable to marshal return result or
+ * @throws Exception if unable to marshal return result or
* release input or output streams
*/
- public void oldDispatch(Remote obj, RemoteCall call, int op)
- throws IOException
+ private void oldDispatch(Remote obj, RemoteCall call, int op)
+ throws Exception
{
long hash; // hash for matching stub with skeleton
+ // read remote call header
+ ObjectInput in;
+ in = call.getInputStream();
try {
- // read remote call header
- ObjectInput in;
- try {
- in = call.getInputStream();
- try {
- Class<?> clazz = Class.forName("sun.rmi.transport.DGCImpl_Skel");
- if (clazz.isAssignableFrom(skel.getClass())) {
- ((MarshalInputStream)in).useCodebaseOnly();
- }
- } catch (ClassNotFoundException ignore) { }
- hash = in.readLong();
- } catch (Exception readEx) {
- throw new UnmarshalException("error unmarshalling call header",
- readEx);
+ Class<?> clazz = Class.forName("sun.rmi.transport.DGCImpl_Skel");
+ if (clazz.isAssignableFrom(skel.getClass())) {
+ ((MarshalInputStream)in).useCodebaseOnly();
}
+ } catch (ClassNotFoundException ignore) { }
- // if calls are being logged, write out object id and operation
- logCall(obj, skel.getOperations()[op]);
- unmarshalCustomCallData(in);
- // dispatch to skeleton for remote object
- skel.dispatch(obj, call, op, hash);
-
- } catch (Throwable e) {
- logCallException(e);
-
- ObjectOutput out = call.getResultStream(false);
- if (e instanceof Error) {
- e = new ServerError(
- "Error occurred in server thread", (Error) e);
- } else if (e instanceof RemoteException) {
- e = new ServerException(
- "RemoteException occurred in server thread",
- (Exception) e);
- }
- if (suppressStackTraces) {
- clearStackTraces(e);
- }
- out.writeObject(e);
- } finally {
- call.releaseInputStream(); // in case skeleton doesn't
- call.releaseOutputStream();
+ try {
+ hash = in.readLong();
+ } catch (Exception ioe) {
+ throw new UnmarshalException("error unmarshalling call header", ioe);
}
+
+ // if calls are being logged, write out object id and operation
+ logCall(obj, skel.getOperations()[op]);
+ unmarshalCustomCallData(in);
+ // dispatch to skeleton for remote object
+ skel.dispatch(obj, call, op, hash);
}
/**
diff --git a/src/java.rmi/share/classes/sun/rmi/transport/ConnectionInputStream.java b/src/java.rmi/share/classes/sun/rmi/transport/ConnectionInputStream.java
index c0ff825..e6917f7 100644
--- a/src/java.rmi/share/classes/sun/rmi/transport/ConnectionInputStream.java
+++ b/src/java.rmi/share/classes/sun/rmi/transport/ConnectionInputStream.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2017, 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
@@ -82,6 +82,14 @@
}
/**
+ * Discard the saved incoming refs so there is nothing to register
+ * when {@code registerRefs} is called.
+ */
+ void discardRefs() {
+ incomingRefTable.clear();
+ }
+
+ /**
* Add references to DGC table (and possibly send dirty call).
* RegisterRefs now calls DGCClient.referenced on all
* refs with the same endpoint at once to achieve batching of
diff --git a/src/java.rmi/share/classes/sun/rmi/transport/DGCClient.java b/src/java.rmi/share/classes/sun/rmi/transport/DGCClient.java
index 71fc403..89144a2 100644
--- a/src/java.rmi/share/classes/sun/rmi/transport/DGCClient.java
+++ b/src/java.rmi/share/classes/sun/rmi/transport/DGCClient.java
@@ -24,9 +24,11 @@
*/
package sun.rmi.transport;
+import java.io.InvalidClassException;
import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
import java.net.SocketPermission;
+import java.rmi.UnmarshalException;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.HashMap;
@@ -41,6 +43,8 @@
import java.rmi.dgc.Lease;
import java.rmi.dgc.VMID;
import java.rmi.server.ObjID;
+
+import sun.rmi.runtime.Log;
import sun.rmi.runtime.NewThreadAction;
import sun.rmi.server.UnicastRef;
import sun.rmi.server.Util;
@@ -388,6 +392,12 @@
synchronized (this) {
dirtyFailures++;
+ if (e instanceof UnmarshalException
+ && e.getCause() instanceof InvalidClassException) {
+ DGCImpl.dgcLog.log(Log.BRIEF, "InvalidClassException exception in DGC dirty call", e);
+ return; // protocol error, do not register these refs
+ }
+
if (dirtyFailures == 1) {
/*
* If this was the first recent failed dirty call,
diff --git a/src/java.rmi/share/classes/sun/rmi/transport/DGCImpl_Skel.java b/src/java.rmi/share/classes/sun/rmi/transport/DGCImpl_Skel.java
new file mode 100644
index 0000000..f991a6e
--- /dev/null
+++ b/src/java.rmi/share/classes/sun/rmi/transport/DGCImpl_Skel.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2017, 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.transport;
+
+/**
+ * Skeleton to dispatch DGC methods.
+ * Originally generated by RMIC but frozen to match the stubs.
+ */
+@SuppressWarnings({"deprecation", "serial"})
+public final class DGCImpl_Skel
+ implements java.rmi.server.Skeleton {
+ private static final java.rmi.server.Operation[] operations = {
+ new java.rmi.server.Operation("void clean(java.rmi.server.ObjID[], long, java.rmi.dgc.VMID, boolean)"),
+ new java.rmi.server.Operation("java.rmi.dgc.Lease dirty(java.rmi.server.ObjID[], long, java.rmi.dgc.Lease)")
+ };
+
+ private static final long interfaceHash = -669196253586618813L;
+
+ public java.rmi.server.Operation[] getOperations() {
+ return operations.clone();
+ }
+
+ public void dispatch(java.rmi.Remote obj, java.rmi.server.RemoteCall call, int opnum, long hash)
+ throws java.lang.Exception {
+ if (hash != interfaceHash)
+ throw new java.rmi.server.SkeletonMismatchException("interface hash mismatch");
+
+ sun.rmi.transport.DGCImpl server = (sun.rmi.transport.DGCImpl) obj;
+ switch (opnum) {
+ case 0: // clean(ObjID[], long, VMID, boolean)
+ {
+ java.rmi.server.ObjID[] $param_arrayOf_ObjID_1;
+ long $param_long_2;
+ java.rmi.dgc.VMID $param_VMID_3;
+ boolean $param_boolean_4;
+ try {
+ java.io.ObjectInput in = call.getInputStream();
+ $param_arrayOf_ObjID_1 = (java.rmi.server.ObjID[]) in.readObject();
+ $param_long_2 = in.readLong();
+ $param_VMID_3 = (java.rmi.dgc.VMID) in.readObject();
+ $param_boolean_4 = in.readBoolean();
+ } catch (java.io.IOException e) {
+ throw new java.rmi.UnmarshalException("error unmarshalling arguments", e);
+ } catch (java.lang.ClassNotFoundException e) {
+ throw new java.rmi.UnmarshalException("error unmarshalling arguments", e);
+ } finally {
+ call.releaseInputStream();
+ }
+ server.clean($param_arrayOf_ObjID_1, $param_long_2, $param_VMID_3, $param_boolean_4);
+ try {
+ call.getResultStream(true);
+ } catch (java.io.IOException e) {
+ throw new java.rmi.MarshalException("error marshalling return", e);
+ }
+ break;
+ }
+
+ case 1: // dirty(ObjID[], long, Lease)
+ {
+ java.rmi.server.ObjID[] $param_arrayOf_ObjID_1;
+ long $param_long_2;
+ java.rmi.dgc.Lease $param_Lease_3;
+ try {
+ java.io.ObjectInput in = call.getInputStream();
+ $param_arrayOf_ObjID_1 = (java.rmi.server.ObjID[]) in.readObject();
+ $param_long_2 = in.readLong();
+ $param_Lease_3 = (java.rmi.dgc.Lease) in.readObject();
+ } catch (java.io.IOException e) {
+ throw new java.rmi.UnmarshalException("error unmarshalling arguments", e);
+ } catch (java.lang.ClassNotFoundException e) {
+ throw new java.rmi.UnmarshalException("error unmarshalling arguments", e);
+ } finally {
+ call.releaseInputStream();
+ }
+ java.rmi.dgc.Lease $result = server.dirty($param_arrayOf_ObjID_1, $param_long_2, $param_Lease_3);
+ try {
+ java.io.ObjectOutput out = call.getResultStream(true);
+ out.writeObject($result);
+ } catch (java.io.IOException e) {
+ throw new java.rmi.MarshalException("error marshalling return", e);
+ }
+ break;
+ }
+
+ default:
+ throw new java.rmi.UnmarshalException("invalid method number");
+ }
+ }
+}
diff --git a/src/java.rmi/share/classes/sun/rmi/transport/DGCImpl_Stub.java b/src/java.rmi/share/classes/sun/rmi/transport/DGCImpl_Stub.java
new file mode 100644
index 0000000..cc44ff8
--- /dev/null
+++ b/src/java.rmi/share/classes/sun/rmi/transport/DGCImpl_Stub.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2017, 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.transport;
+
+import java.io.ObjectInputFilter;
+import java.io.ObjectInputStream;
+import java.rmi.dgc.Lease;
+import java.rmi.dgc.VMID;
+import java.rmi.server.UID;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+import sun.rmi.server.UnicastRef;
+import sun.rmi.transport.tcp.TCPConnection;
+
+/**
+ * Stubs to invoke DGC remote methods.
+ * Originally generated from RMIC but frozen to insert serialFilter.
+ */
+@SuppressWarnings({"deprecation", "serial"})
+public final class DGCImpl_Stub
+ extends java.rmi.server.RemoteStub
+ implements java.rmi.dgc.DGC {
+ private static final java.rmi.server.Operation[] operations = {
+ new java.rmi.server.Operation("void clean(java.rmi.server.ObjID[], long, java.rmi.dgc.VMID, boolean)"),
+ new java.rmi.server.Operation("java.rmi.dgc.Lease dirty(java.rmi.server.ObjID[], long, java.rmi.dgc.Lease)")
+ };
+
+ private static final long interfaceHash = -669196253586618813L;
+
+ /** Registry max depth of remote invocations. **/
+ private static int DGCCLIENT_MAX_DEPTH = 6;
+
+ /** Registry maximum array size in remote invocations. **/
+ private static int DGCCLIENT_MAX_ARRAY_SIZE = 10000;
+
+ // constructors
+ public DGCImpl_Stub() {
+ super();
+ }
+
+ public DGCImpl_Stub(java.rmi.server.RemoteRef ref) {
+ super(ref);
+ }
+
+ // methods from remote interfaces
+
+ // implementation of clean(ObjID[], long, VMID, boolean)
+ public void clean(java.rmi.server.ObjID[] $param_arrayOf_ObjID_1, long $param_long_2, java.rmi.dgc.VMID $param_VMID_3, boolean $param_boolean_4)
+ throws java.rmi.RemoteException {
+ try {
+ java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 0, interfaceHash);
+ try {
+ java.io.ObjectOutput out = call.getOutputStream();
+ out.writeObject($param_arrayOf_ObjID_1);
+ out.writeLong($param_long_2);
+ out.writeObject($param_VMID_3);
+ out.writeBoolean($param_boolean_4);
+ } catch (java.io.IOException e) {
+ throw new java.rmi.MarshalException("error marshalling arguments", e);
+ }
+ ref.invoke(call);
+ ref.done(call);
+ } catch (java.lang.RuntimeException e) {
+ throw e;
+ } catch (java.rmi.RemoteException e) {
+ throw e;
+ } catch (java.lang.Exception e) {
+ throw new java.rmi.UnexpectedException("undeclared checked exception", e);
+ }
+ }
+
+ // implementation of dirty(ObjID[], long, Lease)
+ public java.rmi.dgc.Lease dirty(java.rmi.server.ObjID[] $param_arrayOf_ObjID_1, long $param_long_2, java.rmi.dgc.Lease $param_Lease_3)
+ throws java.rmi.RemoteException {
+ try {
+ java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 1, interfaceHash);
+ try {
+ java.io.ObjectOutput out = call.getOutputStream();
+ out.writeObject($param_arrayOf_ObjID_1);
+ out.writeLong($param_long_2);
+ out.writeObject($param_Lease_3);
+ } catch (java.io.IOException e) {
+ throw new java.rmi.MarshalException("error marshalling arguments", e);
+ }
+ ref.invoke(call);
+ java.rmi.dgc.Lease $result;
+ Connection connection = ((StreamRemoteCall) call).getConnection();
+ try {
+ java.io.ObjectInput in = call.getInputStream();
+
+ if (in instanceof ObjectInputStream) {
+ /**
+ * Set a filter on the stream for the return value.
+ */
+ ObjectInputStream ois = (ObjectInputStream) in;
+ AccessController.doPrivileged((PrivilegedAction<Void>)() -> {
+ ois.setObjectInputFilter(DGCImpl_Stub::leaseFilter);
+ return null;
+ });
+ }
+ $result = (java.rmi.dgc.Lease) in.readObject();
+ } catch (java.io.IOException | java.lang.ClassNotFoundException e) {
+ if (connection instanceof TCPConnection) {
+ // Modified to prevent re-use of the connection after an exception
+ ((TCPConnection) connection).getChannel().free(connection, false);
+ }
+ throw new java.rmi.UnmarshalException("error unmarshalling return", e);
+ } finally {
+ ref.done(call);
+ }
+ return $result;
+ } catch (java.lang.RuntimeException e) {
+ throw e;
+ } catch (java.rmi.RemoteException e) {
+ throw e;
+ } catch (java.lang.Exception e) {
+ throw new java.rmi.UnexpectedException("undeclared checked exception", e);
+ }
+ }
+
+ /**
+ * ObjectInputFilter to filter DGCClient return value (a Lease).
+ * The list of acceptable classes is very short and explicit.
+ * The depth and array sizes are limited.
+ *
+ * @param filterInfo access to class, arrayLength, etc.
+ * @return {@link ObjectInputFilter.Status#ALLOWED} if allowed,
+ * {@link ObjectInputFilter.Status#REJECTED} if rejected,
+ * otherwise {@link ObjectInputFilter.Status#UNDECIDED}
+ */
+ private static ObjectInputFilter.Status leaseFilter(ObjectInputFilter.FilterInfo filterInfo) {
+
+ if (filterInfo.depth() > DGCCLIENT_MAX_DEPTH) {
+ return ObjectInputFilter.Status.REJECTED;
+ }
+ Class<?> clazz = filterInfo.serialClass();
+ if (clazz != null) {
+ while (clazz.isArray()) {
+ if (filterInfo.arrayLength() >= 0 && filterInfo.arrayLength() > DGCCLIENT_MAX_ARRAY_SIZE) {
+ return ObjectInputFilter.Status.REJECTED;
+ }
+ // Arrays are allowed depending on the component type
+ clazz = clazz.getComponentType();
+ }
+ if (clazz.isPrimitive()) {
+ // Arrays of primitives are allowed
+ return ObjectInputFilter.Status.ALLOWED;
+ }
+ return (clazz == UID.class ||
+ clazz == VMID.class ||
+ clazz == Lease.class)
+ ? ObjectInputFilter.Status.ALLOWED
+ : ObjectInputFilter.Status.REJECTED;
+ }
+ // Not a class, not size limited
+ return ObjectInputFilter.Status.UNDECIDED;
+ }
+
+}
diff --git a/src/java.rmi/share/classes/sun/rmi/transport/StreamRemoteCall.java b/src/java.rmi/share/classes/sun/rmi/transport/StreamRemoteCall.java
index 915ed6f..d0a0ced 100644
--- a/src/java.rmi/share/classes/sun/rmi/transport/StreamRemoteCall.java
+++ b/src/java.rmi/share/classes/sun/rmi/transport/StreamRemoteCall.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2017, 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
@@ -168,6 +168,13 @@
}
/**
+ * Discard any post-processing of refs the InputStream.
+ */
+ public void discardPendingRefs() {
+ in.discardRefs();
+ }
+
+ /**
* Returns an output stream (may put out header information
* relating to the success of the call).
* @param success If true, indicates normal return, else indicates
diff --git a/src/jdk.crypto.ec/share/classes/sun/security/ec/ECDSASignature.java b/src/jdk.crypto.ec/share/classes/sun/security/ec/ECDSASignature.java
index 3b74338..f2ac544 100644
--- a/src/jdk.crypto.ec/share/classes/sun/security/ec/ECDSASignature.java
+++ b/src/jdk.crypto.ec/share/classes/sun/security/ec/ECDSASignature.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2017, 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
@@ -370,9 +370,15 @@
}
random.nextBytes(seed);
+ // random bits needed for timing countermeasures
+ int timingArgument = random.nextInt();
+ // values must be non-zero to enable countermeasures
+ timingArgument |= 1;
+
byte[] sig;
try {
- sig = signDigest(getDigestValue(), s, encodedParams, seed);
+ sig = signDigest(getDigestValue(), s, encodedParams, seed,
+ timingArgument);
} catch (GeneralSecurityException e) {
throw new SignatureException("Could not sign data", e);
}
@@ -509,11 +515,19 @@
* @param s the private key's S value.
* @param encodedParams the curve's DER encoded object identifier.
* @param seed the random seed.
+ * @param timing When non-zero, the implmentation will use timing
+ * countermeasures to hide secrets from timing channels. The EC
+ * implementation will disable the countermeasures when this value is
+ * zero, because the underlying EC functions are shared by several
+ * crypto operations, some of which do not use the countermeasures.
+ * The high-order 31 bits must be uniformly random. The entropy from
+ * these bits is used by the countermeasures.
*
* @return byte[] the signature.
*/
private static native byte[] signDigest(byte[] digest, byte[] s,
- byte[] encodedParams, byte[] seed) throws GeneralSecurityException;
+ byte[] encodedParams, byte[] seed, int timing)
+ throws GeneralSecurityException;
/**
* Verifies the signed digest using the public key.
diff --git a/src/jdk.crypto.ec/share/native/libsunec/ECC_JNI.cpp b/src/jdk.crypto.ec/share/native/libsunec/ECC_JNI.cpp
index 31c2d07..1cec783 100644
--- a/src/jdk.crypto.ec/share/native/libsunec/ECC_JNI.cpp
+++ b/src/jdk.crypto.ec/share/native/libsunec/ECC_JNI.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2017, 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
@@ -196,7 +196,7 @@
*/
JNIEXPORT jbyteArray
JNICALL Java_sun_security_ec_ECDSASignature_signDigest
- (JNIEnv *env, jclass clazz, jbyteArray digest, jbyteArray privateKey, jbyteArray encodedParams, jbyteArray seed)
+ (JNIEnv *env, jclass clazz, jbyteArray digest, jbyteArray privateKey, jbyteArray encodedParams, jbyteArray seed, jint timing)
{
jbyte* pDigestBuffer = NULL;
jint jDigestLength = env->GetArrayLength(digest);
@@ -256,7 +256,7 @@
// Sign the digest (using the supplied seed)
if (ECDSA_SignDigest(&privKey, &signature_item, &digest_item,
- (unsigned char *) pSeedBuffer, jSeedLength, 0) != SECSuccess) {
+ (unsigned char *) pSeedBuffer, jSeedLength, 0, timing) != SECSuccess) {
ThrowException(env, KEY_EXCEPTION);
goto cleanup;
}
diff --git a/src/jdk.crypto.ec/share/native/libsunec/impl/ec.c b/src/jdk.crypto.ec/share/native/libsunec/impl/ec.c
index 4f3cab3..c439eb7 100644
--- a/src/jdk.crypto.ec/share/native/libsunec/impl/ec.c
+++ b/src/jdk.crypto.ec/share/native/libsunec/impl/ec.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
* This library is free software; you can redistribute it and/or
@@ -34,7 +34,7 @@
* Dr Vipul Gupta <vipul.gupta@sun.com> and
* Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
*
- * Last Modified Date from the Original Code: November 2016
+ * Last Modified Date from the Original Code: May 2017
*********************************************************************** */
#include "mplogic.h"
@@ -87,7 +87,7 @@
*/
SECStatus
ec_points_mul(const ECParams *params, const mp_int *k1, const mp_int *k2,
- const SECItem *pointP, SECItem *pointQ, int kmflag)
+ const SECItem *pointP, SECItem *pointQ, int kmflag, int timing)
{
mp_int Px, Py, Qx, Qy;
mp_int Gx, Gy, order, irreducible, a, b;
@@ -199,9 +199,9 @@
goto cleanup;
if ((k2 != NULL) && (pointP != NULL)) {
- CHECK_MPI_OK( ECPoints_mul(group, k1, k2, &Px, &Py, &Qx, &Qy) );
+ CHECK_MPI_OK( ECPoints_mul(group, k1, k2, &Px, &Py, &Qx, &Qy, timing) );
} else {
- CHECK_MPI_OK( ECPoints_mul(group, k1, NULL, NULL, NULL, &Qx, &Qy) );
+ CHECK_MPI_OK( ECPoints_mul(group, k1, NULL, NULL, NULL, &Qx, &Qy, timing) );
}
/* Construct the SECItem representation of point Q */
@@ -333,7 +333,8 @@
CHECK_MPI_OK( mp_read_unsigned_octets(&k, key->privateValue.data,
(mp_size) len) );
- rv = ec_points_mul(ecParams, &k, NULL, NULL, &(key->publicValue), kmflag);
+ /* key generation does not support timing mitigation */
+ rv = ec_points_mul(ecParams, &k, NULL, NULL, &(key->publicValue), kmflag, /*timing*/ 0);
if (rv != SECSuccess) goto cleanup;
*privKey = key;
@@ -610,7 +611,8 @@
}
/* Multiply our private key and peer's public point */
- if ((ec_points_mul(ecParams, NULL, &k, publicValue, &pointQ, kmflag) != SECSuccess) ||
+ /* ECDH doesn't support timing mitigation */
+ if ((ec_points_mul(ecParams, NULL, &k, publicValue, &pointQ, kmflag, /*timing*/ 0) != SECSuccess) ||
ec_point_at_infinity(&pointQ))
goto cleanup;
@@ -645,7 +647,8 @@
*/
SECStatus
ECDSA_SignDigestWithSeed(ECPrivateKey *key, SECItem *signature,
- const SECItem *digest, const unsigned char *kb, const int kblen, int kmflag)
+ const SECItem *digest, const unsigned char *kb, const int kblen, int kmflag,
+ int timing)
{
SECStatus rv = SECFailure;
mp_int x1;
@@ -715,16 +718,6 @@
}
/*
- * Using an equivalent exponent of fixed length (same as n or 1 bit less
- * than n) to keep the kG timing relatively constant.
- *
- * Note that this is an extra step on top of the approach defined in
- * ANSI X9.62 so as to make a fixed length K.
- */
- CHECK_MPI_OK( mp_add(&k, &n, &k) );
- CHECK_MPI_OK( mp_div_2(&k, &k) );
-
- /*
** ANSI X9.62, Section 5.3.2, Step 2
**
** Compute kG
@@ -732,7 +725,7 @@
kGpoint.len = 2*flen + 1;
kGpoint.data = PORT_Alloc(2*flen + 1, kmflag);
if ((kGpoint.data == NULL) ||
- (ec_points_mul(ecParams, &k, NULL, NULL, &kGpoint, kmflag)
+ (ec_points_mul(ecParams, &k, NULL, NULL, &kGpoint, kmflag, timing)
!= SECSuccess))
goto cleanup;
@@ -854,7 +847,7 @@
*/
SECStatus
ECDSA_SignDigest(ECPrivateKey *key, SECItem *signature, const SECItem *digest,
- const unsigned char* random, int randomLen, int kmflag)
+ const unsigned char* random, int randomLen, int kmflag, int timing)
{
SECStatus rv = SECFailure;
int len;
@@ -872,7 +865,7 @@
if (kBytes == NULL) goto cleanup;
/* Generate ECDSA signature with the specified k value */
- rv = ECDSA_SignDigestWithSeed(key, signature, digest, kBytes, len, kmflag);
+ rv = ECDSA_SignDigestWithSeed(key, signature, digest, kBytes, len, kmflag, timing);
cleanup:
if (kBytes) {
@@ -1018,7 +1011,8 @@
** Here, A = u1.G B = u2.Q and C = A + B
** If the result, C, is the point at infinity, reject the signature
*/
- if (ec_points_mul(ecParams, &u1, &u2, &key->publicValue, &pointC, kmflag)
+ /* verification does not support timing mitigation */
+ if (ec_points_mul(ecParams, &u1, &u2, &key->publicValue, &pointC, kmflag, /*timing*/ 0)
!= SECSuccess) {
rv = SECFailure;
goto cleanup;
diff --git a/src/jdk.crypto.ec/share/native/libsunec/impl/ec2.h b/src/jdk.crypto.ec/share/native/libsunec/impl/ec2.h
index aa5f2bb..72df04e 100644
--- a/src/jdk.crypto.ec/share/native/libsunec/impl/ec2.h
+++ b/src/jdk.crypto.ec/share/native/libsunec/impl/ec2.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
* This library is free software; you can redistribute it and/or
@@ -33,6 +33,7 @@
* Contributor(s):
* Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
*
+ * Last Modified Date from the Original Code: May 2017
*********************************************************************** */
#ifndef _EC2_H
@@ -79,7 +80,7 @@
* determines the field GF2m. Uses Montgomery projective coordinates. */
mp_err ec_GF2m_pt_mul_mont(const mp_int *n, const mp_int *px,
const mp_int *py, mp_int *rx, mp_int *ry,
- const ECGroup *group);
+ const ECGroup *group, int timing);
#ifdef ECL_ENABLE_GF2M_PROJ
/* Converts a point P(px, py) from affine coordinates to projective
diff --git a/src/jdk.crypto.ec/share/native/libsunec/impl/ec2_aff.c b/src/jdk.crypto.ec/share/native/libsunec/impl/ec2_aff.c
index 5a546c0..8d0f546 100644
--- a/src/jdk.crypto.ec/share/native/libsunec/impl/ec2_aff.c
+++ b/src/jdk.crypto.ec/share/native/libsunec/impl/ec2_aff.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
* This library is free software; you can redistribute it and/or
@@ -33,6 +33,7 @@
* Contributor(s):
* Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
*
+ * Last Modified Date from the Original Code: May 2017
*********************************************************************** */
#include "ec2.h"
@@ -329,7 +330,8 @@
/* 4: Verify that the order of the curve times the publicValue
* is the point at infinity.
*/
- MP_CHECKOK( ECPoint_mul(group, &group->order, px, py, &pxt, &pyt) );
+ /* timing mitigation is not supported */
+ MP_CHECKOK( ECPoint_mul(group, &group->order, px, py, &pxt, &pyt, /*timing*/ 0) );
if (ec_GF2m_pt_is_inf_aff(&pxt, &pyt) != MP_YES) {
res = MP_NO;
goto CLEANUP;
diff --git a/src/jdk.crypto.ec/share/native/libsunec/impl/ec2_mont.c b/src/jdk.crypto.ec/share/native/libsunec/impl/ec2_mont.c
index b91e65e..bb60553 100644
--- a/src/jdk.crypto.ec/share/native/libsunec/impl/ec2_mont.c
+++ b/src/jdk.crypto.ec/share/native/libsunec/impl/ec2_mont.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
* This library is free software; you can redistribute it and/or
@@ -35,6 +35,7 @@
* Stephen Fung <fungstep@hotmail.com>, and
* Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories.
*
+ * Last Modified Date from the Original Code: May 2017
*********************************************************************** */
#include "ec2.h"
@@ -181,10 +182,12 @@
/* Computes R = nP based on algorithm 2P of Lopex, J. and Dahab, R. "Fast
* multiplication on elliptic curves over GF(2^m) without
* precomputation". Elliptic curve points P and R can be identical. Uses
- * Montgomery projective coordinates. */
+ * Montgomery projective coordinates. The timing parameter is ignored
+ * because this algorithm resists timing attacks by default. */
mp_err
ec_GF2m_pt_mul_mont(const mp_int *n, const mp_int *px, const mp_int *py,
- mp_int *rx, mp_int *ry, const ECGroup *group)
+ mp_int *rx, mp_int *ry, const ECGroup *group,
+ int timing)
{
mp_err res = MP_OKAY;
mp_int x1, x2, z1, z2;
diff --git a/src/jdk.crypto.ec/share/native/libsunec/impl/ecc_impl.h b/src/jdk.crypto.ec/share/native/libsunec/impl/ecc_impl.h
index 0739f4c..48aa13a 100644
--- a/src/jdk.crypto.ec/share/native/libsunec/impl/ecc_impl.h
+++ b/src/jdk.crypto.ec/share/native/libsunec/impl/ecc_impl.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
* This library is free software; you can redistribute it and/or
@@ -34,7 +34,7 @@
* Dr Vipul Gupta <vipul.gupta@sun.com> and
* Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
*
- * Last Modified Date from the Original Code: November 2013
+ * Last Modified Date from the Original Code: May 2017
*********************************************************************** */
#ifndef _ECC_IMPL_H
@@ -258,7 +258,7 @@
const unsigned char* random, int randomlen, int);
/* This function has been modified to accept an array of random bytes */
extern SECStatus ECDSA_SignDigest(ECPrivateKey *, SECItem *, const SECItem *,
- const unsigned char* random, int randomlen, int);
+ const unsigned char* random, int randomlen, int, int timing);
extern SECStatus ECDSA_VerifyDigest(ECPublicKey *, const SECItem *,
const SECItem *, int);
extern SECStatus ECDH_Derive(SECItem *, ECParams *, SECItem *, boolean_t,
diff --git a/src/jdk.crypto.ec/share/native/libsunec/impl/ecl-priv.h b/src/jdk.crypto.ec/share/native/libsunec/impl/ecl-priv.h
index fa232dd..bdfe615 100644
--- a/src/jdk.crypto.ec/share/native/libsunec/impl/ecl-priv.h
+++ b/src/jdk.crypto.ec/share/native/libsunec/impl/ecl-priv.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
* This library is free software; you can redistribute it and/or
@@ -34,6 +34,7 @@
* Stephen Fung <fungstep@hotmail.com> and
* Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
*
+ * Last Modified Date from the Original Code: May 2017
*********************************************************************** */
#ifndef _ECL_PRIV_H
@@ -193,12 +194,13 @@
mp_int *ry, const ECGroup *group);
mp_err (*point_mul) (const mp_int *n, const mp_int *px,
const mp_int *py, mp_int *rx, mp_int *ry,
- const ECGroup *group);
+ const ECGroup *group, int timing);
mp_err (*base_point_mul) (const mp_int *n, mp_int *rx, mp_int *ry,
const ECGroup *group);
mp_err (*points_mul) (const mp_int *k1, const mp_int *k2,
const mp_int *px, const mp_int *py, mp_int *rx,
- mp_int *ry, const ECGroup *group);
+ mp_int *ry, const ECGroup *group,
+ int timing);
mp_err (*validate_point) (const mp_int *px, const mp_int *py, const ECGroup *group);
/* Extra storage for implementation-specific data. Any memory
* allocated to these extra fields will be cleared by extra_free. */
@@ -262,10 +264,12 @@
/* point multiplication */
mp_err ec_pts_mul_basic(const mp_int *k1, const mp_int *k2,
const mp_int *px, const mp_int *py, mp_int *rx,
- mp_int *ry, const ECGroup *group);
+ mp_int *ry, const ECGroup *group,
+ int timing);
mp_err ec_pts_mul_simul_w2(const mp_int *k1, const mp_int *k2,
const mp_int *px, const mp_int *py, mp_int *rx,
- mp_int *ry, const ECGroup *group);
+ mp_int *ry, const ECGroup *group,
+ int timing);
/* Computes the windowed non-adjacent-form (NAF) of a scalar. Out should
* be an array of signed char's to output to, bitsize should be the number
diff --git a/src/jdk.crypto.ec/share/native/libsunec/impl/ecl.h b/src/jdk.crypto.ec/share/native/libsunec/impl/ecl.h
index 3a83a9e..deff0aa 100644
--- a/src/jdk.crypto.ec/share/native/libsunec/impl/ecl.h
+++ b/src/jdk.crypto.ec/share/native/libsunec/impl/ecl.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
* This library is free software; you can redistribute it and/or
@@ -33,6 +33,7 @@
* Contributor(s):
* Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
*
+ * Last Modified Date from the Original Code: May 2017
*********************************************************************** */
#ifndef _ECL_H
@@ -70,7 +71,8 @@
* of the group of points on the elliptic curve. Input and output values
* are assumed to be NOT field-encoded. */
mp_err ECPoint_mul(const ECGroup *group, const mp_int *k, const mp_int *px,
- const mp_int *py, mp_int *qx, mp_int *qy);
+ const mp_int *py, mp_int *qx, mp_int *qy,
+ int timing);
/* Elliptic curve scalar-point multiplication. Computes Q(x, y) = k1 * G +
* k2 * P(x, y), where G is the generator (base point) of the group of
@@ -78,7 +80,7 @@
* be NOT field-encoded. */
mp_err ECPoints_mul(const ECGroup *group, const mp_int *k1,
const mp_int *k2, const mp_int *px, const mp_int *py,
- mp_int *qx, mp_int *qy);
+ mp_int *qx, mp_int *qy, int timing);
/* Validates an EC public key as described in Section 5.2.2 of X9.62.
* Returns MP_YES if the public key is valid, MP_NO if the public key
diff --git a/src/jdk.crypto.ec/share/native/libsunec/impl/ecl_mult.c b/src/jdk.crypto.ec/share/native/libsunec/impl/ecl_mult.c
index 92dd0ec..16f2592 100644
--- a/src/jdk.crypto.ec/share/native/libsunec/impl/ecl_mult.c
+++ b/src/jdk.crypto.ec/share/native/libsunec/impl/ecl_mult.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
* This library is free software; you can redistribute it and/or
@@ -33,7 +33,7 @@
* Contributor(s):
* Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
*
- * Last Modified Date from the Original Code: Nov 2016
+ * Last Modified Date from the Original Code: May 2017
*********************************************************************** */
#include "mpi.h"
@@ -50,7 +50,8 @@
* are assumed to be NOT field-encoded. */
mp_err
ECPoint_mul(const ECGroup *group, const mp_int *k, const mp_int *px,
- const mp_int *py, mp_int *rx, mp_int *ry)
+ const mp_int *py, mp_int *rx, mp_int *ry,
+ int timing)
{
mp_err res = MP_OKAY;
mp_int kt;
@@ -76,16 +77,16 @@
kt.flag = (mp_sign)0;
MP_CHECKOK(group->
point_mul(&kt, &group->genx, &group->geny, rx, ry,
- group));
+ group, timing));
}
} else {
if (group->meth->field_enc) {
MP_CHECKOK(group->meth->field_enc(px, rx, group->meth));
MP_CHECKOK(group->meth->field_enc(py, ry, group->meth));
- MP_CHECKOK(group->point_mul(&kt, rx, ry, rx, ry, group));
+ MP_CHECKOK(group->point_mul(&kt, rx, ry, rx, ry, group, timing));
} else {
kt.flag = (mp_sign)0;
- MP_CHECKOK(group->point_mul(&kt, px, py, rx, ry, group));
+ MP_CHECKOK(group->point_mul(&kt, px, py, rx, ry, group, timing));
}
}
if (group->meth->field_dec) {
@@ -107,7 +108,7 @@
mp_err
ec_pts_mul_basic(const mp_int *k1, const mp_int *k2, const mp_int *px,
const mp_int *py, mp_int *rx, mp_int *ry,
- const ECGroup *group)
+ const ECGroup *group, int timing)
{
mp_err res = MP_OKAY;
mp_int sx, sy;
@@ -119,9 +120,9 @@
/* if some arguments are not defined used ECPoint_mul */
if (k1 == NULL) {
- return ECPoint_mul(group, k2, px, py, rx, ry);
+ return ECPoint_mul(group, k2, px, py, rx, ry, timing);
} else if ((k2 == NULL) || (px == NULL) || (py == NULL)) {
- return ECPoint_mul(group, k1, NULL, NULL, rx, ry);
+ return ECPoint_mul(group, k1, NULL, NULL, rx, ry, timing);
}
MP_DIGITS(&sx) = 0;
@@ -129,8 +130,8 @@
MP_CHECKOK(mp_init(&sx, FLAG(k1)));
MP_CHECKOK(mp_init(&sy, FLAG(k1)));
- MP_CHECKOK(ECPoint_mul(group, k1, NULL, NULL, &sx, &sy));
- MP_CHECKOK(ECPoint_mul(group, k2, px, py, rx, ry));
+ MP_CHECKOK(ECPoint_mul(group, k1, NULL, NULL, &sx, &sy, timing));
+ MP_CHECKOK(ECPoint_mul(group, k2, px, py, rx, ry, timing));
if (group->meth->field_enc) {
MP_CHECKOK(group->meth->field_enc(&sx, &sx, group->meth));
@@ -162,7 +163,7 @@
mp_err
ec_pts_mul_simul_w2(const mp_int *k1, const mp_int *k2, const mp_int *px,
const mp_int *py, mp_int *rx, mp_int *ry,
- const ECGroup *group)
+ const ECGroup *group, int timing)
{
mp_err res = MP_OKAY;
mp_int precomp[4][4][2];
@@ -177,9 +178,9 @@
/* if some arguments are not defined used ECPoint_mul */
if (k1 == NULL) {
- return ECPoint_mul(group, k2, px, py, rx, ry);
+ return ECPoint_mul(group, k2, px, py, rx, ry, timing);
} else if ((k2 == NULL) || (px == NULL) || (py == NULL)) {
- return ECPoint_mul(group, k1, NULL, NULL, rx, ry);
+ return ECPoint_mul(group, k1, NULL, NULL, rx, ry, timing);
}
/* initialize precomputation table */
@@ -311,7 +312,8 @@
* Input and output values are assumed to be NOT field-encoded. */
mp_err
ECPoints_mul(const ECGroup *group, const mp_int *k1, const mp_int *k2,
- const mp_int *px, const mp_int *py, mp_int *rx, mp_int *ry)
+ const mp_int *px, const mp_int *py, mp_int *rx, mp_int *ry,
+ int timing)
{
mp_err res = MP_OKAY;
mp_int k1t, k2t;
@@ -348,9 +350,9 @@
/* if points_mul is defined, then use it */
if (group->points_mul) {
- res = group->points_mul(k1p, k2p, px, py, rx, ry, group);
+ res = group->points_mul(k1p, k2p, px, py, rx, ry, group, timing);
} else {
- res = ec_pts_mul_simul_w2(k1p, k2p, px, py, rx, ry, group);
+ res = ec_pts_mul_simul_w2(k1p, k2p, px, py, rx, ry, group, timing);
}
CLEANUP:
diff --git a/src/jdk.crypto.ec/share/native/libsunec/impl/ecp.h b/src/jdk.crypto.ec/share/native/libsunec/impl/ecp.h
index c2aad8e..b367b90 100644
--- a/src/jdk.crypto.ec/share/native/libsunec/impl/ecp.h
+++ b/src/jdk.crypto.ec/share/native/libsunec/impl/ecp.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
* This library is free software; you can redistribute it and/or
@@ -33,6 +33,7 @@
* Contributor(s):
* Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
*
+ * Last Modified Date from the Original Code: May 2017
*********************************************************************** */
#ifndef _ECP_H
@@ -122,7 +123,7 @@
mp_err
ec_GFp_pts_mul_jac(const mp_int *k1, const mp_int *k2, const mp_int *px,
const mp_int *py, mp_int *rx, mp_int *ry,
- const ECGroup *group);
+ const ECGroup *group, int timing);
/* Computes R = nP where R is (rx, ry) and P is the base point. Elliptic
* curve points P and R can be identical. Uses mixed Modified-Jacobian
@@ -131,9 +132,13 @@
* returns output that is still field-encoded. Uses 5-bit window NAF
* method (algorithm 11) for scalar-point multiplication from Brown,
* Hankerson, Lopez, Menezes. Software Implementation of the NIST Elliptic
- * Curves Over Prime Fields. */
+ * Curves Over Prime Fields. The implementation includes a countermeasure
+ * that attempts to hide the size of n from timing channels. This counter-
+ * measure is enabled using the timing argument. The high-rder bits of timing
+ * must be uniformly random in order for this countermeasure to work. */
mp_err
ec_GFp_pt_mul_jm_wNAF(const mp_int *n, const mp_int *px, const mp_int *py,
- mp_int *rx, mp_int *ry, const ECGroup *group);
+ mp_int *rx, mp_int *ry, const ECGroup *group,
+ int timing);
#endif /* _ECP_H */
diff --git a/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_aff.c b/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_aff.c
index f150ca1..c9d9232 100644
--- a/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_aff.c
+++ b/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_aff.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
* This library is free software; you can redistribute it and/or
@@ -38,6 +38,7 @@
* Nils Larsch <nla@trustcenter.de>, and
* Lenka Fibikova <fibikova@exp-math.uni-essen.de>, the OpenSSL Project
*
+ * Last Modified Date from the Original Code: May 2017
*********************************************************************** */
#include "ecp.h"
@@ -340,7 +341,8 @@
/* 4: Verify that the order of the curve times the publicValue
* is the point at infinity.
*/
- MP_CHECKOK( ECPoint_mul(group, &group->order, px, py, &pxt, &pyt) );
+ /* timing mitigation is not supported */
+ MP_CHECKOK( ECPoint_mul(group, &group->order, px, py, &pxt, &pyt, /*timing*/ 0) );
if (ec_GFp_pt_is_inf_aff(&pxt, &pyt) != MP_YES) {
res = MP_NO;
goto CLEANUP;
diff --git a/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_jac.c b/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_jac.c
index 12410be..9e1bdf2 100644
--- a/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_jac.c
+++ b/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_jac.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
* This library is free software; you can redistribute it and/or
@@ -38,6 +38,7 @@
* Nils Larsch <nla@trustcenter.de>, and
* Lenka Fibikova <fibikova@exp-math.uni-essen.de>, the OpenSSL Project
*
+ * Last Modified Date from the Original Code: May 2017
*********************************************************************** */
#include "ecp.h"
@@ -180,6 +181,15 @@
MP_CHECKOK(group->meth->field_mul(&A, qx, &A, group->meth));
MP_CHECKOK(group->meth->field_mul(&B, qy, &B, group->meth));
+ /*
+ * Additional checks for point equality and point at infinity
+ */
+ if (mp_cmp(px, &A) == 0 && mp_cmp(py, &B) == 0) {
+ /* POINT_DOUBLE(P) */
+ MP_CHECKOK(ec_GFp_pt_dbl_jac(px, py, pz, rx, ry, rz, group));
+ goto CLEANUP;
+ }
+
/* C = A - px, D = B - py */
MP_CHECKOK(group->meth->field_sub(&A, px, &C, group->meth));
MP_CHECKOK(group->meth->field_sub(&B, py, &D, group->meth));
@@ -406,7 +416,7 @@
mp_err
ec_GFp_pts_mul_jac(const mp_int *k1, const mp_int *k2, const mp_int *px,
const mp_int *py, mp_int *rx, mp_int *ry,
- const ECGroup *group)
+ const ECGroup *group, int timing)
{
mp_err res = MP_OKAY;
mp_int precomp[4][4][2];
@@ -430,9 +440,9 @@
/* if some arguments are not defined used ECPoint_mul */
if (k1 == NULL) {
- return ECPoint_mul(group, k2, px, py, rx, ry);
+ return ECPoint_mul(group, k2, px, py, rx, ry, timing);
} else if ((k2 == NULL) || (px == NULL) || (py == NULL)) {
- return ECPoint_mul(group, k1, NULL, NULL, rx, ry);
+ return ECPoint_mul(group, k1, NULL, NULL, rx, ry, timing);
}
/* initialize precomputation table */
diff --git a/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_jm.c b/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_jm.c
index cdee87a..c5cdef9 100644
--- a/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_jm.c
+++ b/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_jm.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
* This library is free software; you can redistribute it and/or
@@ -33,6 +33,7 @@
* Contributor(s):
* Stephen Fung <fungstep@hotmail.com>, Sun Microsystems Laboratories
*
+ * Last Modified Date from the Original Code: May 2017
*********************************************************************** */
#include "ecp.h"
@@ -165,6 +166,16 @@
MP_CHECKOK(group->meth->field_mul(A, qx, A, group->meth));
MP_CHECKOK(group->meth->field_mul(B, qy, B, group->meth));
+ /*
+ * Additional checks for point equality and point at infinity
+ */
+ if (mp_cmp(px, A) == 0 && mp_cmp(py, B) == 0) {
+ /* POINT_DOUBLE(P) */
+ MP_CHECKOK(ec_GFp_pt_dbl_jm(px, py, pz, paz4, rx, ry, rz, raz4,
+ scratch, group));
+ goto CLEANUP;
+ }
+
/* C = A - px, D = B - py */
MP_CHECKOK(group->meth->field_sub(A, px, C, group->meth));
MP_CHECKOK(group->meth->field_sub(B, py, D, group->meth));
@@ -213,19 +224,23 @@
* Curves Over Prime Fields. */
mp_err
ec_GFp_pt_mul_jm_wNAF(const mp_int *n, const mp_int *px, const mp_int *py,
- mp_int *rx, mp_int *ry, const ECGroup *group)
+ mp_int *rx, mp_int *ry, const ECGroup *group,
+ int timing)
{
mp_err res = MP_OKAY;
- mp_int precomp[16][2], rz, tpx, tpy;
- mp_int raz4;
+ mp_int precomp[16][2], rz, tpx, tpy, tpz;
+ mp_int raz4, tpaz4;
mp_int scratch[MAX_SCRATCH];
signed char *naf = NULL;
int i, orderBitSize;
+ int numDoubles, numAdds, extraDoubles, extraAdds;
MP_DIGITS(&rz) = 0;
MP_DIGITS(&raz4) = 0;
MP_DIGITS(&tpx) = 0;
MP_DIGITS(&tpy) = 0;
+ MP_DIGITS(&tpz) = 0;
+ MP_DIGITS(&tpaz4) = 0;
for (i = 0; i < 16; i++) {
MP_DIGITS(&precomp[i][0]) = 0;
MP_DIGITS(&precomp[i][1]) = 0;
@@ -239,7 +254,9 @@
/* initialize precomputation table */
MP_CHECKOK(mp_init(&tpx, FLAG(n)));
- MP_CHECKOK(mp_init(&tpy, FLAG(n)));;
+ MP_CHECKOK(mp_init(&tpy, FLAG(n)));
+ MP_CHECKOK(mp_init(&tpz, FLAG(n)));
+ MP_CHECKOK(mp_init(&tpaz4, FLAG(n)));
MP_CHECKOK(mp_init(&rz, FLAG(n)));
MP_CHECKOK(mp_init(&raz4, FLAG(n)));
@@ -295,19 +312,64 @@
/* Compute 5NAF */
ec_compute_wNAF(naf, orderBitSize, n, 5);
+ numAdds = 0;
+ numDoubles = orderBitSize;
/* wNAF method */
for (i = orderBitSize; i >= 0; i--) {
+
+ if (ec_GFp_pt_is_inf_jac(rx, ry, &rz) == MP_YES) {
+ numDoubles--;
+ }
+
/* R = 2R */
ec_GFp_pt_dbl_jm(rx, ry, &rz, &raz4, rx, ry, &rz,
&raz4, scratch, group);
+
if (naf[i] != 0) {
ec_GFp_pt_add_jm_aff(rx, ry, &rz, &raz4,
&precomp[(naf[i] + 15) / 2][0],
&precomp[(naf[i] + 15) / 2][1], rx, ry,
&rz, &raz4, scratch, group);
+ numAdds++;
}
}
+ /* extra operations to make timing less dependent on secrets */
+ if (timing) {
+ /* low-order bit of timing argument contains no entropy */
+ timing >>= 1;
+
+ MP_CHECKOK(ec_GFp_pt_set_inf_jac(&tpx, &tpy, &tpz));
+ mp_zero(&tpaz4);
+
+ /* Set the temp value to a non-infinite point */
+ ec_GFp_pt_add_jm_aff(&tpx, &tpy, &tpz, &tpaz4,
+ &precomp[8][0],
+ &precomp[8][1], &tpx, &tpy,
+ &tpz, &tpaz4, scratch, group);
+
+ /* two bits of extra adds */
+ extraAdds = timing & 0x3;
+ timing >>= 2;
+ /* Window size is 5, so the maximum number of additions is ceil(orderBitSize/5) */
+ /* This is the same as (orderBitSize + 4) / 5 */
+ for(i = numAdds; i <= (orderBitSize + 4) / 5 + extraAdds; i++) {
+ ec_GFp_pt_add_jm_aff(&tpx, &tpy, &tpz, &tpaz4,
+ &precomp[9 + (i % 3)][0],
+ &precomp[9 + (i % 3)][1], &tpx, &tpy,
+ &tpz, &tpaz4, scratch, group);
+ }
+
+ /* two bits of extra doubles */
+ extraDoubles = timing & 0x3;
+ timing >>= 2;
+ for(i = numDoubles; i <= orderBitSize + extraDoubles; i++) {
+ ec_GFp_pt_dbl_jm(&tpx, &tpy, &tpz, &tpaz4, &tpx, &tpy, &tpz,
+ &tpaz4, scratch, group);
+ }
+
+ }
+
/* convert result S to affine coordinates */
MP_CHECKOK(ec_GFp_pt_jac2aff(rx, ry, &rz, rx, ry, group));
@@ -321,6 +383,8 @@
}
mp_clear(&tpx);
mp_clear(&tpy);
+ mp_clear(&tpz);
+ mp_clear(&tpaz4);
mp_clear(&rz);
mp_clear(&raz4);
#ifdef _KERNEL
diff --git a/src/jdk.management.agent/share/classes/sun/management/jmxremote/SingleEntryRegistry.java b/src/jdk.management.agent/share/classes/sun/management/jmxremote/SingleEntryRegistry.java
index 998b00a..c29df19 100644
--- a/src/jdk.management.agent/share/classes/sun/management/jmxremote/SingleEntryRegistry.java
+++ b/src/jdk.management.agent/share/classes/sun/management/jmxremote/SingleEntryRegistry.java
@@ -32,6 +32,7 @@
package sun.management.jmxremote;
+import java.io.ObjectInputFilter;
import java.rmi.AccessException;
import java.rmi.NotBoundException;
import java.rmi.Remote;
@@ -56,7 +57,7 @@
String name,
Remote object)
throws RemoteException {
- super(port, csf, ssf);
+ super(port, csf, ssf, SingleEntryRegistry::singleRegistryFilter);
this.name = name;
this.object = object;
}
@@ -84,6 +85,23 @@
throw new AccessException("Cannot modify this registry");
}
+ /**
+ * ObjectInputFilter to check parameters to SingleEntryRegistry.
+ * Since it is a read-only Registry, no classes are accepted.
+ * String arguments are accepted without passing them to the serialFilter.
+ *
+ * @param info a reference to the serialization filter information
+ * @return Status.REJECTED if parameters are out of range
+ */
+ private static ObjectInputFilter.Status singleRegistryFilter(ObjectInputFilter.FilterInfo info) {
+ return (info.serialClass() != null ||
+ info.depth() > 2 ||
+ info.references() > 4 ||
+ info.arrayLength() >= 0)
+ ? ObjectInputFilter.Status.REJECTED
+ : ObjectInputFilter.Status.ALLOWED;
+ }
+
private final String name;
private final Remote object;
diff --git a/src/jdk.management/share/classes/com/sun/management/HotSpotDiagnosticMXBean.java b/src/jdk.management/share/classes/com/sun/management/HotSpotDiagnosticMXBean.java
index 40d79a2..c79d511 100644
--- a/src/jdk.management/share/classes/com/sun/management/HotSpotDiagnosticMXBean.java
+++ b/src/jdk.management/share/classes/com/sun/management/HotSpotDiagnosticMXBean.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2017, 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
@@ -61,9 +61,10 @@
* @param outputFile the system-dependent filename
* @param live if {@code true} dump only <i>live</i> objects
* i.e. objects that are reachable from others
- * @throws IOException if the {@code outputFile}
+ * @throws IOException if the {@code outputFile} already exists,
* cannot be created, opened, or written to.
* @throws UnsupportedOperationException if this operation is not supported.
+ * @throws IllegalArgumentException if {@code outputFile} does not end with ".hprof" suffix.
* @throws NullPointerException if {@code outputFile} is {@code null}.
* @throws SecurityException
* If a security manager exists and its {@link
diff --git a/src/jdk.management/share/classes/com/sun/management/internal/HotSpotDiagnostic.java b/src/jdk.management/share/classes/com/sun/management/internal/HotSpotDiagnostic.java
index 5b9d8ef..4edf6ad 100644
--- a/src/jdk.management/share/classes/com/sun/management/internal/HotSpotDiagnostic.java
+++ b/src/jdk.management/share/classes/com/sun/management/internal/HotSpotDiagnostic.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2017, 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
@@ -22,7 +22,6 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
-
package com.sun.management.internal;
import java.io.IOException;
@@ -32,6 +31,8 @@
import com.sun.management.HotSpotDiagnosticMXBean;
import com.sun.management.VMOption;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
import sun.management.Util;
/**
@@ -43,6 +44,14 @@
@Override
public void dumpHeap(String outputFile, boolean live) throws IOException {
+
+ String propertyName = "jdk.management.heapdump.allowAnyFileSuffix";
+ PrivilegedAction<Boolean> pa = () -> Boolean.parseBoolean(System.getProperty(propertyName, "false"));
+ boolean allowAnyFileSuffix = AccessController.doPrivileged(pa);
+ if (!allowAnyFileSuffix && !outputFile.endsWith(".hprof")) {
+ throw new IllegalArgumentException("heapdump file must have .hprof extention");
+ }
+
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkWrite(outputFile);
diff --git a/test/java/rmi/activation/nonLocalActivation/NonLocalActivationTest.java b/test/java/rmi/activation/nonLocalActivation/NonLocalActivationTest.java
new file mode 100644
index 0000000..55cea96
--- /dev/null
+++ b/test/java/rmi/activation/nonLocalActivation/NonLocalActivationTest.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2017, 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.net.InetAddress;
+import java.rmi.AccessException;
+import java.rmi.activation.ActivationSystem;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+import java.util.Set;
+
+/*
+ * @test
+ * @bug 8174770
+ * @summary Verify that ActivationSystem rejects non-local access.
+ * The test is manual because the (non-local) host running rmid must be supplied as a property.
+ * @run main/manual/othervm -Dactivation.host=rmid-host NonLocalActivationTest
+ */
+
+/**
+ * Lookup the ActivationSystem on a different host and invoke its remote interface methods.
+ * They should all throw an exception, non-local access is prohibited.
+ *
+ * This test is a manual test and uses rmid running on a *different* host.
+ * The default port (1098) for the Activation System is ok and expected.
+ * Login or ssh to the different host and invoke {@code $JDK_HOME/bin/rmid}.
+ * It will not show any output.
+ *
+ * On the first host modify the @run command above to replace "rmid-host"
+ * with the hostname or IP address of the different host and run the test with jtreg.
+ */
+public class NonLocalActivationTest
+{
+ public static void main(String[] args) throws Exception {
+
+ String host = System.getProperty("activation.host");
+ if (host == null || host.isEmpty()) {
+ throw new RuntimeException("Specify host with system property: -Dactivation.host=<host>");
+ }
+
+ // Check if running the test on a local system; it only applies to remote
+ String myHostName = InetAddress.getLocalHost().getHostName();
+ Set<InetAddress> myAddrs = Set.of(InetAddress.getAllByName(myHostName));
+ Set<InetAddress> hostAddrs = Set.of(InetAddress.getAllByName(host));
+ if (hostAddrs.stream().anyMatch(i -> myAddrs.contains(i))
+ || hostAddrs.stream().anyMatch(h -> h.isLoopbackAddress())) {
+ throw new RuntimeException("Error: property 'activation.host' must not be the local host%n");
+ }
+
+ // Locate the registry operated by the ActivationSystem
+ // Test SystemRegistryImpl
+ Registry registry = LocateRegistry.getRegistry(host, ActivationSystem.SYSTEM_PORT);
+ try {
+ // Verify it is an ActivationSystem registry
+ registry.lookup("java.rmi.activation.ActivationSystem");
+ } catch (Exception nf) {
+ throw new RuntimeException("Not a ActivationSystem registry, does not contain java.rmi.activation.ActivationSystem", nf);
+ }
+
+ try {
+ registry.bind("foo", null);
+ throw new RuntimeException("Remote access should not succeed for method: bind");
+ } catch (Exception e) {
+ assertIsAccessException(e, "Registry.bind");
+ }
+
+ try {
+ registry.rebind("foo", null);
+ throw new RuntimeException("Remote access should not succeed for method: rebind");
+ } catch (Exception e) {
+ assertIsAccessException(e, "Registry.rebind");
+ }
+
+ try {
+ registry.unbind("foo");
+ throw new RuntimeException("Remote access should not succeed for method: unbind");
+ } catch (Exception e) {
+ assertIsAccessException(e, "Registry.unbind");
+ }
+
+
+ // Locate the ActivationSystem on the specified host and default port.
+ // Test each of the ActivationSystem methods
+ ActivationSystem as = (ActivationSystem) registry.lookup("java.rmi.activation.ActivationSystem");
+
+ // Argument is not material, access check is before arg processing
+
+ try {
+ as.registerGroup(null);
+ } catch (Exception aex) {
+ assertIsAccessException(aex, "ActivationSystem.nonLocalAccess");
+ }
+
+ try {
+ as.getActivationDesc(null);
+ } catch (Exception aex) {
+ assertIsAccessException(aex, "ActivationSystem.nonLocalAccess");
+ }
+
+ try {
+ as.getActivationGroupDesc(null);
+ } catch (Exception aex) {
+ assertIsAccessException(aex, "ActivationSystem.nonLocalAccess");
+ }
+
+ try {
+ as.registerObject(null);
+ } catch (Exception aex) {
+ assertIsAccessException(aex, "ActivationSystem.nonLocalAccess");
+ }
+
+ try {
+ as.unregisterGroup(null);
+ } catch (Exception aex) {
+ assertIsAccessException(aex, "ActivationSystem.nonLocalAccess");
+ }
+
+ try {
+ as.unregisterObject(null);
+ } catch (Exception aex) {
+ assertIsAccessException(aex, "ActivationSystem.nonLocalAccess");
+ }
+
+ try {
+ as.setActivationDesc(null, null);
+ } catch (Exception aex) {
+ assertIsAccessException(aex, "ActivationSystem.nonLocalAccess");
+ }
+
+ try {
+ as.setActivationGroupDesc(null, null);
+ } catch (Exception aex) {
+ assertIsAccessException(aex, "ActivationSystem.nonLocalAccess");
+ }
+ }
+
+ /**
+ * Check the exception chain for the expected AccessException and message.
+ * @param ex the exception from the remote invocation.
+ */
+ private static void assertIsAccessException(Exception ex, String msg1) {
+ Throwable t = ex;
+ System.out.println();
+ while (!(t instanceof AccessException) && t.getCause() != null) {
+ t = t.getCause();
+ }
+ if (t instanceof AccessException) {
+ String msg = t.getMessage();
+ int asIndex = msg.indexOf(msg1);
+ int disallowIndex = msg.indexOf("disallowed");
+ int nonLocalHostIndex = msg.indexOf("non-local host");
+ if (asIndex < 0 ||
+ disallowIndex < 0 ||
+ nonLocalHostIndex < 0 ) {
+ throw new RuntimeException("exception message is malformed", t);
+ }
+ System.out.printf("Found expected AccessException: %s%n", t);
+ } else {
+ throw new RuntimeException("AccessException did not occur", ex);
+ }
+ }
+}
diff --git a/test/java/rmi/registry/nonLocalRegistry/NonLocalRegistryTest.java b/test/java/rmi/registry/nonLocalRegistry/NonLocalRegistryTest.java
new file mode 100644
index 0000000..7dd1476
--- /dev/null
+++ b/test/java/rmi/registry/nonLocalRegistry/NonLocalRegistryTest.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2017, 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.net.InetAddress;
+import java.rmi.AccessException;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+import java.util.Set;
+
+/* @test
+ * @bug 8174770
+ * @summary Verify that Registry rejects non-local access for bind, unbind, rebind.
+ * The test is manual because the (non-local) host running rmiregistry must be supplied as a property.
+ * @run main/othervm/manual -Dregistry.host=rmi-registry-host NonLocalRegistryTest
+ */
+
+/**
+ * Verify that access checks for Registry.bind(), .rebind(), and .unbind()
+ * are prevented on remote access to the registry.
+ *
+ * This test is a manual test and uses a standard rmiregistry running
+ * on a *different* host.
+ * The test verifies that the access check is performed *before* the object to be
+ * bound or rebound is deserialized.
+ *
+ * Login or ssh to the different host and invoke {@code $JDK_HOME/bin/rmiregistry}.
+ * It will not show any output.
+ *
+ * On the first host modify the @run command above to replace "rmi-registry-host"
+ * with the hostname or IP address of the different host and run the test with jtreg.
+ */
+public class NonLocalRegistryTest {
+
+ public static void main(String[] args) throws Exception {
+
+ String host = System.getProperty("registry.host");
+ if (host == null || host.isEmpty()) {
+ throw new RuntimeException("Specify host with system property: -Dregistry.host=<host>");
+ }
+
+ // Check if running the test on a local system; it only applies to remote
+ String myHostName = InetAddress.getLocalHost().getHostName();
+ Set<InetAddress> myAddrs = Set.of(InetAddress.getAllByName(myHostName));
+ Set<InetAddress> hostAddrs = Set.of(InetAddress.getAllByName(host));
+ if (hostAddrs.stream().anyMatch(i -> myAddrs.contains(i))
+ || hostAddrs.stream().anyMatch(h -> h.isLoopbackAddress())) {
+ throw new RuntimeException("Error: property 'registry.host' must not be the local host%n");
+ }
+
+ Registry registry = LocateRegistry.getRegistry(host, Registry.REGISTRY_PORT);
+
+ try {
+ registry.bind("foo", null);
+ throw new RuntimeException("Remote access should not succeed for method: bind");
+ } catch (Exception e) {
+ assertIsAccessException(e);
+ }
+
+ try {
+ registry.rebind("foo", null);
+ throw new RuntimeException("Remote access should not succeed for method: rebind");
+ } catch (Exception e) {
+ assertIsAccessException(e);
+ }
+
+ try {
+ registry.unbind("foo");
+ throw new RuntimeException("Remote access should not succeed for method: unbind");
+ } catch (Exception e) {
+ assertIsAccessException(e);
+ }
+ }
+
+ /**
+ * Check the exception chain for the expected AccessException and message.
+ * @param ex the exception from the remote invocation.
+ */
+ private static void assertIsAccessException(Throwable ex) {
+ Throwable t = ex;
+ while (!(t instanceof AccessException) && t.getCause() != null) {
+ t = t.getCause();
+ }
+ if (t instanceof AccessException) {
+ String msg = t.getMessage();
+ int asIndex = msg.indexOf("Registry");
+ int rrIndex = msg.indexOf("Registry.Registry"); // Obsolete error text
+ int disallowIndex = msg.indexOf("disallowed");
+ int nonLocalHostIndex = msg.indexOf("non-local host");
+ if (asIndex < 0 ||
+ rrIndex != -1 ||
+ disallowIndex < 0 ||
+ nonLocalHostIndex < 0 ) {
+ throw new RuntimeException("exception message is malformed", t);
+ }
+ System.out.printf("Found expected AccessException: %s%n%n", t);
+ } else {
+ throw new RuntimeException("AccessException did not occur when expected", ex);
+ }
+ }
+}
diff --git a/test/java/rmi/testlibrary/TestSocketFactory.java b/test/java/rmi/testlibrary/TestSocketFactory.java
new file mode 100644
index 0000000..b320ef0
--- /dev/null
+++ b/test/java/rmi/testlibrary/TestSocketFactory.java
@@ -0,0 +1,602 @@
+/*
+ * Copyright (c) 2017, 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.ByteArrayOutputStream;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Serializable;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.net.SocketOption;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.rmi.server.RMIClientSocketFactory;
+import java.rmi.server.RMIServerSocketFactory;
+import java.rmi.server.RMISocketFactory;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+import org.testng.Assert;
+import org.testng.TestNG;
+import org.testng.annotations.Test;
+import org.testng.annotations.DataProvider;
+
+
+/**
+ * A RMISocketFactory utility factory to log RMI stream contents and to
+ * match and replace output stream contents to simulate failures.
+ */
+public class TestSocketFactory extends RMISocketFactory
+ implements RMIClientSocketFactory, RMIServerSocketFactory, Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private volatile transient byte[] matchBytes;
+
+ private volatile transient byte[] replaceBytes;
+
+ private transient final List<InterposeSocket> sockets = new ArrayList<>();
+
+ private transient final List<InterposeServerSocket> serverSockets = new ArrayList<>();
+
+ public static final boolean DEBUG = false;
+
+ /**
+ * Debugging output can be synchronized with logging of RMI actions.
+ *
+ * @param format a printf format
+ * @param args any args
+ */
+ private static void DEBUG(String format, Object... args) {
+ if (DEBUG) {
+ System.err.printf(format, args);
+ }
+ }
+
+ /**
+ * Create a socket factory that creates InputStreams that log
+ * and OutputStreams that log .
+ */
+ public TestSocketFactory() {
+ this.matchBytes = new byte[0];
+ this.replaceBytes = this.matchBytes;
+ System.out.printf("Creating TestSocketFactory()%n");
+ }
+
+ public void setMatchReplaceBytes(byte[] matchBytes, byte[] replaceBytes) {
+ this.matchBytes = Objects.requireNonNull(matchBytes, "matchBytes");
+ this.replaceBytes = Objects.requireNonNull(replaceBytes, "replaceBytes");
+ sockets.forEach( s -> s.setMatchReplaceBytes(matchBytes, replaceBytes));
+ serverSockets.forEach( s -> s.setMatchReplaceBytes(matchBytes, replaceBytes));
+
+ }
+
+ @Override
+ public Socket createSocket(String host, int port) throws IOException {
+ Socket socket = RMISocketFactory.getDefaultSocketFactory()
+ .createSocket(host, port);
+ InterposeSocket s = new InterposeSocket(socket, matchBytes, replaceBytes);
+ sockets.add(s);
+ return s;
+ }
+
+ /**
+ * Return the current list of sockets.
+ * @return Return a snapshot of the current list of sockets
+ */
+ public List<InterposeSocket> getSockets() {
+ List<InterposeSocket> snap = new ArrayList<>(sockets);
+ return snap;
+ }
+
+ @Override
+ public ServerSocket createServerSocket(int port) throws IOException {
+
+ ServerSocket serverSocket = RMISocketFactory.getDefaultSocketFactory()
+ .createServerSocket(port);
+ InterposeServerSocket ss = new InterposeServerSocket(serverSocket, matchBytes, replaceBytes);
+ serverSockets.add(ss);
+ return ss;
+ }
+
+ /**
+ * Return the current list of server sockets.
+ * @return Return a snapshot of the current list of server sockets
+ */
+ public List<InterposeServerSocket> getServerSockets() {
+ List<InterposeServerSocket> snap = new ArrayList<>(serverSockets);
+ return snap;
+ }
+
+ /**
+ * An InterposeSocket wraps a socket that produces InputStreams
+ * and OutputStreams that log the traffic.
+ * The OutputStreams it produces match an array of bytes and replace them.
+ * Useful for injecting protocol and content errors.
+ */
+ public static class InterposeSocket extends Socket {
+ private final Socket socket;
+ private InputStream in;
+ private MatchReplaceOutputStream out;
+ private volatile byte[] matchBytes;
+ private volatile byte[] replaceBytes;
+ private final ByteArrayOutputStream inLogStream;
+ private final ByteArrayOutputStream outLogStream;
+ private final String name;
+ private static volatile int num = 0; // index for created InterposeSockets
+
+ public InterposeSocket(Socket socket, byte[] matchBytes, byte[] replaceBytes) {
+ this.socket = socket;
+ this.matchBytes = Objects.requireNonNull(matchBytes, "matchBytes");
+ this.replaceBytes = Objects.requireNonNull(replaceBytes, "replaceBytes");
+ this.inLogStream = new ByteArrayOutputStream();
+ this.outLogStream = new ByteArrayOutputStream();
+ this.name = "IS" + ++num + "::"
+ + Thread.currentThread().getName() + ": "
+ + socket.getLocalPort() + " < " + socket.getPort();
+ }
+
+ public void setMatchReplaceBytes(byte[] matchBytes, byte[] replaceBytes) {
+ this.matchBytes = matchBytes;
+ this.replaceBytes = replaceBytes;
+ out.setMatchReplaceBytes(matchBytes, replaceBytes);
+ }
+
+ @Override
+ public void connect(SocketAddress endpoint) throws IOException {
+ socket.connect(endpoint);
+ }
+
+ @Override
+ public void connect(SocketAddress endpoint, int timeout) throws IOException {
+ socket.connect(endpoint, timeout);
+ }
+
+ @Override
+ public void bind(SocketAddress bindpoint) throws IOException {
+ socket.bind(bindpoint);
+ }
+
+ @Override
+ public InetAddress getInetAddress() {
+ return socket.getInetAddress();
+ }
+
+ @Override
+ public InetAddress getLocalAddress() {
+ return socket.getLocalAddress();
+ }
+
+ @Override
+ public int getPort() {
+ return socket.getPort();
+ }
+
+ @Override
+ public int getLocalPort() {
+ return socket.getLocalPort();
+ }
+
+ @Override
+ public SocketAddress getRemoteSocketAddress() {
+ return socket.getRemoteSocketAddress();
+ }
+
+ @Override
+ public SocketAddress getLocalSocketAddress() {
+ return socket.getLocalSocketAddress();
+ }
+
+ @Override
+ public SocketChannel getChannel() {
+ return socket.getChannel();
+ }
+
+ @Override
+ public synchronized void close() throws IOException {
+ socket.close();
+ }
+
+ @Override
+ public String toString() {
+ return "InterposeSocket " + name + ": " + socket.toString();
+ }
+
+ @Override
+ public boolean isConnected() {
+ return socket.isConnected();
+ }
+
+ @Override
+ public boolean isBound() {
+ return socket.isBound();
+ }
+
+ @Override
+ public boolean isClosed() {
+ return socket.isClosed();
+ }
+
+ @Override
+ public <T> Socket setOption(SocketOption<T> name, T value) throws IOException {
+ return socket.setOption(name, value);
+ }
+
+ @Override
+ public <T> T getOption(SocketOption<T> name) throws IOException {
+ return socket.getOption(name);
+ }
+
+ @Override
+ public Set<SocketOption<?>> supportedOptions() {
+ return socket.supportedOptions();
+ }
+
+ @Override
+ public synchronized InputStream getInputStream() throws IOException {
+ if (in == null) {
+ in = socket.getInputStream();
+ String name = Thread.currentThread().getName() + ": "
+ + socket.getLocalPort() + " < " + socket.getPort();
+ in = new LoggingInputStream(in, name, inLogStream);
+ DEBUG("Created new InterposeInputStream: %s%n", name);
+ }
+ return in;
+ }
+
+ @Override
+ public synchronized OutputStream getOutputStream() throws IOException {
+ if (out == null) {
+ OutputStream o = socket.getOutputStream();
+ String name = Thread.currentThread().getName() + ": "
+ + socket.getLocalPort() + " > " + socket.getPort();
+ out = new MatchReplaceOutputStream(o, name, outLogStream, matchBytes, replaceBytes);
+ DEBUG("Created new MatchReplaceOutputStream: %s%n", name);
+ }
+ return out;
+ }
+
+ /**
+ * Return the bytes logged from the input stream.
+ * @return Return the bytes logged from the input stream.
+ */
+ public byte[] getInLogBytes() {
+ return inLogStream.toByteArray();
+ }
+
+ /**
+ * Return the bytes logged from the output stream.
+ * @return Return the bytes logged from the output stream.
+ */
+ public byte[] getOutLogBytes() {
+ return outLogStream.toByteArray();
+ }
+
+ }
+
+ /**
+ * InterposeServerSocket is a ServerSocket that wraps each Socket it accepts
+ * with an InterposeSocket so that its input and output streams can be monitored.
+ */
+ public static class InterposeServerSocket extends ServerSocket {
+ private final ServerSocket socket;
+ private volatile byte[] matchBytes;
+ private volatile byte[] replaceBytes;
+ private final List<InterposeSocket> sockets = new ArrayList<>();
+
+ public InterposeServerSocket(ServerSocket socket, byte[] matchBytes, byte[] replaceBytes) throws IOException {
+ this.socket = socket;
+ this.matchBytes = Objects.requireNonNull(matchBytes, "matchBytes");
+ this.replaceBytes = Objects.requireNonNull(replaceBytes, "replaceBytes");
+ }
+
+ public void setMatchReplaceBytes(byte[] matchBytes, byte[] replaceBytes) {
+ this.matchBytes = matchBytes;
+ this.replaceBytes = replaceBytes;
+ sockets.forEach(s -> s.setMatchReplaceBytes(matchBytes, replaceBytes));
+ }
+ /**
+ * Return a snapshot of the current list of sockets created from this server socket.
+ * @return Return a snapshot of the current list of sockets
+ */
+ public List<InterposeSocket> getSockets() {
+ List<InterposeSocket> snap = new ArrayList<>(sockets);
+ return snap;
+ }
+
+ @Override
+ public void bind(SocketAddress endpoint) throws IOException {
+ socket.bind(endpoint);
+ }
+
+ @Override
+ public void bind(SocketAddress endpoint, int backlog) throws IOException {
+ socket.bind(endpoint, backlog);
+ }
+
+ @Override
+ public InetAddress getInetAddress() {
+ return socket.getInetAddress();
+ }
+
+ @Override
+ public int getLocalPort() {
+ return socket.getLocalPort();
+ }
+
+ @Override
+ public SocketAddress getLocalSocketAddress() {
+ return socket.getLocalSocketAddress();
+ }
+
+ @Override
+ public Socket accept() throws IOException {
+ Socket s = socket.accept();
+ InterposeSocket socket = new InterposeSocket(s, matchBytes, replaceBytes);
+ sockets.add(socket);
+ return socket;
+ }
+
+ @Override
+ public void close() throws IOException {
+ socket.close();
+ }
+
+ @Override
+ public ServerSocketChannel getChannel() {
+ return socket.getChannel();
+ }
+
+ @Override
+ public boolean isClosed() {
+ return socket.isClosed();
+ }
+
+ @Override
+ public String toString() {
+ return socket.toString();
+ }
+
+ @Override
+ public <T> ServerSocket setOption(SocketOption<T> name, T value) throws IOException {
+ return socket.setOption(name, value);
+ }
+
+ @Override
+ public <T> T getOption(SocketOption<T> name) throws IOException {
+ return socket.getOption(name);
+ }
+
+ @Override
+ public Set<SocketOption<?>> supportedOptions() {
+ return socket.supportedOptions();
+ }
+
+ @Override
+ public synchronized void setSoTimeout(int timeout) throws SocketException {
+ socket.setSoTimeout(timeout);
+ }
+
+ @Override
+ public synchronized int getSoTimeout() throws IOException {
+ return socket.getSoTimeout();
+ }
+ }
+
+ /**
+ * LoggingInputStream is a stream and logs all bytes read to it.
+ * For identification it is given a name.
+ */
+ public static class LoggingInputStream extends FilterInputStream {
+ private int bytesIn = 0;
+ private final String name;
+ private final OutputStream log;
+
+ public LoggingInputStream(InputStream in, String name, OutputStream log) {
+ super(in);
+ this.name = name;
+ this.log = log;
+ }
+
+ @Override
+ public int read() throws IOException {
+ int b = super.read();
+ if (b >= 0) {
+ log.write(b);
+ bytesIn++;
+ }
+ return b;
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ int bytes = super.read(b, off, len);
+ if (bytes > 0) {
+ log.write(b, off, bytes);
+ bytesIn += bytes;
+ }
+ return bytes;
+ }
+
+ @Override
+ public int read(byte[] b) throws IOException {
+ return read(b, 0, b.length);
+ }
+
+ @Override
+ public void close() throws IOException {
+ super.close();
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s: In: (%d)", name, bytesIn);
+ }
+ }
+
+ /**
+ * An OutputStream that replaces one string of bytes with another.
+ * If any range matches, the match starts after the partial match.
+ */
+ static class MatchReplaceOutputStream extends OutputStream {
+ private final OutputStream out;
+ private final String name;
+ private volatile byte[] matchBytes;
+ private volatile byte[] replaceBytes;
+ int matchIndex;
+ private int bytesOut = 0;
+ private final OutputStream log;
+
+ MatchReplaceOutputStream(OutputStream out, String name, OutputStream log,
+ byte[] matchBytes, byte[] replaceBytes) {
+ this.out = out;
+ this.name = name;
+ this.matchBytes = Objects.requireNonNull(matchBytes, "matchBytes");
+ this.replaceBytes = Objects.requireNonNull(replaceBytes, "replaceBytes");
+ matchIndex = 0;
+ this.log = log;
+ }
+
+ public void setMatchReplaceBytes(byte[] matchBytes, byte[] replaceBytes) {
+ this.matchBytes = matchBytes;
+ this.replaceBytes = replaceBytes;
+ matchIndex = 0;
+ }
+
+
+ public void write(int b) throws IOException {
+ b = b & 0xff;
+ if (matchBytes.length == 0) {
+ out.write(b);
+ log.write(b);
+ bytesOut++;
+ return;
+ }
+ if (b == (matchBytes[matchIndex] & 0xff)) {
+ if (++matchIndex >= matchBytes.length) {
+ matchIndex = 0;
+ DEBUG( "TestSocketFactory MatchReplace %s replaced %d bytes at offset: %d (x%04x)%n",
+ name, replaceBytes.length, bytesOut, bytesOut);
+ out.write(replaceBytes);
+ log.write(replaceBytes);
+ bytesOut += replaceBytes.length;
+ }
+ } else {
+ if (matchIndex > 0) {
+ // mismatch, write out any that matched already
+ if (matchIndex > 0) // Only non-trivial matches
+ DEBUG( "Partial match %s matched %d bytes at offset: %d (0x%04x), expected: x%02x, actual: x%02x%n",
+ name, matchIndex, bytesOut, bytesOut, matchBytes[matchIndex], b);
+ out.write(matchBytes, 0, matchIndex);
+ log.write(matchBytes, 0, matchIndex);
+ bytesOut += matchIndex;
+ matchIndex = 0;
+ }
+ if (b == (matchBytes[matchIndex] & 0xff)) {
+ matchIndex++;
+ } else {
+ out.write(b);
+ log.write(b);
+ bytesOut++;
+ }
+ }
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s: Out: (%d)", name, bytesOut);
+ }
+ }
+
+ private static byte[] orig = new byte[]{
+ (byte) 0x80, 0x05,
+ 0x73, 0x72, 0x00, 0x12, // TC_OBJECT, TC_CLASSDESC, length = 18
+ 0x6A, 0x61, 0x76, 0x61, 0x2E, 0x72, 0x6D, 0x69, 0x2E, // "java.rmi."
+ 0x64, 0x67, 0x63, 0x2E, 0x4C, 0x65, 0x61, 0x73, 0x65 // "dgc.Lease"
+ };
+ private static byte[] repl = new byte[]{
+ (byte) 0x80, 0x05,
+ 0x73, 0x72, 0x00, 0x12, // TC_OBJECT, TC_CLASSDESC, length = 18
+ 0x6A, 0x61, 0x76, 0x61, 0x2E, (byte) 'l', (byte) 'a', (byte) 'n', (byte) 'g',
+ 0x2E, (byte) 'R', (byte) 'u', (byte) 'n', (byte) 'n', (byte) 'a', (byte) 'b', (byte) 'l',
+ (byte) 'e'
+ };
+
+ @DataProvider(name = "MatchReplaceData")
+ static Object[][] matchReplaceData() {
+ byte[] empty = new byte[0];
+ byte[] byte1 = new byte[]{1, 2, 3, 4, 5, 6};
+ byte[] bytes2 = new byte[]{1, 2, 4, 3, 5, 6};
+ byte[] bytes3 = new byte[]{6, 5, 4, 3, 2, 1};
+ byte[] bytes4 = new byte[]{1, 2, 0x10, 0x20, 0x30, 0x40, 5, 6};
+ byte[] bytes4a = new byte[]{1, 2, 0x10, 0x20, 0x30, 0x40, 5, 7}; // mostly matches bytes4
+ byte[] bytes5 = new byte[]{0x30, 0x40, 5, 6};
+ byte[] bytes6 = new byte[]{1, 2, 0x10, 0x20, 0x30};
+
+ return new Object[][]{
+ {new byte[]{}, new byte[]{}, empty, empty},
+ {new byte[]{}, new byte[]{}, byte1, byte1},
+ {new byte[]{3, 4}, new byte[]{4, 3}, byte1, bytes2}, //swap bytes
+ {new byte[]{3, 4}, new byte[]{0x10, 0x20, 0x30, 0x40}, byte1, bytes4}, // insert
+ {new byte[]{1, 2, 0x10, 0x20}, new byte[]{}, bytes4, bytes5}, // delete head
+ {new byte[]{0x40, 5, 6}, new byte[]{}, bytes4, bytes6}, // delete tail
+ {new byte[]{0x40, 0x50}, new byte[]{0x60, 0x50}, bytes4, bytes4}, // partial match, replace nothing
+ {bytes4a, bytes3, bytes4, bytes4}, // long partial match, not replaced
+ {orig, repl, orig, repl},
+ };
+ }
+
+ @Test(enabled = true, dataProvider = "MatchReplaceData")
+ static void test3(byte[] match, byte[] replace,
+ byte[] input, byte[] expected) {
+ System.out.printf("match: %s, replace: %s%n", Arrays.toString(match), Arrays.toString(replace));
+ try (ByteArrayOutputStream output = new ByteArrayOutputStream();
+ ByteArrayOutputStream log = new ByteArrayOutputStream();
+ OutputStream out = new MatchReplaceOutputStream(output, "test3",
+ log, match, replace)) {
+ out.write(input);
+ byte[] actual = output.toByteArray();
+ long index = Arrays.mismatch(actual, expected);
+
+ if (index >= 0) {
+ System.out.printf("array mismatch, offset: %d%n", index);
+ System.out.printf("actual: %s%n", Arrays.toString(actual));
+ System.out.printf("expected: %s%n", Arrays.toString(expected));
+ }
+ Assert.assertEquals(actual, expected, "match/replace fail");
+ } catch (IOException ioe) {
+ Assert.fail("unexpected exception", ioe);
+ }
+ }
+
+
+
+}
diff --git a/test/javax/management/remote/nonLocalAccess/NonLocalJMXRemoteTest.java b/test/javax/management/remote/nonLocalAccess/NonLocalJMXRemoteTest.java
new file mode 100644
index 0000000..d05aff1
--- /dev/null
+++ b/test/javax/management/remote/nonLocalAccess/NonLocalJMXRemoteTest.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2017, 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.net.InetAddress;
+import java.rmi.AccessException;
+import java.rmi.NotBoundException;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+import java.util.Set;
+
+/* @test
+ * @bug 8174770
+ * @summary Verify that JMX Registry rejects non-local access for bind, unbind, rebind.
+ * The test is manual because the (non-local) host and port running JMX must be supplied as properties.
+ * @run main/othervm/manual -Djmx-registry.host=jmx-registry-host -Djmx-registry.port=jmx-registry-port NonLocalJMXRemoteTest
+ */
+
+/**
+ * Verify that access checks for the Registry exported by JMX Registry.bind(),
+ * .rebind(), and .unbind() are prevented on remote access to the registry.
+ * The test verifies that the access check is performed *before* the object to be
+ * bound or rebound is deserialized.
+ * This tests the SingleEntryRegistry implemented by JMX.
+ * This test is a manual test and uses JMX running on a *different* host.
+ * JMX can be enabled in any Java runtime; for example:
+ * login or ssh to the different host and invoke rmiregistry with arguments below.
+ * It will not show any output.
+ * {@code $JDK_HOME/bin/rmiregistry \
+ * -J-Dcom.sun.management.jmxremote.port=8888 \
+ * -J-Dcom.sun.management.jmxremote.local.only=false \
+ * -J-Dcom.sun.management.jmxremote.ssl=false \
+ * -J-Dcom.sun.management.jmxremote.authenticate=false
+ * }
+ * On the first host modify the @run command above to replace "jmx-registry-host"
+ * with the hostname or IP address of the different host and run the test with jtreg.
+ */
+public class NonLocalJMXRemoteTest {
+
+ public static void main(String[] args) throws Exception {
+
+ String host = System.getProperty("jmx-registry.host");
+ if (host == null || host.isEmpty()) {
+ throw new RuntimeException("Specify host with system property: -Djmx-registry.host=<host>");
+ }
+ int port = Integer.getInteger("jmx-registry.port", -1);
+ if (port <= 0) {
+ throw new RuntimeException("Specify port with system property: -Djmx-registry.port=<port>");
+ }
+
+ // Check if running the test on a local system; it only applies to remote
+ String myHostName = InetAddress.getLocalHost().getHostName();
+ Set<InetAddress> myAddrs = Set.of(InetAddress.getAllByName(myHostName));
+ Set<InetAddress> hostAddrs = Set.of(InetAddress.getAllByName(host));
+ if (hostAddrs.stream().anyMatch(i -> myAddrs.contains(i))
+ || hostAddrs.stream().anyMatch(h -> h.isLoopbackAddress())) {
+ throw new RuntimeException("Error: property 'jmx-registry.host' must not be the local host%n");
+ }
+
+ Registry registry = LocateRegistry.getRegistry(host, port);
+ try {
+ // Verify it is a JMX Registry
+ registry.lookup("jmxrmi");
+ } catch (NotBoundException nf) {
+ throw new RuntimeException("Not a JMX registry, jmxrmi is not bound", nf);
+ }
+
+ try {
+ registry.bind("foo", null);
+ throw new RuntimeException("Remote access should not succeed for method: bind");
+ } catch (Exception e) {
+ assertIsAccessException(e);
+ }
+
+ try {
+ registry.rebind("foo", null);
+ throw new RuntimeException("Remote access should not succeed for method: rebind");
+ } catch (Exception e) {
+ assertIsAccessException(e);
+ }
+
+ try {
+ registry.unbind("foo");
+ throw new RuntimeException("Remote access should not succeed for method: unbind");
+ } catch (Exception e) {
+ assertIsAccessException(e);
+ }
+ }
+
+ /**
+ * Check the exception chain for the expected AccessException and message.
+ * @param ex the exception from the remote invocation.
+ */
+ private static void assertIsAccessException(Throwable ex) {
+ Throwable t = ex;
+ while (!(t instanceof AccessException) && t.getCause() != null) {
+ t = t.getCause();
+ }
+ if (t instanceof AccessException) {
+ String msg = t.getMessage();
+ int asIndex = msg.indexOf("Registry");
+ int disallowIndex = msg.indexOf("disallowed");
+ int nonLocalHostIndex = msg.indexOf("non-local host");
+ if (asIndex < 0 ||
+ disallowIndex < 0 ||
+ nonLocalHostIndex < 0 ) {
+ throw new RuntimeException("exception message is malformed", t);
+ }
+ System.out.printf("Found expected AccessException: %s%n%n", t);
+ } else {
+ throw new RuntimeException("AccessException did not occur when expected", ex);
+ }
+ }
+}