# HG changeset patch # User asaha # Date 1500006847 25200 # Node ID 711620fe31712e7e0a3fb149b472b80ee95eae2b # Parent b54b35b343186d46ef05b934c4b7cd6828c6eedb# Parent 25cb5143b701737e931b473e3d531960327858a1 Merge diff -r b54b35b34318 -r 711620fe3171 jdk/make/rmic/Rmic-java.rmi.gmk --- a/jdk/make/rmic/Rmic-java.rmi.gmk Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/make/rmic/Rmic-java.rmi.gmk Thu Jul 13 21:34:07 2017 -0700 @@ -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 -r b54b35b34318 -r 711620fe3171 jdk/src/java.base/share/classes/java/security/CodeSource.java --- a/jdk/src/java.base/share/classes/java/security/CodeSource.java Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/java.base/share/classes/java/security/CodeSource.java Thu Jul 13 21:34:07 2017 -0700 @@ -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 cfs = null; + List 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 -r b54b35b34318 -r 711620fe3171 jdk/src/java.base/share/classes/java/util/Vector.java diff -r b54b35b34318 -r 711620fe3171 jdk/src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java --- a/jdk/src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java Thu Jul 13 21:34:07 2017 -0700 @@ -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. * + *

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 pa = () -> { shutdown(); return null; }; + AccessController.doPrivileged(pa, acc); + } } /** diff -r b54b35b34318 -r 711620fe3171 jdk/src/java.base/share/classes/java/util/jar/JarVerifier.java --- a/jdk/src/java.base/share/classes/java/util/jar/JarVerifier.java Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/java.base/share/classes/java/util/jar/JarVerifier.java Thu Jul 13 21:34:07 2017 -0700 @@ -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 -r b54b35b34318 -r 711620fe3171 jdk/src/java.base/share/classes/sun/nio/ch/AsynchronousChannelGroupImpl.java --- a/jdk/src/java.base/share/classes/sun/nio/ch/AsynchronousChannelGroupImpl.java Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/java.base/share/classes/sun/nio/ch/AsynchronousChannelGroupImpl.java Thu Jul 13 21:34:07 2017 -0700 @@ -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 -r b54b35b34318 -r 711620fe3171 jdk/src/java.base/share/classes/sun/security/pkcs/PKCS8Key.java --- a/jdk/src/java.base/share/classes/sun/security/pkcs/PKCS8Key.java Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/java.base/share/classes/sun/security/pkcs/PKCS8Key.java Thu Jul 13 21:34:07 2017 -0700 @@ -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 -r b54b35b34318 -r 711620fe3171 jdk/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java --- a/jdk/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java Thu Jul 13 21:34:07 2017 -0700 @@ -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 -r b54b35b34318 -r 711620fe3171 jdk/src/java.base/share/classes/sun/security/provider/DSA.java --- a/jdk/src/java.base/share/classes/sun/security/provider/DSA.java Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/java.base/share/classes/sun/security/provider/DSA.java Thu Jul 13 21:34:07 2017 -0700 @@ -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 -r b54b35b34318 -r 711620fe3171 jdk/src/java.base/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java --- a/jdk/src/java.base/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/java.base/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java Thu Jul 13 21:34:07 2017 -0700 @@ -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 -r b54b35b34318 -r 711620fe3171 jdk/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java --- a/jdk/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java Thu Jul 13 21:34:07 2017 -0700 @@ -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 -r b54b35b34318 -r 711620fe3171 jdk/src/java.base/share/classes/sun/security/util/HostnameChecker.java --- a/jdk/src/java.base/share/classes/sun/security/util/HostnameChecker.java Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/java.base/share/classes/sun/security/util/HostnameChecker.java Thu Jul 13 21:34:07 2017 -0700 @@ -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> 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 -r b54b35b34318 -r 711620fe3171 jdk/src/java.base/share/classes/sun/security/util/ManifestEntryVerifier.java --- a/jdk/src/java.base/share/classes/sun/security/util/ManifestEntryVerifier.java Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/java.base/share/classes/sun/security/util/ManifestEntryVerifier.java Thu Jul 13 21:34:07 2017 -0700 @@ -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 -r b54b35b34318 -r 711620fe3171 jdk/src/java.base/share/conf/security/java.security --- a/jdk/src/java.base/share/conf/security/java.security Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/java.base/share/conf/security/java.security Thu Jul 13 21:34:07 2017 -0700 @@ -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 -r b54b35b34318 -r 711620fe3171 jdk/src/java.base/share/native/libverify/check_code.c --- a/jdk/src/java.base/share/native/libverify/check_code.c Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/java.base/share/native/libverify/check_code.c Thu Jul 13 21:34:07 2017 -0700 @@ -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 -r b54b35b34318 -r 711620fe3171 jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java Thu Jul 13 21:34:07 2017 -0700 @@ -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 -r b54b35b34318 -r 711620fe3171 jdk/src/java.desktop/share/classes/javax/imageio/spi/ServiceRegistry.java --- a/jdk/src/java.desktop/share/classes/javax/imageio/spi/ServiceRegistry.java Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/java.desktop/share/classes/javax/imageio/spi/ServiceRegistry.java Thu Jul 13 21:34:07 2017 -0700 @@ -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 poset = new PartiallyOrderedSet<>(); + // Provider Objects organized by partial ordering + final PartiallyOrderedSet poset = new PartiallyOrderedSet<>(); // Class -> Provider Object of that class // No way to express heterogeneous map, we want // Map, T>, where T is ? - Map, Object> map = new HashMap<>(); + final Map, Object> map = new HashMap<>(); + final Map, 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) () -> { + rs.onDeregistration(registry, category); + return null; + }, acc); + } } } poset.clear(); + accMap.clear(); } @SuppressWarnings("deprecation") diff -r b54b35b34318 -r 711620fe3171 jdk/src/java.desktop/share/classes/sun/awt/image/ImageWatched.java --- a/jdk/src/java.desktop/share/classes/sun/awt/image/ImageWatched.java Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/java.desktop/share/classes/sun/awt/image/ImageWatched.java Thu Jul 13 21:34:07 2017 -0700 @@ -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 extends WeakReference { + + 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 myref; + private final AccWeakReference myref; private Link next; public WeakLink(ImageObserver obs, Link next) { - myref = new WeakReference(obs); + myref = new AccWeakReference(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) () -> { + 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 -r b54b35b34318 -r 711620fe3171 jdk/src/java.desktop/share/native/libjavajpeg/imageioJPEG.c --- a/jdk/src/java.desktop/share/native/libjavajpeg/imageioJPEG.c Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/java.desktop/share/native/libjavajpeg/imageioJPEG.c Thu Jul 13 21:34:07 2017 -0700 @@ -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 + 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); - } else { - jpeg_abort_decompress(cinfo); } free(scanLinePtr); diff -r b54b35b34318 -r 711620fe3171 jdk/src/java.naming/share/classes/com/sun/jndi/ldap/LdapClient.java --- a/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/LdapClient.java Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/LdapClient.java Thu Jul 13 21:34:07 2017 -0700 @@ -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 -r b54b35b34318 -r 711620fe3171 jdk/src/java.naming/share/classes/com/sun/jndi/ldap/LdapCtx.java --- a/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/LdapCtx.java Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/LdapCtx.java Thu Jul 13 21:34:07 2017 -0700 @@ -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 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 -r b54b35b34318 -r 711620fe3171 jdk/src/java.naming/share/classes/com/sun/jndi/ldap/LdapReferralException.java --- a/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/LdapReferralException.java Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/LdapReferralException.java Thu Jul 13 21:34:07 2017 -0700 @@ -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 -r b54b35b34318 -r 711620fe3171 jdk/src/java.naming/share/classes/javax/naming/directory/BasicAttribute.java --- a/jdk/src/java.naming/share/classes/javax/naming/directory/BasicAttribute.java Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/java.naming/share/classes/javax/naming/directory/BasicAttribute.java Thu Jul 13 21:34:07 2017 -0700 @@ -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 -r b54b35b34318 -r 711620fe3171 jdk/src/java.naming/share/classes/sun/security/provider/certpath/ldap/LDAPCertStoreImpl.java --- a/jdk/src/java.naming/share/classes/sun/security/provider/certpath/ldap/LDAPCertStoreImpl.java Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/java.naming/share/classes/sun/security/provider/certpath/ldap/LDAPCertStoreImpl.java Thu Jul 13 21:34:07 2017 -0700 @@ -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 -r b54b35b34318 -r 711620fe3171 jdk/src/java.rmi/share/classes/java/rmi/activation/ActivationID.java --- a/jdk/src/java.rmi/share/classes/java/rmi/activation/ActivationID.java Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/java.rmi/share/classes/java/rmi/activation/ActivationID.java Thu Jul 13 21:34:07 2017 -0700 @@ -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 ActivationID takes a single * argument, activator, that specifies a remote reference to the @@ -116,13 +130,19 @@ try { MarshalledObject 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() { + 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 -r b54b35b34318 -r 711620fe3171 jdk/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl.java --- a/jdk/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl.java Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl.java Thu Jul 13 21:34:07 2017 -0700 @@ -75,6 +75,10 @@ * registry. * * The LocateRegistry class is used to obtain registry for different hosts. + *

+ * 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() { 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 -r b54b35b34318 -r 711620fe3171 jdk/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl_Skel.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl_Skel.java Thu Jul 13 21:34:07 2017 -0700 @@ -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 -r b54b35b34318 -r 711620fe3171 jdk/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl_Stub.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl_Stub.java Thu Jul 13 21:34:07 2017 -0700 @@ -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 -r b54b35b34318 -r 711620fe3171 jdk/src/java.rmi/share/classes/sun/rmi/server/Activation.java --- a/jdk/src/java.rmi/share/classes/sun/rmi/server/Activation.java Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/java.rmi/share/classes/sun/rmi/server/Activation.java Thu Jul 13 21:34:07 2017 -0700 @@ -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 -r b54b35b34318 -r 711620fe3171 jdk/src/java.rmi/share/classes/sun/rmi/server/UnicastRef.java --- a/jdk/src/java.rmi/share/classes/sun/rmi/server/UnicastRef.java Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/java.rmi/share/classes/sun/rmi/server/UnicastRef.java Thu Jul 13 21:34:07 2017 -0700 @@ -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 -r b54b35b34318 -r 711620fe3171 jdk/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef.java --- a/jdk/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef.java Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef.java Thu Jul 13 21:34:07 2017 -0700 @@ -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,20 +289,25 @@ 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"); - } + } 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); + readEx); } /* @@ -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); + try { + hash = in.readLong(); + } catch (Exception ioe) { + throw new UnmarshalException("error unmarshalling call header", ioe); + } - 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(); - } + // 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 -r b54b35b34318 -r 711620fe3171 jdk/src/java.rmi/share/classes/sun/rmi/transport/ConnectionInputStream.java --- a/jdk/src/java.rmi/share/classes/sun/rmi/transport/ConnectionInputStream.java Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/java.rmi/share/classes/sun/rmi/transport/ConnectionInputStream.java Thu Jul 13 21:34:07 2017 -0700 @@ -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 -r b54b35b34318 -r 711620fe3171 jdk/src/java.rmi/share/classes/sun/rmi/transport/DGCClient.java --- a/jdk/src/java.rmi/share/classes/sun/rmi/transport/DGCClient.java Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/java.rmi/share/classes/sun/rmi/transport/DGCClient.java Thu Jul 13 21:34:07 2017 -0700 @@ -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 -r b54b35b34318 -r 711620fe3171 jdk/src/java.rmi/share/classes/sun/rmi/transport/DGCImpl_Skel.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.rmi/share/classes/sun/rmi/transport/DGCImpl_Skel.java Thu Jul 13 21:34:07 2017 -0700 @@ -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 -r b54b35b34318 -r 711620fe3171 jdk/src/java.rmi/share/classes/sun/rmi/transport/DGCImpl_Stub.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.rmi/share/classes/sun/rmi/transport/DGCImpl_Stub.java Thu Jul 13 21:34:07 2017 -0700 @@ -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)() -> { + 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 -r b54b35b34318 -r 711620fe3171 jdk/src/java.rmi/share/classes/sun/rmi/transport/StreamRemoteCall.java --- a/jdk/src/java.rmi/share/classes/sun/rmi/transport/StreamRemoteCall.java Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/java.rmi/share/classes/sun/rmi/transport/StreamRemoteCall.java Thu Jul 13 21:34:07 2017 -0700 @@ -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 -r b54b35b34318 -r 711620fe3171 jdk/src/jdk.crypto.ec/share/classes/sun/security/ec/ECDSASignature.java --- a/jdk/src/jdk.crypto.ec/share/classes/sun/security/ec/ECDSASignature.java Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/jdk.crypto.ec/share/classes/sun/security/ec/ECDSASignature.java Thu Jul 13 21:34:07 2017 -0700 @@ -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 -r b54b35b34318 -r 711620fe3171 jdk/src/jdk.crypto.ec/share/native/libsunec/ECC_JNI.cpp --- a/jdk/src/jdk.crypto.ec/share/native/libsunec/ECC_JNI.cpp Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/jdk.crypto.ec/share/native/libsunec/ECC_JNI.cpp Thu Jul 13 21:34:07 2017 -0700 @@ -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 -r b54b35b34318 -r 711620fe3171 jdk/src/jdk.crypto.ec/share/native/libsunec/impl/ec.c --- a/jdk/src/jdk.crypto.ec/share/native/libsunec/impl/ec.c Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/jdk.crypto.ec/share/native/libsunec/impl/ec.c Thu Jul 13 21:34:07 2017 -0700 @@ -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 and * Douglas Stebila , 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 -r b54b35b34318 -r 711620fe3171 jdk/src/jdk.crypto.ec/share/native/libsunec/impl/ec2.h --- a/jdk/src/jdk.crypto.ec/share/native/libsunec/impl/ec2.h Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/jdk.crypto.ec/share/native/libsunec/impl/ec2.h Thu Jul 13 21:34:07 2017 -0700 @@ -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 , 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 -r b54b35b34318 -r 711620fe3171 jdk/src/jdk.crypto.ec/share/native/libsunec/impl/ec2_aff.c --- a/jdk/src/jdk.crypto.ec/share/native/libsunec/impl/ec2_aff.c Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/jdk.crypto.ec/share/native/libsunec/impl/ec2_aff.c Thu Jul 13 21:34:07 2017 -0700 @@ -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 , 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 -r b54b35b34318 -r 711620fe3171 jdk/src/jdk.crypto.ec/share/native/libsunec/impl/ec2_mont.c --- a/jdk/src/jdk.crypto.ec/share/native/libsunec/impl/ec2_mont.c Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/jdk.crypto.ec/share/native/libsunec/impl/ec2_mont.c Thu Jul 13 21:34:07 2017 -0700 @@ -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 , and * Douglas Stebila , 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 -r b54b35b34318 -r 711620fe3171 jdk/src/jdk.crypto.ec/share/native/libsunec/impl/ecc_impl.h --- a/jdk/src/jdk.crypto.ec/share/native/libsunec/impl/ecc_impl.h Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/jdk.crypto.ec/share/native/libsunec/impl/ecc_impl.h Thu Jul 13 21:34:07 2017 -0700 @@ -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 and * Douglas Stebila , 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 -r b54b35b34318 -r 711620fe3171 jdk/src/jdk.crypto.ec/share/native/libsunec/impl/ecl-priv.h --- a/jdk/src/jdk.crypto.ec/share/native/libsunec/impl/ecl-priv.h Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/jdk.crypto.ec/share/native/libsunec/impl/ecl-priv.h Thu Jul 13 21:34:07 2017 -0700 @@ -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 and * Douglas Stebila , 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 -r b54b35b34318 -r 711620fe3171 jdk/src/jdk.crypto.ec/share/native/libsunec/impl/ecl.h --- a/jdk/src/jdk.crypto.ec/share/native/libsunec/impl/ecl.h Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/jdk.crypto.ec/share/native/libsunec/impl/ecl.h Thu Jul 13 21:34:07 2017 -0700 @@ -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 , 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 -r b54b35b34318 -r 711620fe3171 jdk/src/jdk.crypto.ec/share/native/libsunec/impl/ecl_mult.c --- a/jdk/src/jdk.crypto.ec/share/native/libsunec/impl/ecl_mult.c Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/jdk.crypto.ec/share/native/libsunec/impl/ecl_mult.c Thu Jul 13 21:34:07 2017 -0700 @@ -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 , 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 -r b54b35b34318 -r 711620fe3171 jdk/src/jdk.crypto.ec/share/native/libsunec/impl/ecp.h --- a/jdk/src/jdk.crypto.ec/share/native/libsunec/impl/ecp.h Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/jdk.crypto.ec/share/native/libsunec/impl/ecp.h Thu Jul 13 21:34:07 2017 -0700 @@ -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 , 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 -r b54b35b34318 -r 711620fe3171 jdk/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_aff.c --- a/jdk/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_aff.c Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_aff.c Thu Jul 13 21:34:07 2017 -0700 @@ -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 , and * Lenka Fibikova , 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 -r b54b35b34318 -r 711620fe3171 jdk/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_jac.c --- a/jdk/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_jac.c Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_jac.c Thu Jul 13 21:34:07 2017 -0700 @@ -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 , and * Lenka Fibikova , 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 -r b54b35b34318 -r 711620fe3171 jdk/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_jm.c --- a/jdk/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_jm.c Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_jm.c Thu Jul 13 21:34:07 2017 -0700 @@ -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 , 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 -r b54b35b34318 -r 711620fe3171 jdk/src/jdk.management.agent/share/classes/sun/management/jmxremote/SingleEntryRegistry.java --- a/jdk/src/jdk.management.agent/share/classes/sun/management/jmxremote/SingleEntryRegistry.java Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/jdk.management.agent/share/classes/sun/management/jmxremote/SingleEntryRegistry.java Thu Jul 13 21:34:07 2017 -0700 @@ -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 -r b54b35b34318 -r 711620fe3171 jdk/src/jdk.management/share/classes/com/sun/management/HotSpotDiagnosticMXBean.java --- a/jdk/src/jdk.management/share/classes/com/sun/management/HotSpotDiagnosticMXBean.java Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/jdk.management/share/classes/com/sun/management/HotSpotDiagnosticMXBean.java Thu Jul 13 21:34:07 2017 -0700 @@ -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 live 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 -r b54b35b34318 -r 711620fe3171 jdk/src/jdk.management/share/classes/com/sun/management/internal/HotSpotDiagnostic.java --- a/jdk/src/jdk.management/share/classes/com/sun/management/internal/HotSpotDiagnostic.java Thu Jul 13 19:34:42 2017 +0000 +++ b/jdk/src/jdk.management/share/classes/com/sun/management/internal/HotSpotDiagnostic.java Thu Jul 13 21:34:07 2017 -0700 @@ -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 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 -r b54b35b34318 -r 711620fe3171 jdk/test/java/rmi/activation/nonLocalActivation/NonLocalActivationTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/rmi/activation/nonLocalActivation/NonLocalActivationTest.java Thu Jul 13 21:34:07 2017 -0700 @@ -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="); + } + + // Check if running the test on a local system; it only applies to remote + String myHostName = InetAddress.getLocalHost().getHostName(); + Set myAddrs = Set.of(InetAddress.getAllByName(myHostName)); + Set 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 -r b54b35b34318 -r 711620fe3171 jdk/test/java/rmi/registry/nonLocalRegistry/NonLocalRegistryTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/rmi/registry/nonLocalRegistry/NonLocalRegistryTest.java Thu Jul 13 21:34:07 2017 -0700 @@ -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="); + } + + // Check if running the test on a local system; it only applies to remote + String myHostName = InetAddress.getLocalHost().getHostName(); + Set myAddrs = Set.of(InetAddress.getAllByName(myHostName)); + Set 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 -r b54b35b34318 -r 711620fe3171 jdk/test/java/rmi/testlibrary/TestSocketFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/rmi/testlibrary/TestSocketFactory.java Thu Jul 13 21:34:07 2017 -0700 @@ -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 sockets = new ArrayList<>(); + + private transient final List 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 getSockets() { + List 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 getServerSockets() { + List 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 Socket setOption(SocketOption name, T value) throws IOException { + return socket.setOption(name, value); + } + + @Override + public T getOption(SocketOption name) throws IOException { + return socket.getOption(name); + } + + @Override + public Set> 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 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 getSockets() { + List 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 ServerSocket setOption(SocketOption name, T value) throws IOException { + return socket.setOption(name, value); + } + + @Override + public T getOption(SocketOption name) throws IOException { + return socket.getOption(name); + } + + @Override + public Set> 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 -r b54b35b34318 -r 711620fe3171 jdk/test/javax/management/remote/nonLocalAccess/NonLocalJMXRemoteTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/management/remote/nonLocalAccess/NonLocalJMXRemoteTest.java Thu Jul 13 21:34:07 2017 -0700 @@ -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="); + } + int port = Integer.getInteger("jmx-registry.port", -1); + if (port <= 0) { + throw new RuntimeException("Specify port with system property: -Djmx-registry.port="); + } + + // Check if running the test on a local system; it only applies to remote + String myHostName = InetAddress.getLocalHost().getHostName(); + Set myAddrs = Set.of(InetAddress.getAllByName(myHostName)); + Set 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); + } + } +}