diff --git a/.hgtags b/.hgtags index 686a57f644052ebb9f99b20bfea96797e5066c86..b68c2ddabee1c498292847541c1c85d944e4fe29 100644 --- a/.hgtags +++ b/.hgtags @@ -997,3 +997,6 @@ e880f2d161bf23a09f8c1a19861d7df7d2ed126f jdk8u222-b01 c7a97c9b7e5932d651eda37c8a907311818491d7 jdk8u222-b07 0bb89d93d4d7da64d408a9888df21085e7bfb291 jdk8u222-b08 887c8314411dd461ec4b1e14cd6368ed3d9a7a3b jdk8u232-b00 +0da125166b2bd35aac0d6222ba44535730e2713f jdk8u222-b09 +2a9bea6e5e03a53469abdcd2da268a312cc7b5b8 jdk8u222-b10 +2a9bea6e5e03a53469abdcd2da268a312cc7b5b8 jdk8u222-ga diff --git a/src/macosx/native/java/util/SCDynamicStoreConfig.m b/src/macosx/native/java/util/SCDynamicStoreConfig.m index d3f838871ad7333c88f81d3cf837bada2a3e0017..4ea43635d46e88608c69d8161d7c5688ad4fd734 100644 --- a/src/macosx/native/java/util/SCDynamicStoreConfig.m +++ b/src/macosx/native/java/util/SCDynamicStoreConfig.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2019, 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 @@ -102,7 +102,8 @@ NSDictionary *realmConfigsForRealms(SCDynamicStoreRef store, NSArray *realms) { for (NSString *realm in realms) { CFTypeRef realmInfo = SCDynamicStoreCopyValue(store, (CFStringRef) [NSString stringWithFormat:@"Kerberos:%@", realm]); - if (CFGetTypeID(realmInfo) != CFDictionaryGetTypeID()) { + if (realmInfo == NULL || CFGetTypeID(realmInfo) != CFDictionaryGetTypeID()) { + if (realmInfo) CFRelease(realmInfo); return nil; } diff --git a/src/macosx/native/sun/awt/splashscreen/splashscreen_sys.m b/src/macosx/native/sun/awt/splashscreen/splashscreen_sys.m index 07bbd43e0a516a6abeaa18601ea01648f88da184..0e228f31ef195e37b6a44974abb89a93da3ea885 100644 --- a/src/macosx/native/sun/awt/splashscreen/splashscreen_sys.m +++ b/src/macosx/native/sun/awt/splashscreen/splashscreen_sys.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2019, 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 @@ -184,7 +184,7 @@ SplashInitPlatform(Splash * splash) { splash->maskRequired = 0; - + //TODO: the following is too much of a hack but should work in 90% cases. // besides we don't use device-dependant drawing, so probably // that's very fine indeed @@ -251,9 +251,11 @@ void SplashRedrawWindow(Splash * splash) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - SplashUpdateScreenData(splash); - [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ + // drop the reference to the old view and image + [splash->window setContentView: nil]; + SplashUpdateScreenData(splash); + // NSDeviceRGBColorSpace vs. NSCalibratedRGBColorSpace ? NSBitmapImageRep * rep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes: (unsigned char**)&splash->screenData @@ -281,7 +283,7 @@ SplashRedrawWindow(Splash * splash) { size.height /= scaleFactor; [image setSize: size]; } - + NSImageView * view = [[NSImageView alloc] init]; [view setImage: image]; diff --git a/src/share/classes/com/sun/crypto/provider/AESCrypt.java b/src/share/classes/com/sun/crypto/provider/AESCrypt.java index c85f715e96714d6262c39af5dec8f2712486b7fc..c74f609f3ad4a32ab144b673edbbe8916d14389f 100644 --- a/src/share/classes/com/sun/crypto/provider/AESCrypt.java +++ b/src/share/classes/com/sun/crypto/provider/AESCrypt.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2018, 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 @@ -346,7 +346,15 @@ final class AESCrypt extends SymmetricCipher implements AESConstants * Encrypt exactly one block of plaintext. */ void encryptBlock(byte[] in, int inOffset, - byte[] out, int outOffset) + byte[] out, int outOffset) { + // Array bound checks are done in caller code, i.e. + // FeedbackCipher.encrypt/decrypt(...) to improve performance. + implEncryptBlock(in, inOffset, out, outOffset); + } + + // Encryption operation. Possibly replaced with a compiler intrinsic. + private void implEncryptBlock(byte[] in, int inOffset, + byte[] out, int outOffset) { int keyOffset = 0; int t0 = ((in[inOffset++] ) << 24 | @@ -412,12 +420,19 @@ final class AESCrypt extends SymmetricCipher implements AESConstants out[outOffset ] = (byte)(S[(t2 ) & 0xFF] ^ (tt )); } - /** * Decrypt exactly one block of plaintext. */ void decryptBlock(byte[] in, int inOffset, - byte[] out, int outOffset) + byte[] out, int outOffset) { + // Array bound checks are done in caller code, i.e. + // FeedbackCipher.encrypt/decrypt(...) to improve performance. + implDecryptBlock(in, inOffset, out, outOffset); + } + + // Decrypt operation. Possibly replaced with a compiler intrinsic. + private void implDecryptBlock(byte[] in, int inOffset, + byte[] out, int outOffset) { int keyOffset = 4; int t0 = ((in[inOffset++] ) << 24 | @@ -572,7 +587,6 @@ final class AESCrypt extends SymmetricCipher implements AESConstants out[outOffset ] = (byte)(Si[(a0 ) & 0xFF] ^ (t1 )); } - /** * Expand a user-supplied key material into a session key. * diff --git a/src/share/classes/com/sun/crypto/provider/CipherBlockChaining.java b/src/share/classes/com/sun/crypto/provider/CipherBlockChaining.java index 1d33117dd5d89b015d8775c1426850a9c67c07bb..7fdc6e1f67b22162a4b99afdbeef6a7822aabdfa 100644 --- a/src/share/classes/com/sun/crypto/provider/CipherBlockChaining.java +++ b/src/share/classes/com/sun/crypto/provider/CipherBlockChaining.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2018, 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 @@ -27,7 +27,9 @@ package com.sun.crypto.provider; import java.security.InvalidKeyException; import java.security.ProviderException; +import java.util.Objects; +import sun.security.util.ArrayUtil; /** * This class represents ciphers in cipher block chaining (CBC) mode. @@ -138,18 +140,24 @@ class CipherBlockChaining extends FeedbackCipher { * @return the length of the encrypted data */ int encrypt(byte[] plain, int plainOffset, int plainLen, - byte[] cipher, int cipherOffset) - { + byte[] cipher, int cipherOffset) { if (plainLen <= 0) { return plainLen; } - if ((plainLen % blockSize) != 0) { - throw new ProviderException("Internal error in input buffering"); - } + ArrayUtil.blockSizeCheck(plainLen, blockSize); + ArrayUtil.nullAndBoundsCheck(plain, plainOffset, plainLen); + ArrayUtil.nullAndBoundsCheck(cipher, cipherOffset, plainLen); + return implEncrypt(plain, plainOffset, plainLen, + cipher, cipherOffset); + } + + private int implEncrypt(byte[] plain, int plainOffset, int plainLen, + byte[] cipher, int cipherOffset) + { int endIndex = plainOffset + plainLen; for (; plainOffset < endIndex; - plainOffset+=blockSize, cipherOffset += blockSize) { + plainOffset += blockSize, cipherOffset += blockSize) { for (int i = 0; i < blockSize; i++) { k[i] = (byte)(plain[i + plainOffset] ^ r[i]); } @@ -182,14 +190,19 @@ class CipherBlockChaining extends FeedbackCipher { * @return the length of the decrypted data */ int decrypt(byte[] cipher, int cipherOffset, int cipherLen, - byte[] plain, int plainOffset) - { + byte[] plain, int plainOffset) { if (cipherLen <= 0) { return cipherLen; } - if ((cipherLen % blockSize) != 0) { - throw new ProviderException("Internal error in input buffering"); - } + ArrayUtil.blockSizeCheck(cipherLen, blockSize); + ArrayUtil.nullAndBoundsCheck(cipher, cipherOffset, cipherLen); + ArrayUtil.nullAndBoundsCheck(plain, plainOffset, cipherLen); + return implDecrypt(cipher, cipherOffset, cipherLen, plain, plainOffset); + } + + private int implDecrypt(byte[] cipher, int cipherOffset, int cipherLen, + byte[] plain, int plainOffset) + { int endIndex = cipherOffset + cipherLen; for (; cipherOffset < endIndex; diff --git a/src/share/classes/com/sun/crypto/provider/CipherFeedback.java b/src/share/classes/com/sun/crypto/provider/CipherFeedback.java index 84b527efe5b03afb2e7177b3c65b0b91deed4ae9..71e94cc7ffaee5ac1c7648e51e4025dbe6751cf6 100644 --- a/src/share/classes/com/sun/crypto/provider/CipherFeedback.java +++ b/src/share/classes/com/sun/crypto/provider/CipherFeedback.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2018, 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 @@ -27,6 +27,7 @@ package com.sun.crypto.provider; import java.security.InvalidKeyException; import java.security.ProviderException; +import sun.security.util.ArrayUtil; /** * This class represents ciphers in cipher-feedback (CFB) mode. @@ -149,9 +150,9 @@ final class CipherFeedback extends FeedbackCipher { */ int encrypt(byte[] plain, int plainOffset, int plainLen, byte[] cipher, int cipherOffset) { - if ((plainLen % numBytes) != 0) { - throw new ProviderException("Internal error in input buffering"); - } + ArrayUtil.blockSizeCheck(plainLen, numBytes); + ArrayUtil.nullAndBoundsCheck(plain, plainOffset, plainLen); + ArrayUtil.nullAndBoundsCheck(cipher, cipherOffset, plainLen); int nShift = blockSize - numBytes; int loopCount = plainLen / numBytes; @@ -225,9 +226,10 @@ final class CipherFeedback extends FeedbackCipher { */ int decrypt(byte[] cipher, int cipherOffset, int cipherLen, byte[] plain, int plainOffset) { - if ((cipherLen % numBytes) != 0) { - throw new ProviderException("Internal error in input buffering"); - } + + ArrayUtil.blockSizeCheck(cipherLen, numBytes); + ArrayUtil.nullAndBoundsCheck(cipher, cipherOffset, cipherLen); + ArrayUtil.nullAndBoundsCheck(plain, plainOffset, cipherLen); int nShift = blockSize - numBytes; int loopCount = cipherLen / numBytes; diff --git a/src/share/classes/com/sun/crypto/provider/CounterMode.java b/src/share/classes/com/sun/crypto/provider/CounterMode.java index b810b8ff8c7611701fcf8d6fea45779635c8d8e2..cda5db2cf8505053fdc9707101627c06f90cf8d5 100644 --- a/src/share/classes/com/sun/crypto/provider/CounterMode.java +++ b/src/share/classes/com/sun/crypto/provider/CounterMode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2018, 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 @@ -27,6 +27,7 @@ package com.sun.crypto.provider; import java.security.InvalidKeyException; +import sun.security.util.ArrayUtil; /** * This class represents ciphers in counter (CTR) mode. @@ -173,6 +174,10 @@ final class CounterMode extends FeedbackCipher { if (len == 0) { return 0; } + + ArrayUtil.nullAndBoundsCheck(in, inOff, len); + ArrayUtil.nullAndBoundsCheck(out, outOff, len); + int result = len; while (len-- > 0) { if (used >= blockSize) { diff --git a/src/share/classes/com/sun/crypto/provider/ElectronicCodeBook.java b/src/share/classes/com/sun/crypto/provider/ElectronicCodeBook.java index 334e4245e27a5522000c75b10ea06f1bb2c558b5..24e85adb9ba888ba5471a7a5ccc311f821e7d659 100644 --- a/src/share/classes/com/sun/crypto/provider/ElectronicCodeBook.java +++ b/src/share/classes/com/sun/crypto/provider/ElectronicCodeBook.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2018, 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 @@ -27,6 +27,7 @@ package com.sun.crypto.provider; import java.security.InvalidKeyException; import java.security.ProviderException; +import sun.security.util.ArrayUtil; /** * This class represents ciphers in electronic codebook (ECB) mode. @@ -112,9 +113,10 @@ final class ElectronicCodeBook extends FeedbackCipher { * @return the length of the encrypted data */ int encrypt(byte[] in, int inOff, int len, byte[] out, int outOff) { - if ((len % blockSize) != 0) { - throw new ProviderException("Internal error in input buffering"); - } + ArrayUtil.blockSizeCheck(len, blockSize); + ArrayUtil.nullAndBoundsCheck(in, inOff, len); + ArrayUtil.nullAndBoundsCheck(out, outOff, len); + for (int i = len; i >= blockSize; i -= blockSize) { embeddedCipher.encryptBlock(in, inOff, out, outOff); inOff += blockSize; @@ -141,9 +143,10 @@ final class ElectronicCodeBook extends FeedbackCipher { * @return the length of the decrypted data */ int decrypt(byte[] in, int inOff, int len, byte[] out, int outOff) { - if ((len % blockSize) != 0) { - throw new ProviderException("Internal error in input buffering"); - } + ArrayUtil.blockSizeCheck(len, blockSize); + ArrayUtil.nullAndBoundsCheck(in, inOff, len); + ArrayUtil.nullAndBoundsCheck(out, outOff, len); + for (int i = len; i >= blockSize; i -= blockSize) { embeddedCipher.decryptBlock(in, inOff, out, outOff); inOff += blockSize; diff --git a/src/share/classes/com/sun/crypto/provider/GaloisCounterMode.java b/src/share/classes/com/sun/crypto/provider/GaloisCounterMode.java index cdb22d1217919c632e1b427289382c6899163337..b574848704c44a8b972a56d9433054e16d346560 100644 --- a/src/share/classes/com/sun/crypto/provider/GaloisCounterMode.java +++ b/src/share/classes/com/sun/crypto/provider/GaloisCounterMode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2018, 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 @@ -30,6 +30,8 @@ import java.io.*; import java.security.*; import javax.crypto.*; import static com.sun.crypto.provider.AESConstants.AES_BLOCK_SIZE; +import sun.security.util.ArrayUtil; + /** * This class represents ciphers in GaloisCounter (GCM) mode. @@ -406,8 +408,8 @@ final class GaloisCounterMode extends FeedbackCipher { /** * Performs encryption operation. * - *

The input plain text in, starting at inOff - * and ending at (inOff + len - 1), is encrypted. The result + *

The input plain text in, starting at inOfs + * and ending at (inOfs + len - 1), is encrypted. The result * is stored in out, starting at outOfs. * * @param in the buffer with the input data to be encrypted @@ -422,15 +424,18 @@ final class GaloisCounterMode extends FeedbackCipher { int encrypt(byte[] in, int inOfs, int len, byte[] out, int outOfs) { checkDataLength(processed, len); - if ((len % blockSize) != 0) { - throw new ProviderException("Internal error in input buffering"); - } + ArrayUtil.blockSizeCheck(len, blockSize); processAAD(); + if (len > 0) { + ArrayUtil.nullAndBoundsCheck(in, inOfs, len); + ArrayUtil.nullAndBoundsCheck(out, outOfs, len); + gctrPAndC.update(in, inOfs, len, out, outOfs); processed += len; ghashAllToS.update(out, outOfs, len); } + return len; } @@ -450,7 +455,10 @@ final class GaloisCounterMode extends FeedbackCipher { throw new ShortBufferException ("Can't fit both data and tag into one buffer"); } - if (out.length - outOfs < (len + tagLenBytes)) { + try { + ArrayUtil.nullAndBoundsCheck(out, outOfs, + (len + tagLenBytes)); + } catch (ArrayIndexOutOfBoundsException aiobe) { throw new ShortBufferException("Output buffer too small"); } @@ -458,6 +466,8 @@ final class GaloisCounterMode extends FeedbackCipher { processAAD(); if (len > 0) { + ArrayUtil.nullAndBoundsCheck(in, inOfs, len); + doLastBlock(in, inOfs, len, out, outOfs, true); } @@ -493,15 +503,14 @@ final class GaloisCounterMode extends FeedbackCipher { int decrypt(byte[] in, int inOfs, int len, byte[] out, int outOfs) { checkDataLength(ibuffer.size(), len); - if ((len % blockSize) != 0) { - throw new ProviderException("Internal error in input buffering"); - } + ArrayUtil.blockSizeCheck(len, blockSize); processAAD(); if (len > 0) { // store internally until decryptFinal is called because // spec mentioned that only return recovered data after tag // is successfully verified + ArrayUtil.nullAndBoundsCheck(in, inOfs, len); ibuffer.write(in, inOfs, len); } return 0; @@ -530,22 +539,28 @@ final class GaloisCounterMode extends FeedbackCipher { if (len < tagLenBytes) { throw new AEADBadTagException("Input too short - need tag"); } + // do this check here can also catch the potential integer overflow // scenario for the subsequent output buffer capacity check. checkDataLength(ibuffer.size(), (len - tagLenBytes)); - if (out.length - outOfs < ((ibuffer.size() + len) - tagLenBytes)) { + try { + ArrayUtil.nullAndBoundsCheck(out, outOfs, + (ibuffer.size() + len) - tagLenBytes); + } catch (ArrayIndexOutOfBoundsException aiobe) { throw new ShortBufferException("Output buffer too small"); } processAAD(); + ArrayUtil.nullAndBoundsCheck(in, inOfs, len); + // get the trailing tag bytes from 'in' byte[] tag = new byte[tagLenBytes]; System.arraycopy(in, inOfs + len - tagLenBytes, tag, 0, tagLenBytes); len -= tagLenBytes; - if (len != 0) { + if (len > 0) { ibuffer.write(in, inOfs, len); } diff --git a/src/share/classes/com/sun/crypto/provider/OutputFeedback.java b/src/share/classes/com/sun/crypto/provider/OutputFeedback.java index 47d9d63c93df6efbfa5a9e69a506193a5f210de4..7b518836cd1cfe0c37705acf347218a8a8e3cf89 100644 --- a/src/share/classes/com/sun/crypto/provider/OutputFeedback.java +++ b/src/share/classes/com/sun/crypto/provider/OutputFeedback.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2018, 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 @@ -27,6 +27,7 @@ package com.sun.crypto.provider; import java.security.InvalidKeyException; import java.security.ProviderException; +import sun.security.util.ArrayUtil; /** * This class represents ciphers in output-feedback (OFB) mode. @@ -148,10 +149,10 @@ final class OutputFeedback extends FeedbackCipher { */ int encrypt(byte[] plain, int plainOffset, int plainLen, byte[] cipher, int cipherOffset) { + ArrayUtil.blockSizeCheck(plainLen, numBytes); + ArrayUtil.nullAndBoundsCheck(plain, plainOffset, plainLen); + ArrayUtil.nullAndBoundsCheck(cipher, cipherOffset, plainLen); - if ((plainLen % numBytes) != 0) { - throw new ProviderException("Internal error in input buffering"); - } int nShift = blockSize - numBytes; int loopCount = plainLen / numBytes; @@ -189,6 +190,9 @@ final class OutputFeedback extends FeedbackCipher { */ int encryptFinal(byte[] plain, int plainOffset, int plainLen, byte[] cipher, int cipherOffset) { + ArrayUtil.nullAndBoundsCheck(plain, plainOffset, plainLen); + ArrayUtil.nullAndBoundsCheck(cipher, cipherOffset, plainLen); + int oddBytes = plainLen % numBytes; int len = encrypt(plain, plainOffset, (plainLen - oddBytes), cipher, cipherOffset); diff --git a/src/share/classes/com/sun/crypto/provider/PCBC.java b/src/share/classes/com/sun/crypto/provider/PCBC.java index fd99bb0cbd51208bc0c9d152df59d0e8fa59beaf..544776ec04fe07d25602708370297221bcbecec5 100644 --- a/src/share/classes/com/sun/crypto/provider/PCBC.java +++ b/src/share/classes/com/sun/crypto/provider/PCBC.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2018, 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 @@ -27,6 +27,7 @@ package com.sun.crypto.provider; import java.security.InvalidKeyException; import java.security.ProviderException; +import sun.security.util.ArrayUtil; /** @@ -136,9 +137,10 @@ final class PCBC extends FeedbackCipher { int encrypt(byte[] plain, int plainOffset, int plainLen, byte[] cipher, int cipherOffset) { - if ((plainLen % blockSize) != 0) { - throw new ProviderException("Internal error in input buffering"); - } + ArrayUtil.blockSizeCheck(plainLen, blockSize); + ArrayUtil.nullAndBoundsCheck(plain, plainOffset, plainLen); + ArrayUtil.nullAndBoundsCheck(cipher, cipherOffset, plainLen); + int i; int endIndex = plainOffset + plainLen; @@ -176,9 +178,10 @@ final class PCBC extends FeedbackCipher { int decrypt(byte[] cipher, int cipherOffset, int cipherLen, byte[] plain, int plainOffset) { - if ((cipherLen % blockSize) != 0) { - throw new ProviderException("Internal error in input buffering"); - } + ArrayUtil.blockSizeCheck(cipherLen, blockSize); + ArrayUtil.nullAndBoundsCheck(cipher, cipherOffset, cipherLen); + ArrayUtil.nullAndBoundsCheck(plain, plainOffset, cipherLen); + int i; int endIndex = cipherOffset + cipherLen; diff --git a/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java b/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java index 5c93d89e0e7f9b89510a2b0298e2e9b0bfb73978..8f58f5b3e6d5c4c66331996251ace1e5d8d00929 100644 --- a/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java +++ b/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2018, 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 @@ -374,7 +374,10 @@ public class JPEGImageReader extends ImageReader { // And set current image since we've read it now currentImage = 0; } - if (seekForwardOnly) { + // If the image positions list is empty as in the case of a tables-only + // stream, then attempting to access the element at index + // imagePositions.size() - 1 will cause an IndexOutOfBoundsException. + if (seekForwardOnly && !imagePositions.isEmpty()) { Long pos = (Long) imagePositions.get(imagePositions.size()-1); iis.flushBefore(pos.longValue()); } @@ -491,6 +494,11 @@ public class JPEGImageReader extends ImageReader { if (!tablesOnlyChecked) { checkTablesOnly(); } + // If the image positions list is empty as in the case of a tables-only + // stream, then no image data can be read. + if (imagePositions.isEmpty()) { + throw new IIOException("No image data present to read"); + } if (imageIndex < imagePositions.size()) { iis.seek(((Long)(imagePositions.get(imageIndex))).longValue()); } else { diff --git a/src/share/classes/java/lang/Throwable.java b/src/share/classes/java/lang/Throwable.java index 4b9e2ad0415a7031ff48d98effc6d406730d9d85..34440fa2c5c400dcc0313e4e1ae8bd05c955cc43 100644 --- a/src/share/classes/java/lang/Throwable.java +++ b/src/share/classes/java/lang/Throwable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2019, 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 @@ -24,8 +24,9 @@ */ package java.lang; -import java.io.*; -import java.util.*; + +import java.io.*; +import java.util.*; /** * The {@code Throwable} class is the superclass of all errors and @@ -912,25 +913,37 @@ public class Throwable implements Serializable { private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { s.defaultReadObject(); // read in all fields - if (suppressedExceptions != null) { - List suppressed = null; - if (suppressedExceptions.isEmpty()) { - // Use the sentinel for a zero-length list - suppressed = SUPPRESSED_SENTINEL; - } else { // Copy Throwables to new list - suppressed = new ArrayList<>(1); - for (Throwable t : suppressedExceptions) { + + // Set suppressed exceptions and stack trace elements fields + // to marker values until the contents from the serial stream + // are validated. + List candidateSuppressedExceptions = suppressedExceptions; + suppressedExceptions = SUPPRESSED_SENTINEL; + + StackTraceElement[] candidateStackTrace = stackTrace; + stackTrace = UNASSIGNED_STACK.clone(); + + if (candidateSuppressedExceptions != null) { + int suppressedSize = validateSuppressedExceptionsList(candidateSuppressedExceptions); + if (suppressedSize > 0) { // Copy valid Throwables to new list + List suppList = new ArrayList(Math.min(100, suppressedSize)); + + for (Throwable t : candidateSuppressedExceptions) { // Enforce constraints on suppressed exceptions in // case of corrupt or malicious stream. if (t == null) throw new NullPointerException(NULL_CAUSE_MESSAGE); if (t == this) throw new IllegalArgumentException(SELF_SUPPRESSION_MESSAGE); - suppressed.add(t); + suppList.add(t); } + // If there are any invalid suppressed exceptions, + // implicitly use the sentinel value assigned earlier. + suppressedExceptions = suppList; } - suppressedExceptions = suppressed; - } // else a null suppressedExceptions field remains null + } else { + suppressedExceptions = null; + } /* * For zero-length stack traces, use a clone of @@ -941,25 +954,41 @@ public class Throwable implements Serializable { * the stackTrace needs to be constructed from the information * in backtrace. */ - if (stackTrace != null) { - if (stackTrace.length == 0) { - stackTrace = UNASSIGNED_STACK.clone(); - } else if (stackTrace.length == 1 && + if (candidateStackTrace != null) { + // Work from a clone of the candidateStackTrace to ensure + // consistency of checks. + candidateStackTrace = candidateStackTrace.clone(); + if (candidateStackTrace.length >= 1) { + if (candidateStackTrace.length == 1 && // Check for the marker of an immutable stack trace - SentinelHolder.STACK_TRACE_ELEMENT_SENTINEL.equals(stackTrace[0])) { - stackTrace = null; - } else { // Verify stack trace elements are non-null. - for(StackTraceElement ste : stackTrace) { - if (ste == null) - throw new NullPointerException("null StackTraceElement in serial stream. "); + SentinelHolder.STACK_TRACE_ELEMENT_SENTINEL.equals(candidateStackTrace[0])) { + stackTrace = null; + } else { // Verify stack trace elements are non-null. + for (StackTraceElement ste : candidateStackTrace) { + if (ste == null) + throw new NullPointerException("null StackTraceElement in serial stream."); + } + stackTrace = candidateStackTrace; } } + } + // A null stackTrace field in the serial form can result from + // an exception serialized without that field in older JDK + // releases; treat such exceptions as having empty stack + // traces by leaving stackTrace assigned to a clone of + // UNASSIGNED_STACK. + } + + private int validateSuppressedExceptionsList(List deserSuppressedExceptions) + throws IOException { + if (Object.class.getClassLoader() != deserSuppressedExceptions.getClass().getClassLoader()) { + throw new StreamCorruptedException("List implementation not on the bootclasspath."); } else { - // A null stackTrace field in the serial form can result - // from an exception serialized without that field in - // older JDK releases; treat such exceptions as having - // empty stack traces. - stackTrace = UNASSIGNED_STACK.clone(); + int size = deserSuppressedExceptions.size(); + if (size < 0) { + throw new StreamCorruptedException("Negative list size reported."); + } + return size; } } diff --git a/src/share/classes/java/net/URL.java b/src/share/classes/java/net/URL.java index 919825adbb62c0067d259a36ca12359e133e97f2..be6c294d191588c49e493d8ecce2f678b36b38e2 100644 --- a/src/share/classes/java/net/URL.java +++ b/src/share/classes/java/net/URL.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2019, 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.ObjectStreamField; import java.io.ObjectInputStream.GetField; import java.util.Hashtable; import java.util.StringTokenizer; +import sun.net.util.IPAddressUtil; import sun.security.util.SecurityConstants; /** @@ -414,13 +415,19 @@ public final class URL implements java.io.Serializable { } ref = parts.getRef(); - // Note: we don't do validation of the URL here. Too risky to change + // Note: we don't do full validation of the URL here. Too risky to change // right now, but worth considering for future reference. -br if (handler == null && (handler = getURLStreamHandler(protocol)) == null) { throw new MalformedURLException("unknown protocol: " + protocol); } this.handler = handler; + if (host != null && isBuiltinStreamHandler(handler)) { + String s = IPAddressUtil.checkExternalForm(this); + if (s != null) { + throw new MalformedURLException(s); + } + } } /** @@ -943,7 +950,12 @@ public final class URL implements java.io.Serializable { * @since 1.5 */ public URI toURI() throws URISyntaxException { - return new URI (toString()); + URI uri = new URI(toString()); + if (authority != null && isBuiltinStreamHandler(handler)) { + String s = IPAddressUtil.checkAuthority(this); + if (s != null) throw new URISyntaxException(authority, s); + } + return uri; } /** @@ -1400,6 +1412,10 @@ public final class URL implements java.io.Serializable { return replacementURL; } + boolean isBuiltinStreamHandler(URLStreamHandler handler) { + return isBuiltinStreamHandler(handler.getClass().getName()); + } + private boolean isBuiltinStreamHandler(String handlerClassName) { return (handlerClassName.startsWith(BUILTIN_HANDLERS_PREFIX)); } diff --git a/src/share/classes/java/net/URLStreamHandler.java b/src/share/classes/java/net/URLStreamHandler.java index 513055982c76df9f6efc89a8e3b85dd1a7a29784..cbdf02a5eea6c72ba7df0fd764e63d98efad7d80 100644 --- a/src/share/classes/java/net/URLStreamHandler.java +++ b/src/share/classes/java/net/URLStreamHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2019, 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 @@ -532,12 +532,15 @@ public abstract class URLStreamHandler { * @see java.net.URL#set(java.lang.String, java.lang.String, int, java.lang.String, java.lang.String) * @since 1.3 */ - protected void setURL(URL u, String protocol, String host, int port, + protected void setURL(URL u, String protocol, String host, int port, String authority, String userInfo, String path, String query, String ref) { if (this != u.handler) { throw new SecurityException("handler for url different from " + "this handler"); + } else if (host != null && u.isBuiltinStreamHandler(this)) { + String s = IPAddressUtil.checkHostString(host); + if (s != null) throw new IllegalArgumentException(s); } // ensure that no one can reset the protocol on a given URL. u.set(u.getProtocol(), host, port, authority, userInfo, path, query, ref); diff --git a/src/share/classes/java/security/AccessController.java b/src/share/classes/java/security/AccessController.java index 36408a8d633d5a21afc495e921785dcfc261bbbe..00e084ca96b8821a6e4cf6bccf6cd1672dd89150 100644 --- a/src/share/classes/java/security/AccessController.java +++ b/src/share/classes/java/security/AccessController.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2019, 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 @@ -425,7 +425,8 @@ public final class AccessController { throw new NullPointerException("null permissions parameter"); } Class caller = Reflection.getCallerClass(); - return AccessController.doPrivileged(action, createWrapper(null, + DomainCombiner dc = (context == null) ? null : context.getCombiner(); + return AccessController.doPrivileged(action, createWrapper(dc, caller, parent, context, perms)); } @@ -710,7 +711,8 @@ public final class AccessController { throw new NullPointerException("null permissions parameter"); } Class caller = Reflection.getCallerClass(); - return AccessController.doPrivileged(action, createWrapper(null, caller, parent, context, perms)); + DomainCombiner dc = (context == null) ? null : context.getCombiner(); + return AccessController.doPrivileged(action, createWrapper(dc, caller, parent, context, perms)); } diff --git a/src/share/classes/java/util/Collections.java b/src/share/classes/java/util/Collections.java index 4dbdf8a5b41ada6c508fa5f291c1ddc5cdd57cee..79159eaa1106df60729e76d2c8ed099146360db5 100644 --- a/src/share/classes/java/util/Collections.java +++ b/src/share/classes/java/util/Collections.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2019, 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 @@ -25,6 +25,7 @@ package java.util; import java.io.Serializable; +import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.IOException; import java.lang.reflect.Array; @@ -37,6 +38,7 @@ import java.util.function.UnaryOperator; import java.util.stream.IntStream; import java.util.stream.Stream; import java.util.stream.StreamSupport; +import sun.misc.SharedSecrets; /** * This class consists exclusively of static methods that operate on or return @@ -5075,6 +5077,11 @@ public class Collections { public Spliterator spliterator() { return stream().spliterator(); } + + private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { + ois.defaultReadObject(); + SharedSecrets.getJavaOISAccess().checkArray(ois, Object[].class, n); + } } /** diff --git a/src/share/classes/jdk/internal/util/Preconditions.java b/src/share/classes/jdk/internal/util/Preconditions.java new file mode 100644 index 0000000000000000000000000000000000000000..5be620d28a27fb9e7b4506a57387904cfa636554 --- /dev/null +++ b/src/share/classes/jdk/internal/util/Preconditions.java @@ -0,0 +1,345 @@ +/* + * Copyright (c) 2016, 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 jdk.internal.util; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.function.BiFunction; +import java.util.function.Function; + +/** + * Utility methods to check if state or arguments are correct. + * + */ +public class Preconditions { + + /** + * Maps out-of-bounds values to a runtime exception. + * + * @param checkKind the kind of bounds check, whose name may correspond + * to the name of one of the range check methods, checkIndex, + * checkFromToIndex, checkFromIndexSize + * @param args the out-of-bounds arguments that failed the range check. + * If the checkKind corresponds a the name of a range check method + * then the bounds arguments are those that can be passed in order + * to the method. + * @param oobef the exception formatter that when applied with a checkKind + * and a list out-of-bounds arguments returns a runtime exception. + * If {@code null} then, it is as if an exception formatter was + * supplied that returns {@link IndexOutOfBoundsException} for any + * given arguments. + * @return the runtime exception + */ + private static RuntimeException outOfBounds( + BiFunction, ? extends RuntimeException> oobef, + String checkKind, + Integer... args) { + List largs = Collections.unmodifiableList(Arrays.asList(args)); + RuntimeException e = oobef == null + ? null : oobef.apply(checkKind, largs); + return e == null + ? new IndexOutOfBoundsException(outOfBoundsMessage(checkKind, largs)) : e; + } + + private static RuntimeException outOfBoundsCheckIndex( + BiFunction, ? extends RuntimeException> oobe, + int index, int length) { + return outOfBounds(oobe, "checkIndex", index, length); + } + + private static RuntimeException outOfBoundsCheckFromToIndex( + BiFunction, ? extends RuntimeException> oobe, + int fromIndex, int toIndex, int length) { + return outOfBounds(oobe, "checkFromToIndex", fromIndex, toIndex, length); + } + + private static RuntimeException outOfBoundsCheckFromIndexSize( + BiFunction, ? extends RuntimeException> oobe, + int fromIndex, int size, int length) { + return outOfBounds(oobe, "checkFromIndexSize", fromIndex, size, length); + } + + /** + * Returns an out-of-bounds exception formatter from an given exception + * factory. The exception formatter is a function that formats an + * out-of-bounds message from its arguments and applies that message to the + * given exception factory to produce and relay an exception. + * + *

The exception formatter accepts two arguments: a {@code String} + * describing the out-of-bounds range check that failed, referred to as the + * check kind; and a {@code List} containing the + * out-of-bound integer values that failed the check. The list of + * out-of-bound values is not modified. + * + *

Three check kinds are supported {@code checkIndex}, + * {@code checkFromToIndex} and {@code checkFromIndexSize} corresponding + * respectively to the specified application of an exception formatter as an + * argument to the out-of-bounds range check methods + * {@link #checkIndex(int, int, BiFunction) checkIndex}, + * {@link #checkFromToIndex(int, int, int, BiFunction) checkFromToIndex}, and + * {@link #checkFromIndexSize(int, int, int, BiFunction) checkFromIndexSize}. + * Thus a supported check kind corresponds to a method name and the + * out-of-bound integer values correspond to method argument values, in + * order, preceding the exception formatter argument (similar in many + * respects to the form of arguments required for a reflective invocation of + * such a range check method). + * + *

Formatter arguments conforming to such supported check kinds will + * produce specific exception messages describing failed out-of-bounds + * checks. Otherwise, more generic exception messages will be produced in + * any of the following cases: the check kind is supported but fewer + * or more out-of-bounds values are supplied, the check kind is not + * supported, the check kind is {@code null}, or the list of out-of-bound + * values is {@code null}. + * + * @apiNote + * This method produces an out-of-bounds exception formatter that can be + * passed as an argument to any of the supported out-of-bounds range check + * methods declared by {@code Objects}. For example, a formatter producing + * an {@code ArrayIndexOutOfBoundsException} may be produced and stored on a + * {@code static final} field as follows: + *

{@code
+     * static final
+     * BiFunction, ArrayIndexOutOfBoundsException> AIOOBEF =
+     *     outOfBoundsExceptionFormatter(ArrayIndexOutOfBoundsException::new);
+     * }
+ * The formatter instance {@code AIOOBEF} may be passed as an argument to an + * out-of-bounds range check method, such as checking if an {@code index} + * is within the bounds of a {@code limit}: + *
{@code
+     * checkIndex(index, limit, AIOOBEF);
+     * }
+ * If the bounds check fails then the range check method will throw an + * {@code ArrayIndexOutOfBoundsException} with an appropriate exception + * message that is a produced from {@code AIOOBEF} as follows: + *
{@code
+     * AIOOBEF.apply("checkIndex", List.of(index, limit));
+     * }
+ * + * @param f the exception factory, that produces an exception from a message + * where the message is produced and formatted by the returned + * exception formatter. If this factory is stateless and side-effect + * free then so is the returned formatter. + * Exceptions thrown by the factory are relayed to the caller + * of the returned formatter. + * @param the type of runtime exception to be returned by the given + * exception factory and relayed by the exception formatter + * @return the out-of-bounds exception formatter + */ + public static + BiFunction, X> outOfBoundsExceptionFormatter(Function f) { + // Use anonymous class to avoid bootstrap issues if this method is + // used early in startup + return new BiFunction, X>() { + @Override + public X apply(String checkKind, List args) { + return f.apply(outOfBoundsMessage(checkKind, args)); + } + }; + } + + private static String outOfBoundsMessage(String checkKind, List args) { + if (checkKind == null && args == null) { + return String.format("Range check failed"); + } else if (checkKind == null) { + return String.format("Range check failed: %s", args); + } else if (args == null) { + return String.format("Range check failed: %s", checkKind); + } + + int argSize = 0; + switch (checkKind) { + case "checkIndex": + argSize = 2; + break; + case "checkFromToIndex": + case "checkFromIndexSize": + argSize = 3; + break; + default: + } + + // Switch to default if fewer or more arguments than required are supplied + switch ((args.size() != argSize) ? "" : checkKind) { + case "checkIndex": + return String.format("Index %d out-of-bounds for length %d", + args.get(0), args.get(1)); + case "checkFromToIndex": + return String.format("Range [%d, %d) out-of-bounds for length %d", + args.get(0), args.get(1), args.get(2)); + case "checkFromIndexSize": + return String.format("Range [%d, %The {@code index} is defined to be out-of-bounds if any of the + * following inequalities is true: + *
    + *
  • {@code index < 0}
  • + *
  • {@code index >= length}
  • + *
  • {@code length < 0}, which is implied from the former inequalities
  • + *
+ * + *

If the {@code index} is out-of-bounds, then a runtime exception is + * thrown that is the result of applying the following arguments to the + * exception formatter: the name of this method, {@code checkIndex}; + * and an unmodifiable list integers whose values are, in order, the + * out-of-bounds arguments {@code index} and {@code length}. + * + * @param the type of runtime exception to throw if the arguments are + * out-of-bounds + * @param index the index + * @param length the upper-bound (exclusive) of the range + * @param oobef the exception formatter that when applied with this + * method name and out-of-bounds arguments returns a runtime + * exception. If {@code null} or returns {@code null} then, it is as + * if an exception formatter produced from an invocation of + * {@code outOfBoundsExceptionFormatter(IndexOutOfBounds::new)} is used + * instead (though it may be more efficient). + * Exceptions thrown by the formatter are relayed to the caller. + * @return {@code index} if it is within bounds of the range + * @throws X if the {@code index} is out-of-bounds and the exception + * formatter is non-{@code null} + * @throws IndexOutOfBoundsException if the {@code index} is out-of-bounds + * and the exception formatter is {@code null} + * @since 9 + * + * @implNote + * This method is made intrinsic in optimizing compilers to guide them to + * perform unsigned comparisons of the index and length when it is known the + * length is a non-negative value (such as that of an array length or from + * the upper bound of a loop) + */ + public static + int checkIndex(int index, int length, + BiFunction, X> oobef) { + if (index < 0 || index >= length) + throw outOfBoundsCheckIndex(oobef, index, length); + return index; + } + + /** + * Checks if the sub-range from {@code fromIndex} (inclusive) to + * {@code toIndex} (exclusive) is within the bounds of range from {@code 0} + * (inclusive) to {@code length} (exclusive). + * + *

The sub-range is defined to be out-of-bounds if any of the following + * inequalities is true: + *

    + *
  • {@code fromIndex < 0}
  • + *
  • {@code fromIndex > toIndex}
  • + *
  • {@code toIndex > length}
  • + *
  • {@code length < 0}, which is implied from the former inequalities
  • + *
+ * + *

If the sub-range is out-of-bounds, then a runtime exception is + * thrown that is the result of applying the following arguments to the + * exception formatter: the name of this method, {@code checkFromToIndex}; + * and an unmodifiable list integers whose values are, in order, the + * out-of-bounds arguments {@code fromIndex}, {@code toIndex}, and {@code length}. + * + * @param the type of runtime exception to throw if the arguments are + * out-of-bounds + * @param fromIndex the lower-bound (inclusive) of the sub-range + * @param toIndex the upper-bound (exclusive) of the sub-range + * @param length the upper-bound (exclusive) the range + * @param oobef the exception formatter that when applied with this + * method name and out-of-bounds arguments returns a runtime + * exception. If {@code null} or returns {@code null} then, it is as + * if an exception formatter produced from an invocation of + * {@code outOfBoundsExceptionFormatter(IndexOutOfBounds::new)} is used + * instead (though it may be more efficient). + * Exceptions thrown by the formatter are relayed to the caller. + * @return {@code fromIndex} if the sub-range within bounds of the range + * @throws X if the sub-range is out-of-bounds and the exception factory + * function is non-{@code null} + * @throws IndexOutOfBoundsException if the sub-range is out-of-bounds and + * the exception factory function is {@code null} + * @since 9 + */ + public static + int checkFromToIndex(int fromIndex, int toIndex, int length, + BiFunction, X> oobef) { + if (fromIndex < 0 || fromIndex > toIndex || toIndex > length) + throw outOfBoundsCheckFromToIndex(oobef, fromIndex, toIndex, length); + return fromIndex; + } + + /** + * Checks if the sub-range from {@code fromIndex} (inclusive) to + * {@code fromIndex + size} (exclusive) is within the bounds of range from + * {@code 0} (inclusive) to {@code length} (exclusive). + * + *

The sub-range is defined to be out-of-bounds if any of the following + * inequalities is true: + *

    + *
  • {@code fromIndex < 0}
  • + *
  • {@code size < 0}
  • + *
  • {@code fromIndex + size > length}, taking into account integer overflow
  • + *
  • {@code length < 0}, which is implied from the former inequalities
  • + *
+ * + *

If the sub-range is out-of-bounds, then a runtime exception is + * thrown that is the result of applying the following arguments to the + * exception formatter: the name of this method, {@code checkFromIndexSize}; + * and an unmodifiable list integers whose values are, in order, the + * out-of-bounds arguments {@code fromIndex}, {@code size}, and + * {@code length}. + * + * @param the type of runtime exception to throw if the arguments are + * out-of-bounds + * @param fromIndex the lower-bound (inclusive) of the sub-interval + * @param size the size of the sub-range + * @param length the upper-bound (exclusive) of the range + * @param oobef the exception formatter that when applied with this + * method name and out-of-bounds arguments returns a runtime + * exception. If {@code null} or returns {@code null} then, it is as + * if an exception formatter produced from an invocation of + * {@code outOfBoundsExceptionFormatter(IndexOutOfBounds::new)} is used + * instead (though it may be more efficient). + * Exceptions thrown by the formatter are relayed to the caller. + * @return {@code fromIndex} if the sub-range within bounds of the range + * @throws X if the sub-range is out-of-bounds and the exception factory + * function is non-{@code null} + * @throws IndexOutOfBoundsException if the sub-range is out-of-bounds and + * the exception factory function is {@code null} + * @since 9 + */ + public static + int checkFromIndexSize(int fromIndex, int size, int length, + BiFunction, X> oobef) { + if ((length | fromIndex | size) < 0 || size > length - fromIndex) + throw outOfBoundsCheckFromIndexSize(oobef, fromIndex, size, length); + return fromIndex; + } +} diff --git a/src/share/classes/sun/net/util/IPAddressUtil.java b/src/share/classes/sun/net/util/IPAddressUtil.java index 6aa98c8f8d9ff84fb2e598c4a16283cc1d359acb..2bcd2c0781ca04b6a342dad60d9be046309ae1dd 100644 --- a/src/share/classes/sun/net/util/IPAddressUtil.java +++ b/src/share/classes/sun/net/util/IPAddressUtil.java @@ -25,6 +25,9 @@ package sun.net.util; +import java.net.URL; +import java.util.Arrays; + public class IPAddressUtil { private final static int INADDR4SZ = 4; private final static int INADDR16SZ = 16; @@ -287,4 +290,182 @@ public class IPAddressUtil { } return false; } + + // See java.net.URI for more details on how to generate these + // masks. + // + // square brackets + private static final long L_IPV6_DELIMS = 0x0L; // "[]" + private static final long H_IPV6_DELIMS = 0x28000000L; // "[]" + // RFC 3986 gen-delims + private static final long L_GEN_DELIMS = 0x8400800800000000L; // ":/?#[]@" + private static final long H_GEN_DELIMS = 0x28000001L; // ":/?#[]@" + // These gen-delims can appear in authority + private static final long L_AUTH_DELIMS = 0x400000000000000L; // "@[]:" + private static final long H_AUTH_DELIMS = 0x28000001L; // "@[]:" + // colon is allowed in userinfo + private static final long L_COLON = 0x400000000000000L; // ":" + private static final long H_COLON = 0x0L; // ":" + // slash should be encoded in authority + private static final long L_SLASH = 0x800000000000L; // "/" + private static final long H_SLASH = 0x0L; // "/" + // backslash should always be encoded + private static final long L_BACKSLASH = 0x0L; // "\" + private static final long H_BACKSLASH = 0x10000000L; // "\" + // ASCII chars 0-31 + 127 - various controls + CRLF + TAB + private static final long L_NON_PRINTABLE = 0xffffffffL; + private static final long H_NON_PRINTABLE = 0x8000000000000000L; + // All of the above + private static final long L_EXCLUDE = 0x84008008ffffffffL; + private static final long H_EXCLUDE = 0x8000000038000001L; + + private static final char[] OTHERS = { + 8263,8264,8265,8448,8449,8453,8454,10868, + 65109,65110,65119,65131,65283,65295,65306,65311,65312 + }; + + // Tell whether the given character is found by the given mask pair + public static boolean match(char c, long lowMask, long highMask) { + if (c < 64) + return ((1L << c) & lowMask) != 0; + if (c < 128) + return ((1L << (c - 64)) & highMask) != 0; + return false; // other non ASCII characters are not filtered + } + + // returns -1 if the string doesn't contain any characters + // from the mask, the index of the first such character found + // otherwise. + public static int scan(String s, long lowMask, long highMask) { + int i = -1, len; + if (s == null || (len = s.length()) == 0) return -1; + boolean match = false; + while (++i < len && !(match = match(s.charAt(i), lowMask, highMask))); + if (match) return i; + return -1; + } + + public static int scan(String s, long lowMask, long highMask, char[] others) { + int i = -1, len; + if (s == null || (len = s.length()) == 0) return -1; + boolean match = false; + char c, c0 = others[0]; + while (++i < len && !(match = match((c=s.charAt(i)), lowMask, highMask))) { + if (c >= c0 && (Arrays.binarySearch(others, c) > -1)) { + match = true; break; + } + } + if (match) return i; + + return -1; + } + + private static String describeChar(char c) { + if (c < 32 || c == 127) { + if (c == '\n') return "LF"; + if (c == '\r') return "CR"; + return "control char (code=" + (int)c + ")"; + } + if (c == '\\') return "'\\'"; + return "'" + c + "'"; + } + + private static String checkUserInfo(String str) { + // colon is permitted in user info + int index = scan(str, L_EXCLUDE & ~L_COLON, + H_EXCLUDE & ~H_COLON); + if (index >= 0) { + return "Illegal character found in user-info: " + + describeChar(str.charAt(index)); + } + return null; + } + + private static String checkHost(String str) { + int index; + if (str.startsWith("[") && str.endsWith("]")) { + str = str.substring(1, str.length() - 1); + if (isIPv6LiteralAddress(str)) { + index = str.indexOf('%'); + if (index >= 0) { + index = scan(str = str.substring(index), + L_NON_PRINTABLE | L_IPV6_DELIMS, + H_NON_PRINTABLE | H_IPV6_DELIMS); + if (index >= 0) { + return "Illegal character found in IPv6 scoped address: " + + describeChar(str.charAt(index)); + } + } + return null; + } + return "Unrecognized IPv6 address format"; + } else { + index = scan(str, L_EXCLUDE, H_EXCLUDE); + if (index >= 0) { + return "Illegal character found in host: " + + describeChar(str.charAt(index)); + } + } + return null; + } + + private static String checkAuth(String str) { + int index = scan(str, + L_EXCLUDE & ~L_AUTH_DELIMS, + H_EXCLUDE & ~H_AUTH_DELIMS); + if (index >= 0) { + return "Illegal character found in authority: " + + describeChar(str.charAt(index)); + } + return null; + } + + // check authority of hierarchical URL. Appropriate for + // HTTP-like protocol handlers + public static String checkAuthority(URL url) { + String s, u, h; + if (url == null) return null; + if ((s = checkUserInfo(u = url.getUserInfo())) != null) { + return s; + } + if ((s = checkHost(h = url.getHost())) != null) { + return s; + } + if (h == null && u == null) { + return checkAuth(url.getAuthority()); + } + return null; + } + + // minimal syntax checks - deeper check may be performed + // by the appropriate protocol handler + public static String checkExternalForm(URL url) { + String s; + if (url == null) return null; + int index = scan(s = url.getUserInfo(), + L_NON_PRINTABLE | L_SLASH, + H_NON_PRINTABLE | H_SLASH); + if (index >= 0) { + return "Illegal character found in authority: " + + describeChar(s.charAt(index)); + } + if ((s = checkHostString(url.getHost())) != null) { + return s; + } + return null; + } + + public static String checkHostString(String host) { + if (host == null) return null; + int index = scan(host, + L_NON_PRINTABLE | L_SLASH, + H_NON_PRINTABLE | H_SLASH, + OTHERS); + if (index >= 0) { + return "Illegal character found in host: " + + describeChar(host.charAt(index)); + } + return null; + } + } diff --git a/src/share/classes/sun/net/www/protocol/ftp/FtpURLConnection.java b/src/share/classes/sun/net/www/protocol/ftp/FtpURLConnection.java index e560abf9c287b7db69251ac6caf186a15ac075f3..582687ba46b6bf614da7498f917966e2af6b3fe6 100644 --- a/src/share/classes/sun/net/www/protocol/ftp/FtpURLConnection.java +++ b/src/share/classes/sun/net/www/protocol/ftp/FtpURLConnection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2019, 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 @@ -36,6 +36,7 @@ import java.io.BufferedInputStream; import java.io.FilterInputStream; import java.io.FilterOutputStream; import java.io.FileNotFoundException; +import java.net.MalformedURLException; import java.net.URL; import java.net.SocketPermission; import java.net.UnknownHostException; @@ -47,6 +48,7 @@ import java.util.StringTokenizer; import java.util.Iterator; import java.security.Permission; import sun.net.NetworkClient; +import sun.net.util.IPAddressUtil; import sun.net.www.MessageHeader; import sun.net.www.MeteredStream; import sun.net.www.URLConnection; @@ -155,6 +157,21 @@ public class FtpURLConnection extends URLConnection { } } + static URL checkURL(URL u) throws IllegalArgumentException { + if (u != null) { + if (u.toExternalForm().indexOf('\n') > -1) { + Exception mfue = new MalformedURLException("Illegal character in URL"); + throw new IllegalArgumentException(mfue.getMessage(), mfue); + } + } + String s = IPAddressUtil.checkAuthority(u); + if (s != null) { + Exception mfue = new MalformedURLException(s); + throw new IllegalArgumentException(mfue.getMessage(), mfue); + } + return u; + } + /** * Creates an FtpURLConnection from a URL. * @@ -168,7 +185,7 @@ public class FtpURLConnection extends URLConnection { * Same as FtpURLconnection(URL) with a per connection proxy specified */ FtpURLConnection(URL url, Proxy p) { - super(url); + super(checkURL(url)); instProxy = p; host = url.getHost(); port = url.getPort(); diff --git a/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java b/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java index 4c5ec78fca25ec82bf0b93d2e8bcb7a86897e666..6adc9f65b7fd41ecc807a395f5be1707bdbeb028 100644 --- a/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java +++ b/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2019, 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 @@ -66,6 +66,7 @@ import java.util.HashSet; import java.util.HashMap; import java.util.Set; import sun.net.*; +import sun.net.util.IPAddressUtil; import sun.net.www.*; import sun.net.www.http.HttpClient; import sun.net.www.http.PosterOutputStream; @@ -850,8 +851,13 @@ public class HttpURLConnection extends java.net.HttpURLConnection { throw new MalformedURLException("Illegal character in URL"); } } + String s = IPAddressUtil.checkAuthority(u); + if (s != null) { + throw new MalformedURLException(s); + } return u; } + protected HttpURLConnection(URL u, Proxy p, Handler handler) throws IOException { super(checkURL(u)); diff --git a/src/share/classes/sun/net/www/protocol/https/HttpsURLConnectionImpl.java b/src/share/classes/sun/net/www/protocol/https/HttpsURLConnectionImpl.java index e43a36310ab1d2f48349a1090d0f8210ee2bca80..0186e2472573607a6678d3b9a23443170357ec9b 100644 --- a/src/share/classes/sun/net/www/protocol/https/HttpsURLConnectionImpl.java +++ b/src/share/classes/sun/net/www/protocol/https/HttpsURLConnectionImpl.java @@ -45,6 +45,7 @@ import java.security.Permission; import java.security.Principal; import java.util.Map; import java.util.List; +import sun.net.util.IPAddressUtil; import sun.net.www.http.HttpClient; /** @@ -86,6 +87,10 @@ public class HttpsURLConnectionImpl throw new MalformedURLException("Illegal character in URL"); } } + String s = IPAddressUtil.checkAuthority(u); + if (s != null) { + throw new MalformedURLException(s); + } return u; } // For both copies of the file, uncomment one line and comment the other @@ -333,7 +338,7 @@ public class HttpsURLConnectionImpl * @param key the keyword by which the request is known * (e.g., "accept"). * @param value the value associated with it. - * @see #getRequestProperties(java.lang.String) + * @see #getRequestProperty(java.lang.String) * @since 1.4 */ public void addRequestProperty(String key, String value) { diff --git a/src/share/classes/sun/security/provider/DigestBase.java b/src/share/classes/sun/security/provider/DigestBase.java index c3ac4ac36f59ac016d3071557cf7f0de05719343..89b1d77f31bf5dab9d876b5b6b99500f1c4e6459 100644 --- a/src/share/classes/sun/security/provider/DigestBase.java +++ b/src/share/classes/sun/security/provider/DigestBase.java @@ -29,6 +29,7 @@ import java.security.MessageDigestSpi; import java.security.DigestException; import java.security.ProviderException; import java.util.Arrays; +import java.util.Objects; /** * Common base message digest implementation for the Sun provider. @@ -137,12 +138,35 @@ abstract class DigestBase extends MessageDigestSpi implements Cloneable { // compress complete blocks private int implCompressMultiBlock(byte[] b, int ofs, int limit) { + implCompressMultiBlockCheck(b, ofs, limit); + return implCompressMultiBlock0(b, ofs, limit); + } + + private int implCompressMultiBlock0(byte[] b, int ofs, int limit) { for (; ofs <= limit; ofs += blockSize) { implCompress(b, ofs); } return ofs; } + private void implCompressMultiBlockCheck(byte[] b, int ofs, int limit) { + if (limit < 0) { + return; // not an error because implCompressMultiBlockImpl won't execute if limit < 0 + // and an exception is thrown if ofs < 0. + } + + Objects.requireNonNull(b); + + if (ofs < 0 || ofs >= b.length) { + throw new ArrayIndexOutOfBoundsException(ofs); + } + + int endIndex = (limit / blockSize) * blockSize + blockSize - 1; + if (endIndex >= b.length) { + throw new ArrayIndexOutOfBoundsException(endIndex); + } + } + // reset this object. See JCA doc. protected final void engineReset() { if (bytesProcessed == 0) { diff --git a/src/share/classes/sun/security/provider/SHA.java b/src/share/classes/sun/security/provider/SHA.java index 24dc0b2897f60ef79cd4bd9ecc3aa142a0b450fc..dfa477adf2d7afd8af6829f84672eebe5996e268 100644 --- a/src/share/classes/sun/security/provider/SHA.java +++ b/src/share/classes/sun/security/provider/SHA.java @@ -27,6 +27,8 @@ package sun.security.provider; import java.util.Arrays; +import java.util.Objects; + import static sun.security.provider.ByteArrayAccess.*; /** @@ -123,8 +125,26 @@ public final class SHA extends DigestBase { * "old" NIST Secure Hash Algorithm. */ void implCompress(byte[] buf, int ofs) { + implCompressCheck(buf, ofs); + implCompress0(buf, ofs); + } + + private void implCompressCheck(byte[] buf, int ofs) { + Objects.requireNonNull(buf); + + // The checks performed by the method 'b2iBig64' + // are sufficient for the case when the method + // 'implCompressImpl' is replaced with a compiler + // intrinsic. b2iBig64(buf, ofs, W); + } + // The method 'implCompressImpl seems not to use its parameters. + // The method can, however, be replaced with a compiler intrinsic + // that operates directly on the array 'buf' (starting from + // offset 'ofs') and not on array 'W', therefore 'buf' and 'ofs' + // must be passed as parameter to the method. + private void implCompress0(byte[] buf, int ofs) { // The first 16 ints have the byte stream, compute the rest of // the buffer for (int t = 16; t <= 79; t++) { diff --git a/src/share/classes/sun/security/provider/SHA2.java b/src/share/classes/sun/security/provider/SHA2.java index 6f34c8d55dfc09b0dab5fc0e58afa1a8c9e40d8e..25f13d0736477f42dfbeba755e3e902f30d91af4 100644 --- a/src/share/classes/sun/security/provider/SHA2.java +++ b/src/share/classes/sun/security/provider/SHA2.java @@ -27,6 +27,8 @@ package sun.security.provider; import java.util.Arrays; +import java.util.Objects; + import static sun.security.provider.ByteArrayAccess.*; /** @@ -193,8 +195,26 @@ abstract class SHA2 extends DigestBase { * Process the current block to update the state variable state. */ void implCompress(byte[] buf, int ofs) { + implCompressCheck(buf, ofs); + implCompress0(buf, ofs); + } + + private void implCompressCheck(byte[] buf, int ofs) { + Objects.requireNonNull(buf); + + // The checks performed by the method 'b2iBig64' + // are sufficient for the case when the method + // 'implCompressImpl' is replaced with a compiler + // intrinsic. b2iBig64(buf, ofs, W); + } + // The method 'implCompressImpl' seems not to use its parameters. + // The method can, however, be replaced with a compiler intrinsic + // that operates directly on the array 'buf' (starting from + // offset 'ofs') and not on array 'W', therefore 'buf' and 'ofs' + // must be passed as parameter to the method. + private void implCompress0(byte[] buf, int ofs) { // The first 16 ints are from the byte stream, compute the rest of // the W[]'s for (int t = 16; t < ITERATION; t++) { diff --git a/src/share/classes/sun/security/provider/SHA5.java b/src/share/classes/sun/security/provider/SHA5.java index 90c12526d8e34fa61fe51125303cef043a56030e..ceba1fc2b2dd6b1b0c1ae8a71745b8c2cd4e0dc2 100644 --- a/src/share/classes/sun/security/provider/SHA5.java +++ b/src/share/classes/sun/security/provider/SHA5.java @@ -26,6 +26,7 @@ package sun.security.provider; import java.util.Arrays; +import java.util.Objects; import static sun.security.provider.ByteArrayAccess.*; @@ -209,8 +210,26 @@ abstract class SHA5 extends DigestBase { * "old" NIST Secure Hash Algorithm. */ final void implCompress(byte[] buf, int ofs) { + implCompressCheck(buf, ofs); + implCompress0(buf, ofs); + } + + private void implCompressCheck(byte[] buf, int ofs) { + Objects.requireNonNull(buf); + + // The checks performed by the method 'b2iBig128' + // are sufficient for the case when the method + // 'implCompressImpl' is replaced with a compiler + // intrinsic. b2lBig128(buf, ofs, W); + } + // The method 'implCompressImpl' seems not to use its parameters. + // The method can, however, be replaced with a compiler intrinsic + // that operates directly on the array 'buf' (starting from + // offset 'ofs') and not on array 'W', therefore 'buf' and 'ofs' + // must be passed as parameter to the method. + private final void implCompress0(byte[] buf, int ofs) { // The first 16 longs are from the byte stream, compute the rest of // the W[]'s for (int t = 16; t < ITERATION; t++) { diff --git a/src/share/classes/sun/security/ssl/SSLContextImpl.java b/src/share/classes/sun/security/ssl/SSLContextImpl.java index 9659d258b1c5ea1960994782f256555d719f983d..4753b02fffa18ba5ad42c28323b2164d893d752b 100644 --- a/src/share/classes/sun/security/ssl/SSLContextImpl.java +++ b/src/share/classes/sun/security/ssl/SSLContextImpl.java @@ -1114,8 +1114,9 @@ final class AbstractTrustManagerWrapper extends X509ExtendedTrustManager checkAdditionalTrust(chain, authType, engine, false); } - private void checkAdditionalTrust(X509Certificate[] chain, String authType, - Socket socket, boolean isClient) throws CertificateException { + private void checkAdditionalTrust(X509Certificate[] chain, + String authType, Socket socket, + boolean checkClientTrusted) throws CertificateException { if (socket != null && socket.isConnected() && socket instanceof SSLSocket) { @@ -1129,9 +1130,8 @@ final class AbstractTrustManagerWrapper extends X509ExtendedTrustManager String identityAlg = sslSocket.getSSLParameters(). getEndpointIdentificationAlgorithm(); if (identityAlg != null && identityAlg.length() != 0) { - String hostname = session.getPeerHost(); - X509TrustManagerImpl.checkIdentity( - hostname, chain[0], identityAlg); + X509TrustManagerImpl.checkIdentity(session, chain, + identityAlg, checkClientTrusted); } // try the best to check the algorithm constraints @@ -1155,12 +1155,13 @@ final class AbstractTrustManagerWrapper extends X509ExtendedTrustManager constraints = new SSLAlgorithmConstraints(sslSocket, true); } - checkAlgorithmConstraints(chain, constraints, isClient); + checkAlgorithmConstraints(chain, constraints, checkClientTrusted); } } - private void checkAdditionalTrust(X509Certificate[] chain, String authType, - SSLEngine engine, boolean isClient) throws CertificateException { + private void checkAdditionalTrust(X509Certificate[] chain, + String authType, SSLEngine engine, + boolean checkClientTrusted) throws CertificateException { if (engine != null) { SSLSession session = engine.getHandshakeSession(); if (session == null) { @@ -1171,9 +1172,8 @@ final class AbstractTrustManagerWrapper extends X509ExtendedTrustManager String identityAlg = engine.getSSLParameters(). getEndpointIdentificationAlgorithm(); if (identityAlg != null && identityAlg.length() != 0) { - String hostname = session.getPeerHost(); - X509TrustManagerImpl.checkIdentity( - hostname, chain[0], identityAlg); + X509TrustManagerImpl.checkIdentity(session, chain, + identityAlg, checkClientTrusted); } // try the best to check the algorithm constraints @@ -1197,12 +1197,13 @@ final class AbstractTrustManagerWrapper extends X509ExtendedTrustManager constraints = new SSLAlgorithmConstraints(engine, true); } - checkAlgorithmConstraints(chain, constraints, isClient); + checkAlgorithmConstraints(chain, constraints, checkClientTrusted); } } private void checkAlgorithmConstraints(X509Certificate[] chain, - AlgorithmConstraints constraints, boolean isClient) throws CertificateException { + AlgorithmConstraints constraints, + boolean checkClientTrusted) throws CertificateException { try { // Does the certificate chain end with a trusted certificate? @@ -1222,7 +1223,8 @@ final class AbstractTrustManagerWrapper extends X509ExtendedTrustManager if (checkedLength >= 0) { AlgorithmChecker checker = new AlgorithmChecker(constraints, null, - (isClient ? Validator.VAR_TLS_CLIENT : Validator.VAR_TLS_SERVER)); + (checkClientTrusted ? Validator.VAR_TLS_CLIENT : + Validator.VAR_TLS_SERVER)); checker.init(false); for (int i = checkedLength; i >= 0; i--) { Certificate cert = chain[i]; diff --git a/src/share/classes/sun/security/ssl/X509TrustManagerImpl.java b/src/share/classes/sun/security/ssl/X509TrustManagerImpl.java index 5a829a55066b274b5b5ceaf6a27f4b34e40a6d93..19801b16ec31c6b7d0e871ce9c6b16b749f4d29a 100644 --- a/src/share/classes/sun/security/ssl/X509TrustManagerImpl.java +++ b/src/share/classes/sun/security/ssl/X509TrustManagerImpl.java @@ -145,7 +145,7 @@ final class X509TrustManagerImpl extends X509ExtendedTrustManager } private Validator checkTrustedInit(X509Certificate[] chain, - String authType, boolean isClient) { + String authType, boolean checkClientTrusted) { if (chain == null || chain.length == 0) { throw new IllegalArgumentException( "null or zero-length certificate chain"); @@ -157,7 +157,7 @@ final class X509TrustManagerImpl extends X509ExtendedTrustManager } Validator v = null; - if (isClient) { + if (checkClientTrusted) { v = clientValidator; if (v == null) { synchronized (this) { @@ -187,9 +187,10 @@ final class X509TrustManagerImpl extends X509ExtendedTrustManager } - private void checkTrusted(X509Certificate[] chain, String authType, - Socket socket, boolean isClient) throws CertificateException { - Validator v = checkTrustedInit(chain, authType, isClient); + private void checkTrusted(X509Certificate[] chain, + String authType, Socket socket, + boolean checkClientTrusted) throws CertificateException { + Validator v = checkTrustedInit(chain, authType, checkClientTrusted); AlgorithmConstraints constraints = null; if ((socket != null) && socket.isConnected() && @@ -205,8 +206,7 @@ final class X509TrustManagerImpl extends X509ExtendedTrustManager String identityAlg = sslSocket.getSSLParameters(). getEndpointIdentificationAlgorithm(); if (identityAlg != null && identityAlg.length() != 0) { - checkIdentity(session, chain[0], identityAlg, isClient, - getRequestedServerNames(socket)); + checkIdentity(session, chain, identityAlg, checkClientTrusted); } // create the algorithm constraints @@ -231,7 +231,7 @@ final class X509TrustManagerImpl extends X509ExtendedTrustManager } X509Certificate[] trustedChain = null; - if (isClient) { + if (checkClientTrusted) { trustedChain = validate(v, chain, constraints, null); } else { trustedChain = validate(v, chain, constraints, authType); @@ -242,9 +242,10 @@ final class X509TrustManagerImpl extends X509ExtendedTrustManager } } - private void checkTrusted(X509Certificate[] chain, String authType, - SSLEngine engine, boolean isClient) throws CertificateException { - Validator v = checkTrustedInit(chain, authType, isClient); + private void checkTrusted(X509Certificate[] chain, + String authType, SSLEngine engine, + boolean checkClientTrusted) throws CertificateException { + Validator v = checkTrustedInit(chain, authType, checkClientTrusted); AlgorithmConstraints constraints = null; if (engine != null) { @@ -257,8 +258,7 @@ final class X509TrustManagerImpl extends X509ExtendedTrustManager String identityAlg = engine.getSSLParameters(). getEndpointIdentificationAlgorithm(); if (identityAlg != null && identityAlg.length() != 0) { - checkIdentity(session, chain[0], identityAlg, isClient, - getRequestedServerNames(engine)); + checkIdentity(session, chain, identityAlg, checkClientTrusted); } // create the algorithm constraints @@ -283,7 +283,7 @@ final class X509TrustManagerImpl extends X509ExtendedTrustManager } X509Certificate[] trustedChain = null; - if (isClient) { + if (checkClientTrusted) { trustedChain = validate(v, chain, constraints, null); } else { trustedChain = validate(v, chain, constraints, authType); @@ -373,13 +373,8 @@ final class X509TrustManagerImpl extends X509ExtendedTrustManager if (socket != null && socket.isConnected() && socket instanceof SSLSocket) { - SSLSocket sslSocket = (SSLSocket)socket; - SSLSession session = sslSocket.getHandshakeSession(); - - if (session != null && (session instanceof ExtendedSSLSession)) { - ExtendedSSLSession extSession = (ExtendedSSLSession)session; - return extSession.getRequestedServerNames(); - } + return getRequestedServerNames( + ((SSLSocket)socket).getHandshakeSession()); } return Collections.emptyList(); @@ -388,12 +383,16 @@ final class X509TrustManagerImpl extends X509ExtendedTrustManager // Also used by X509KeyManagerImpl static List getRequestedServerNames(SSLEngine engine) { if (engine != null) { - SSLSession session = engine.getHandshakeSession(); + return getRequestedServerNames(engine.getHandshakeSession()); + } - if (session != null && (session instanceof ExtendedSSLSession)) { - ExtendedSSLSession extSession = (ExtendedSSLSession)session; - return extSession.getRequestedServerNames(); - } + return Collections.emptyList(); + } + + private static List getRequestedServerNames( + SSLSession session) { + if (session != null && (session instanceof ExtendedSSLSession)) { + return ((ExtendedSSLSession)session).getRequestedServerNames(); } return Collections.emptyList(); @@ -414,22 +413,23 @@ final class X509TrustManagerImpl extends X509ExtendedTrustManager * the identity checking aginst the server_name extension if present, and * may failove to peer host checking. */ - private static void checkIdentity(SSLSession session, - X509Certificate cert, + static void checkIdentity(SSLSession session, + X509Certificate [] trustedChain, String algorithm, - boolean isClient, - List sniNames) throws CertificateException { + boolean checkClientTrusted) throws CertificateException { boolean identifiable = false; String peerHost = session.getPeerHost(); - if (isClient) { - String hostname = getHostNameInSNI(sniNames); - if (hostname != null) { + if (!checkClientTrusted) { + List sniNames = getRequestedServerNames(session); + String sniHostName = getHostNameInSNI(sniNames); + if (sniHostName != null) { try { - checkIdentity(hostname, cert, algorithm); + checkIdentity(sniHostName, + trustedChain[0], algorithm); identifiable = true; } catch (CertificateException ce) { - if (hostname.equalsIgnoreCase(peerHost)) { + if (sniHostName.equalsIgnoreCase(peerHost)) { throw ce; } @@ -439,7 +439,8 @@ final class X509TrustManagerImpl extends X509ExtendedTrustManager } if (!identifiable) { - checkIdentity(peerHost, cert, algorithm); + checkIdentity(peerHost, + trustedChain[0], algorithm); } } diff --git a/src/share/classes/sun/security/util/ArrayUtil.java b/src/share/classes/sun/security/util/ArrayUtil.java index 5e5fc0aa52e29b6abc30295116f48958e48752a8..331c10079cb91badc089b1bf567b40893e018890 100644 --- a/src/share/classes/sun/security/util/ArrayUtil.java +++ b/src/share/classes/sun/security/util/ArrayUtil.java @@ -25,12 +25,34 @@ package sun.security.util; +import java.util.List; +import java.util.function.BiFunction; +import java.security.*; +import jdk.internal.util.Preconditions; + + /** * This class holds the various utility methods for array range checks. */ public final class ArrayUtil { + private static final BiFunction, + ArrayIndexOutOfBoundsException> AIOOBE_SUPPLIER = + Preconditions.outOfBoundsExceptionFormatter + (ArrayIndexOutOfBoundsException::new); + + public static void blockSizeCheck(int len, int blockSize) { + if ((len % blockSize) != 0) { + throw new ProviderException("Internal error in input buffering"); + } + } + + public static void nullAndBoundsCheck(byte[] array, int offset, int len) { + // NPE is thrown when array is null + Preconditions.checkFromIndexSize(offset, len, array.length, AIOOBE_SUPPLIER); + } + private static void swap(byte[] arr, int i, int j) { byte tmp = arr[i]; arr[i] = arr[j]; @@ -48,4 +70,3 @@ public final class ArrayUtil { } } } - diff --git a/src/share/classes/sun/security/util/DerIndefLenConverter.java b/src/share/classes/sun/security/util/DerIndefLenConverter.java index cbd5ecc00e705b5fa2d745daa4f67589d6b9e6bb..9eb44862cbc5fb8f346d8e5b909afea6990f441a 100644 --- a/src/share/classes/sun/security/util/DerIndefLenConverter.java +++ b/src/share/classes/sun/security/util/DerIndefLenConverter.java @@ -92,37 +92,41 @@ class DerIndefLenConverter { private void parseTag() throws IOException { if (dataPos == dataSize) return; - if (isEOC(data[dataPos]) && (data[dataPos + 1] == 0)) { - int numOfEncapsulatedLenBytes = 0; - Object elem = null; - int index; - for (index = ndefsList.size()-1; index >= 0; index--) { - // Determine the first element in the vector that does not - // have a matching EOC - elem = ndefsList.get(index); - if (elem instanceof Integer) { - break; - } else { - numOfEncapsulatedLenBytes += ((byte[])elem).length - 3; + try { + if (isEOC(data[dataPos]) && (data[dataPos + 1] == 0)) { + int numOfEncapsulatedLenBytes = 0; + Object elem = null; + int index; + for (index = ndefsList.size()-1; index >= 0; index--) { + // Determine the first element in the vector that does not + // have a matching EOC + elem = ndefsList.get(index); + if (elem instanceof Integer) { + break; + } else { + numOfEncapsulatedLenBytes += ((byte[])elem).length - 3; + } } + if (index < 0) { + throw new IOException("EOC does not have matching " + + "indefinite-length tag"); + } + int sectionLen = dataPos - ((Integer)elem).intValue() + + numOfEncapsulatedLenBytes; + byte[] sectionLenBytes = getLengthBytes(sectionLen); + ndefsList.set(index, sectionLenBytes); + unresolved--; + + // Add the number of bytes required to represent this section + // to the total number of length bytes, + // and subtract the indefinite-length tag (1 byte) and + // EOC bytes (2 bytes) for this section + numOfTotalLenBytes += (sectionLenBytes.length - 3); } - if (index < 0) { - throw new IOException("EOC does not have matching " + - "indefinite-length tag"); - } - int sectionLen = dataPos - ((Integer)elem).intValue() + - numOfEncapsulatedLenBytes; - byte[] sectionLenBytes = getLengthBytes(sectionLen); - ndefsList.set(index, sectionLenBytes); - unresolved--; - - // Add the number of bytes required to represent this section - // to the total number of length bytes, - // and subtract the indefinite-length tag (1 byte) and - // EOC bytes (2 bytes) for this section - numOfTotalLenBytes += (sectionLenBytes.length - 3); + dataPos++; + } catch (IndexOutOfBoundsException iobe) { + throw new IOException(iobe); } - dataPos++; } /** diff --git a/src/share/classes/sun/security/util/HostnameChecker.java b/src/share/classes/sun/security/util/HostnameChecker.java index 1b30cf53292e966bafe01d09f043f245ad4fde2a..89712ddd9990fa17211fc5393f6aa1569fab2fe3 100644 --- a/src/share/classes/sun/security/util/HostnameChecker.java +++ b/src/share/classes/sun/security/util/HostnameChecker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2019, 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 @@ -262,18 +262,17 @@ public class HostnameChecker { * The matching is performed as per RFC 2818 rules for TLS and * RFC 2830 rules for LDAP.

* - * The name parameter should represent a DNS name. - * The template parameter - * may contain the wildcard character * + * The name parameter should represent a DNS name. The + * template parameter may contain the wildcard character '*'. */ private boolean isMatched(String name, String template) { // check the validity of the domain name template. try { - // Replacing wildcard character '*' with 'x' so as to check + // Replacing wildcard character '*' with 'z' so as to check // the domain name template validity. // // Using the checking implemented in SNIHostName - SNIHostName sni = new SNIHostName(template.replace('*', 'x')); + SNIHostName sni = new SNIHostName(template.replace('*', 'z')); } catch (IllegalArgumentException iae) { // It would be nice to add debug log if not matching. return false; diff --git a/src/share/native/sun/awt/libpng/png.c b/src/share/native/sun/awt/libpng/png.c index 1a44c9c8cfc89218f7033bda47a52e4d671d61e4..a471c76d06021056c80eafa38f4dc89d833603e0 100644 --- a/src/share/native/sun/awt/libpng/png.c +++ b/src/share/native/sun/awt/libpng/png.c @@ -4622,8 +4622,7 @@ png_image_free(png_imagep image) if (image != NULL && image->opaque != NULL && image->opaque->error_buf == NULL) { - /* Ignore errors here: */ - (void)png_safe_execute(image, png_image_free_function, image); + png_image_free_function(image); image->opaque = NULL; } } diff --git a/src/share/native/sun/font/layout/AlternateSubstSubtables.cpp b/src/share/native/sun/font/layout/AlternateSubstSubtables.cpp index f296e89d3d59de7b7233b54a582f900e67e1250b..b27d4ee5010c9970dd2b3e42d44f097530ac2cda 100644 --- a/src/share/native/sun/font/layout/AlternateSubstSubtables.cpp +++ b/src/share/native/sun/font/layout/AlternateSubstSubtables.cpp @@ -50,7 +50,13 @@ le_uint32 AlternateSubstitutionSubtable::process(const LEReferenceTo + arrayRef(base, success, alternateSetTableOffsetArray, altSetCount); + if (!LE_SUCCESS(success)) return 0; + + Offset alternateSetTableOffset = SWAPW(arrayRef.getObject(coverageIndex, success)); + if (!LE_SUCCESS(success)) return 0; + const LEReferenceTo alternateSetTable(base, success, (const AlternateSetTable *) ((char *) this + alternateSetTableOffset)); if (!LE_SUCCESS(success)) return 0; diff --git a/src/share/native/sun/font/layout/MarkToBasePosnSubtables.cpp b/src/share/native/sun/font/layout/MarkToBasePosnSubtables.cpp index 086da91629e583401f48c060f36e088b9a51fe53..f8081a9c22324ed037aa62c1c6b7bb8572f0c80f 100644 --- a/src/share/native/sun/font/layout/MarkToBasePosnSubtables.cpp +++ b/src/share/native/sun/font/layout/MarkToBasePosnSubtables.cpp @@ -80,6 +80,9 @@ le_int32 MarkToBasePositioningSubtable::process(const LETableReference &base, Gl // FIXME: We probably don't want to find a base glyph before a previous ligature... GlyphIterator baseIterator(*glyphIterator, (le_uint16) (lfIgnoreMarks /*| lfIgnoreLigatures*/)); LEGlyphID baseGlyph = findBaseGlyph(&baseIterator); + if (baseGlyph == 0xFFFF) { + return 0; + } le_int32 baseCoverage = getBaseCoverage(base, (LEGlyphID) baseGlyph, success); LEReferenceTo baseArray(base, success, (const BaseArray *) ((char *) this + SWAPW(baseArrayOffset))); if(LE_FAILURE(success)) return 0; diff --git a/src/share/native/sun/font/layout/MarkToLigaturePosnSubtables.cpp b/src/share/native/sun/font/layout/MarkToLigaturePosnSubtables.cpp index 2515b8afb5afcabb2009d4cf490f7902db49c0f6..e70f35c50e5bea7d7a2bc038b73a6d3531b9b4f9 100644 --- a/src/share/native/sun/font/layout/MarkToLigaturePosnSubtables.cpp +++ b/src/share/native/sun/font/layout/MarkToLigaturePosnSubtables.cpp @@ -81,6 +81,9 @@ le_int32 MarkToLigaturePositioningSubtable::process(const LETableReference &base // FIXME: we probably don't want to find a ligature before a previous base glyph... GlyphIterator ligatureIterator(*glyphIterator, (le_uint16) (lfIgnoreMarks /*| lfIgnoreBaseGlyphs*/)); LEGlyphID ligatureGlyph = findLigatureGlyph(&ligatureIterator); + if (ligatureGlyph == 0xFFFF) { + return 0; + } le_int32 ligatureCoverage = getBaseCoverage(base, (LEGlyphID) ligatureGlyph, success); LEReferenceTo ligatureArray(base, success, SWAPW(baseArrayOffset)); if (LE_FAILURE(success)) { return 0; } diff --git a/src/share/native/sun/font/layout/MarkToMarkPosnSubtables.cpp b/src/share/native/sun/font/layout/MarkToMarkPosnSubtables.cpp index 4ed835453af14493d0eb1e946d4177fa1288ce80..0e16a2fced2c808c255b0176c434a3e160291073 100644 --- a/src/share/native/sun/font/layout/MarkToMarkPosnSubtables.cpp +++ b/src/share/native/sun/font/layout/MarkToMarkPosnSubtables.cpp @@ -81,6 +81,9 @@ le_int32 MarkToMarkPositioningSubtable::process(const LETableReference &base, Gl GlyphIterator mark2Iterator(*glyphIterator); LEGlyphID mark2Glyph = findMark2Glyph(&mark2Iterator); + if (mark2Glyph == 0xFFFF) { + return 0; + } le_int32 mark2Coverage = getBaseCoverage(base, (LEGlyphID) mark2Glyph, success); LEReferenceTo mark2Array(base, success, (const Mark2Array *) ((char *) this + SWAPW(baseArrayOffset))); if(LE_FAILURE(success)) return 0; diff --git a/src/share/native/sun/font/layout/OpenTypeLayoutEngine.cpp b/src/share/native/sun/font/layout/OpenTypeLayoutEngine.cpp index b4c9122c5e24fa5a69da895fb7bf976cc1ea289f..a02894954f3dd219c75ef75d387259bbe777f4aa 100644 --- a/src/share/native/sun/font/layout/OpenTypeLayoutEngine.cpp +++ b/src/share/native/sun/font/layout/OpenTypeLayoutEngine.cpp @@ -543,7 +543,7 @@ void OpenTypeLayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int3 yAdjust += yKerning; #endif - for (le_int32 base = i; base >= 0; base = adjustments->getBaseOffset(base)) { + for (le_int32 base = i; base >= 0 && base < glyphCount; base = adjustments->getBaseOffset(base)) { xPlacement += adjustments->getXPlacement(base); yPlacement += adjustments->getYPlacement(base); } diff --git a/src/windows/classes/sun/net/www/protocol/file/Handler.java b/src/windows/classes/sun/net/www/protocol/file/Handler.java index 8a5531268decc27fa367a1390feb417dde878b33..7a331a0c5ece6a2afb521f9504013876feec8a26 100644 --- a/src/windows/classes/sun/net/www/protocol/file/Handler.java +++ b/src/windows/classes/sun/net/www/protocol/file/Handler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2019, 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 @@ -95,7 +95,7 @@ public class Handler extends URLStreamHandler { path = "\\\\" + host + path; File f = new File(path); if (f.exists()) { - return createFileURLConnection(url, f); + return new UNCFileURLConnection(url, f, path); } /* diff --git a/src/windows/classes/sun/net/www/protocol/file/UNCFileURLConnection.java b/src/windows/classes/sun/net/www/protocol/file/UNCFileURLConnection.java new file mode 100644 index 0000000000000000000000000000000000000000..c36b84aa4dcface26605d43d8e885ece6752f435 --- /dev/null +++ b/src/windows/classes/sun/net/www/protocol/file/UNCFileURLConnection.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2019, 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.net.www.protocol.file; + +import java.io.File; +import java.io.FilePermission; +import java.net.URL; +import java.security.Permission; + +final class UNCFileURLConnection extends FileURLConnection { + + private final String effectivePath; + private volatile Permission permission; + + UNCFileURLConnection(URL u, File file, String effectivePath) { + super(u, file); + this.effectivePath = effectivePath; + } + + @Override + public Permission getPermission() { + Permission perm = permission; + if (perm == null) { + permission = perm = new FilePermission(effectivePath, "read"); + } + return perm; + } +} + diff --git a/src/windows/native/sun/security/mscapi/security.cpp b/src/windows/native/sun/security/mscapi/security.cpp index 7012a35ccd57d6e11363ee8990ee0b318c9345ec..12c408e8ee3a13394d9db4e079c8e6048a931520 100644 --- a/src/windows/native/sun/security/mscapi/security.cpp +++ b/src/windows/native/sun/security/mscapi/security.cpp @@ -202,14 +202,17 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_PRNG_generateSeed } /* - * If length is negative then use the supplied seed to re-seed the - * generator and return null. + * If length is negative and a seed is supplied, use it to re-seed the + * generator. Return null whether a seed is supplied or not. * If length is non-zero then generate a new seed according to the * requested length and return the new seed. * If length is zero then overwrite the supplied seed with a new * seed of the same length and return the seed. */ if (length < 0) { + if (seed == NULL) { + __leave; + } length = env->GetArrayLength(seed); if ((reseedBytes = env->GetByteArrayElements(seed, 0)) == NULL) { __leave; diff --git a/test/java/util/Objects/CheckIndex.java b/test/java/util/Objects/CheckIndex.java new file mode 100644 index 0000000000000000000000000000000000000000..4fe72e5ce37e3730fbb4fd5ef8a6bf8beb7b1918 --- /dev/null +++ b/test/java/util/Objects/CheckIndex.java @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2015, 2016 Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @summary Objects.checkIndex/jdk.internal.util.Preconditions.checkIndex tests + * @run testng CheckIndex + * @bug 8135248 8142493 8155794 + * @modules java.base/jdk.internal.util + */ + +import jdk.internal.util.Preconditions; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.IntSupplier; + +import static org.testng.Assert.*; + +public class CheckIndex { + + static class AssertingOutOfBoundsException extends RuntimeException { + public AssertingOutOfBoundsException(String message) { + super(message); + } + } + + static BiFunction, AssertingOutOfBoundsException> assertingOutOfBounds( + String message, String expCheckKind, Integer... expArgs) { + return (checkKind, args) -> { + assertEquals(checkKind, expCheckKind); + assertEquals(args, Collections.unmodifiableList(Arrays.asList(expArgs))); + try { + args.clear(); + fail("Out of bounds List argument should be unmodifiable"); + } catch (Exception e) { + } + return new AssertingOutOfBoundsException(message); + }; + } + + static BiFunction, AssertingOutOfBoundsException> assertingOutOfBoundsReturnNull( + String expCheckKind, Integer... expArgs) { + return (checkKind, args) -> { + assertEquals(checkKind, expCheckKind); + assertEquals(args, Collections.unmodifiableList(Arrays.asList(expArgs))); + return null; + }; + } + + static final int[] VALUES = {0, 1, Integer.MAX_VALUE - 1, Integer.MAX_VALUE, -1, Integer.MIN_VALUE + 1, Integer.MIN_VALUE}; + + @DataProvider + static Object[][] checkIndexProvider() { + List l = new ArrayList<>(); + for (int index : VALUES) { + for (int length : VALUES) { + boolean withinBounds = index >= 0 && + length >= 0 && + index < length; + l.add(new Object[]{index, length, withinBounds}); + } + } + return l.toArray(new Object[0][0]); + } + + interface X { + int apply(int a, int b, int c); + } + + @Test(dataProvider = "checkIndexProvider") + public void testCheckIndex(int index, int length, boolean withinBounds) { + List list = Collections.unmodifiableList(Arrays.asList(new Integer[] { index, length })); + String expectedMessage = withinBounds + ? null + : Preconditions.outOfBoundsExceptionFormatter(IndexOutOfBoundsException::new). + apply("checkIndex", list).getMessage(); + + BiConsumer, IntSupplier> checker = (ec, s) -> { + try { + int rIndex = s.getAsInt(); + if (!withinBounds) + fail(String.format( + "Index %d is out of bounds of [0, %d), but was reported to be within bounds", index, length)); + assertEquals(rIndex, index); + } + catch (RuntimeException e) { + assertTrue(ec.isInstance(e)); + if (withinBounds) + fail(String.format( + "Index %d is within bounds of [0, %d), but was reported to be out of bounds", index, length)); + else + assertEquals(e.getMessage(), expectedMessage); + } + }; + + checker.accept(AssertingOutOfBoundsException.class, + () -> Preconditions.checkIndex(index, length, + assertingOutOfBounds(expectedMessage, "checkIndex", index, length))); + checker.accept(IndexOutOfBoundsException.class, + () -> Preconditions.checkIndex(index, length, + assertingOutOfBoundsReturnNull("checkIndex", index, length))); + checker.accept(IndexOutOfBoundsException.class, + () -> Preconditions.checkIndex(index, length, null)); + checker.accept(ArrayIndexOutOfBoundsException.class, + () -> Preconditions.checkIndex(index, length, + Preconditions.outOfBoundsExceptionFormatter(ArrayIndexOutOfBoundsException::new))); + checker.accept(StringIndexOutOfBoundsException.class, + () -> Preconditions.checkIndex(index, length, + Preconditions.outOfBoundsExceptionFormatter(StringIndexOutOfBoundsException::new))); + } + + + @DataProvider + static Object[][] checkFromToIndexProvider() { + List l = new ArrayList<>(); + for (int fromIndex : VALUES) { + for (int toIndex : VALUES) { + for (int length : VALUES) { + boolean withinBounds = fromIndex >= 0 && + toIndex >= 0 && + length >= 0 && + fromIndex <= toIndex && + toIndex <= length; + l.add(new Object[]{fromIndex, toIndex, length, withinBounds}); + } + } + } + return l.toArray(new Object[0][0]); + } + + @Test(dataProvider = "checkFromToIndexProvider") + public void testCheckFromToIndex(int fromIndex, int toIndex, int length, boolean withinBounds) { + List list = Collections.unmodifiableList(Arrays.asList(new Integer[] { fromIndex, toIndex, length })); + String expectedMessage = withinBounds + ? null + : Preconditions.outOfBoundsExceptionFormatter(IndexOutOfBoundsException::new). + apply("checkFromToIndex", list).getMessage(); + + BiConsumer, IntSupplier> check = (ec, s) -> { + try { + int rIndex = s.getAsInt(); + if (!withinBounds) + fail(String.format( + "Range [%d, %d) is out of bounds of [0, %d), but was reported to be withing bounds", fromIndex, toIndex, length)); + assertEquals(rIndex, fromIndex); + } + catch (RuntimeException e) { + assertTrue(ec.isInstance(e)); + if (withinBounds) + fail(String.format( + "Range [%d, %d) is within bounds of [0, %d), but was reported to be out of bounds", fromIndex, toIndex, length)); + else + assertEquals(e.getMessage(), expectedMessage); + } + }; + + check.accept(AssertingOutOfBoundsException.class, + () -> Preconditions.checkFromToIndex(fromIndex, toIndex, length, + assertingOutOfBounds(expectedMessage, "checkFromToIndex", fromIndex, toIndex, length))); + check.accept(IndexOutOfBoundsException.class, + () -> Preconditions.checkFromToIndex(fromIndex, toIndex, length, + assertingOutOfBoundsReturnNull("checkFromToIndex", fromIndex, toIndex, length))); + check.accept(IndexOutOfBoundsException.class, + () -> Preconditions.checkFromToIndex(fromIndex, toIndex, length, null)); + check.accept(ArrayIndexOutOfBoundsException.class, + () -> Preconditions.checkFromToIndex(fromIndex, toIndex, length, + Preconditions.outOfBoundsExceptionFormatter(ArrayIndexOutOfBoundsException::new))); + check.accept(StringIndexOutOfBoundsException.class, + () -> Preconditions.checkFromToIndex(fromIndex, toIndex, length, + Preconditions.outOfBoundsExceptionFormatter(StringIndexOutOfBoundsException::new))); + } + + + @DataProvider + static Object[][] checkFromIndexSizeProvider() { + List l = new ArrayList<>(); + for (int fromIndex : VALUES) { + for (int size : VALUES) { + for (int length : VALUES) { + // Explicitly convert to long + long lFromIndex = fromIndex; + long lSize = size; + long lLength = length; + // Avoid overflow + long lToIndex = lFromIndex + lSize; + + boolean withinBounds = lFromIndex >= 0L && + lSize >= 0L && + lLength >= 0L && + lFromIndex <= lToIndex && + lToIndex <= lLength; + l.add(new Object[]{fromIndex, size, length, withinBounds}); + } + } + } + return l.toArray(new Object[0][0]); + } + + @Test(dataProvider = "checkFromIndexSizeProvider") + public void testCheckFromIndexSize(int fromIndex, int size, int length, boolean withinBounds) { + List list = Collections.unmodifiableList(Arrays.asList(new Integer[] { fromIndex, size, length })); + String expectedMessage = withinBounds + ? null + : Preconditions.outOfBoundsExceptionFormatter(IndexOutOfBoundsException::new). + apply("checkFromIndexSize", list).getMessage(); + + BiConsumer, IntSupplier> check = (ec, s) -> { + try { + int rIndex = s.getAsInt(); + if (!withinBounds) + fail(String.format( + "Range [%d, %d + %d) is out of bounds of [0, %d), but was reported to be withing bounds", fromIndex, fromIndex, size, length)); + assertEquals(rIndex, fromIndex); + } + catch (RuntimeException e) { + assertTrue(ec.isInstance(e)); + if (withinBounds) + fail(String.format( + "Range [%d, %d + %d) is within bounds of [0, %d), but was reported to be out of bounds", fromIndex, fromIndex, size, length)); + else + assertEquals(e.getMessage(), expectedMessage); + } + }; + + check.accept(AssertingOutOfBoundsException.class, + () -> Preconditions.checkFromIndexSize(fromIndex, size, length, + assertingOutOfBounds(expectedMessage, "checkFromIndexSize", fromIndex, size, length))); + check.accept(IndexOutOfBoundsException.class, + () -> Preconditions.checkFromIndexSize(fromIndex, size, length, + assertingOutOfBoundsReturnNull("checkFromIndexSize", fromIndex, size, length))); + check.accept(IndexOutOfBoundsException.class, + () -> Preconditions.checkFromIndexSize(fromIndex, size, length, null)); + check.accept(ArrayIndexOutOfBoundsException.class, + () -> Preconditions.checkFromIndexSize(fromIndex, size, length, + Preconditions.outOfBoundsExceptionFormatter(ArrayIndexOutOfBoundsException::new))); + check.accept(StringIndexOutOfBoundsException.class, + () -> Preconditions.checkFromIndexSize(fromIndex, size, length, + Preconditions.outOfBoundsExceptionFormatter(StringIndexOutOfBoundsException::new))); + } + + @Test + public void uniqueMessagesForCheckKinds() { + BiFunction, IndexOutOfBoundsException> f = + Preconditions.outOfBoundsExceptionFormatter(IndexOutOfBoundsException::new); + + List messages = new ArrayList<>(); + List arg1 = Collections.unmodifiableList(Arrays.asList(new Integer[] { -1 })); + List arg2 = Collections.unmodifiableList(Arrays.asList(new Integer[] { -1, 0 })); + List arg3 = Collections.unmodifiableList(Arrays.asList(new Integer[] { -1, 0, 0 })); + List arg4 = Collections.unmodifiableList(Arrays.asList(new Integer[] { -1, 0, 0, 0 })); + // Exact arguments + messages.add(f.apply("checkIndex", arg2).getMessage()); + messages.add(f.apply("checkFromToIndex", arg3).getMessage()); + messages.add(f.apply("checkFromIndexSize", arg3).getMessage()); + // Unknown check kind + messages.add(f.apply("checkUnknown", arg3).getMessage()); + // Known check kind with more arguments + messages.add(f.apply("checkIndex", arg3).getMessage()); + messages.add(f.apply("checkFromToIndex", arg4).getMessage()); + messages.add(f.apply("checkFromIndexSize", arg4).getMessage()); + // Known check kind with fewer arguments + messages.add(f.apply("checkIndex", arg1).getMessage()); + messages.add(f.apply("checkFromToIndex", arg2).getMessage()); + messages.add(f.apply("checkFromIndexSize", arg2).getMessage()); + // Null arguments + messages.add(f.apply(null, null).getMessage()); + messages.add(f.apply("checkNullArguments", null).getMessage()); + messages.add(f.apply(null, arg1).getMessage()); + + assertEquals(messages.size(), messages.stream().distinct().count()); + } +} diff --git a/test/javax/imageio/plugins/jpeg/JpegTablesOnlyReadTest.java b/test/javax/imageio/plugins/jpeg/JpegTablesOnlyReadTest.java new file mode 100644 index 0000000000000000000000000000000000000000..2393da3c25ca8285c3bbb62de8ccd97484747219 --- /dev/null +++ b/test/javax/imageio/plugins/jpeg/JpegTablesOnlyReadTest.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8191073 + * @summary Test verifies that when user tries to read image data from a + * tables-only image input stream it should through IIOException + * instead of throwing any other exception as per specification. + * @run main JpegTablesOnlyReadTest + */ + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Base64; +import javax.imageio.IIOException; +import javax.imageio.ImageIO; + +public class JpegTablesOnlyReadTest { + // JPEG input stream containing tables-only image + private static String inputImageBase64 = "/9j/4IAQSkZJRgABAQEASABIAAD" + + "/2wBDAFA3PEY8MlBGQUZaVVBfeMiCeG5uePWvuZHI//////////////////////" + + "//////////////////////////////2wBDAVVaWnhpeOuCguv//////////////" + + "///////////////////////////////////////////////////////////wAAR" + + "CAAgACADASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAECA//EACUQAQA" + + "CAAUDBAMAAAAAAAAAAAEAAhESITGxQXKSA2Fi0SIyUf/EABYBAQEBAAAAAAAAAA" + + "AAAAAAAAABA//EABcRAQEBAQAAAAAAAAAAAAAAAAEAESH/2gAMAwEAAhEDEQA/A" + + "Nf2VW2OKaWTqnRhl97eb9wrs91uWPEBUX+EtmrssvvbzfuJWjVG2tg1svLLtgJ0" + + "Uxwmd96d5zE7tVdnutyxm5JVoo0u6rpXHdWLP8PU8WIjtRuvVZN96d5zDP8AD1P" + + "Fhre1Apc/Ida4RAdv/9k="; + + public static void main(String[] args) throws IOException { + byte[] inputBytes = Base64.getDecoder().decode(inputImageBase64); + InputStream in = new ByteArrayInputStream(inputBytes); + + // Read tables-only JPEG image + try { + ImageIO.read(in); + } catch (IIOException e) { + // do nothing we expect it to throw IIOException if it throws + // any other exception test will fail. + } + } +} +