diff --git a/.hgtags b/.hgtags index 1477af9d98b..bc54aef4ab6 100644 --- a/.hgtags +++ b/.hgtags @@ -565,3 +565,5 @@ deaef57bf366fdab908b97a9760d0fa6e273abcd jdk-11.0.5+6 046604d257d7bc698ee213d70af09793f5008ff1 jdk-11.0.5+7 2c29e9b3a2856350d55a188635c36c5b23c1c9e3 jdk-11.0.5+8 ee7128cf507a670ae84841b202a7a06711608359 jdk-11.0.5+9 +6385eb06af947d8ec5fd51a4733bc8187efb88b5 jdk-11.0.5+10 +6385eb06af947d8ec5fd51a4733bc8187efb88b5 jdk-11.0.5-ga diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index 42e22812ee4..57bb3520b70 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -6353,7 +6353,7 @@ void MacroAssembler::string_indexof_char(Register str1, Register cnt1, Register movptr(result, str1); if (UseAVX >= 2) { cmpl(cnt1, stride); - jcc(Assembler::less, SCAN_TO_CHAR_LOOP); + jcc(Assembler::less, SCAN_TO_CHAR); cmpl(cnt1, 2*stride); jcc(Assembler::less, SCAN_TO_8_CHAR_INIT); movdl(vec1, ch); @@ -6380,10 +6380,8 @@ void MacroAssembler::string_indexof_char(Register str1, Register cnt1, Register } bind(SCAN_TO_8_CHAR); cmpl(cnt1, stride); - if (UseAVX >= 2) { - jcc(Assembler::less, SCAN_TO_CHAR); - } else { - jcc(Assembler::less, SCAN_TO_CHAR_LOOP); + jcc(Assembler::less, SCAN_TO_CHAR); + if (UseAVX < 2) { movdl(vec1, ch); pshuflw(vec1, vec1, 0x00); pshufd(vec1, vec1, 0); diff --git a/src/java.base/share/classes/java/io/FilePermission.java b/src/java.base/share/classes/java/io/FilePermission.java index 3328805b53b..2876fdd5fc4 100644 --- a/src/java.base/share/classes/java/io/FilePermission.java +++ b/src/java.base/share/classes/java/io/FilePermission.java @@ -366,12 +366,22 @@ private void init(int mask) { this.mask = mask; if (cpath.equals("<>")) { + allFiles = true; directory = true; recursive = true; cpath = ""; return; } + // Validate path by platform's default file system + try { + String name = cpath.endsWith("*") ? cpath.substring(0, cpath.length() - 1) + "-" : cpath; + builtInFS.getPath(new File(name).getPath()); + } catch (InvalidPathException ipe) { + invalid = true; + return; + } + // store only the canonical cpath if possible cpath = AccessController.doPrivileged(new PrivilegedAction<>() { public String run() { @@ -462,6 +472,9 @@ public String run() { *

* The default value of the {@code jdk.io.permissionsUseCanonicalPath} * system property is {@code false} in this implementation. + *

+ * The value can also be set with a security property using the same name, + * but setting a system property will override the security property value. * * @param path the pathname of the file/directory. * @param actions the action string. @@ -572,19 +585,19 @@ public boolean implies(Permission p) { * @return the effective mask */ boolean impliesIgnoreMask(FilePermission that) { + if (this == that) { + return true; + } + if (allFiles) { + return true; + } + if (this.invalid || that.invalid) { + return false; + } + if (that.allFiles) { + return false; + } if (FilePermCompat.nb) { - if (this == that) { - return true; - } - if (allFiles) { - return true; - } - if (this.invalid || that.invalid) { - return false; - } - if (that.allFiles) { - return false; - } // Left at least same level of wildness as right if ((this.recursive && that.recursive) != that.recursive || (this.directory && that.directory) != that.directory) { @@ -782,10 +795,10 @@ public boolean equals(Object obj) { FilePermission that = (FilePermission) obj; + if (this.invalid || that.invalid) { + return false; + } if (FilePermCompat.nb) { - if (this.invalid || that.invalid) { - return false; - } return (this.mask == that.mask) && (this.allFiles == that.allFiles) && this.npath.equals(that.npath) && @@ -794,6 +807,7 @@ public boolean equals(Object obj) { (this.recursive == that.recursive); } else { return (this.mask == that.mask) && + (this.allFiles == that.allFiles) && this.cpath.equals(that.cpath) && (this.directory == that.directory) && (this.recursive == that.recursive); diff --git a/src/java.base/share/classes/java/net/NetPermission.java b/src/java.base/share/classes/java/net/NetPermission.java index 0df2c91a299..745bb9e7db4 100644 --- a/src/java.base/share/classes/java/net/NetPermission.java +++ b/src/java.base/share/classes/java/net/NetPermission.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2017, 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 @@ -145,6 +145,15 @@ * * * + * setSocketImpl + * The ability to create a sub-class of Socket or ServerSocket with a + * user specified SocketImpl. + * Malicious user-defined SocketImpls can change the behavior of + * Socket and ServerSocket in surprising ways, by virtue of their + * ability to access the protected fields of SocketImpl. + * + * + * * specifyStreamHandler * The ability * to specify a stream handler when constructing a URL diff --git a/src/java.base/share/classes/java/net/ServerSocket.java b/src/java.base/share/classes/java/net/ServerSocket.java index 92a8b8ca8fd..c666d6c7886 100644 --- a/src/java.base/share/classes/java/net/ServerSocket.java +++ b/src/java.base/share/classes/java/net/ServerSocket.java @@ -27,6 +27,7 @@ import jdk.internal.misc.JavaNetSocketAccess; import jdk.internal.misc.SharedSecrets; +import sun.security.util.SecurityConstants; import java.io.FileDescriptor; import java.io.IOException; @@ -78,12 +79,25 @@ class ServerSocket implements java.io.Closeable { /** * Package-private constructor to create a ServerSocket associated with * the given SocketImpl. + * + * @throws SecurityException if a security manager is set and + * its {@code checkPermission} method doesn't allow + * {@code NetPermission("setSocketImpl")}. */ ServerSocket(SocketImpl impl) { + checkPermission(); this.impl = impl; impl.setServerSocket(this); } + private static Void checkPermission() { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(SecurityConstants.SET_SOCKETIMPL_PERMISSION); + } + return null; + } + /** * Creates an unbound server socket. * diff --git a/src/java.base/share/classes/java/net/Socket.java b/src/java.base/share/classes/java/net/Socket.java index f085b1d5e90..6e52cb5441e 100644 --- a/src/java.base/share/classes/java/net/Socket.java +++ b/src/java.base/share/classes/java/net/Socket.java @@ -25,6 +25,8 @@ package java.net; +import sun.security.util.SecurityConstants; + import java.io.InputStream; import java.io.OutputStream; import java.io.IOException; @@ -161,9 +163,14 @@ public Socket(Proxy proxy) { * * @exception SocketException if there is an error in the underlying protocol, * such as a TCP error. + * + * @throws SecurityException if {@code impl} is non-null and a security manager is set + * and its {@code checkPermission} method doesn't allow {@code NetPermission("setSocketImpl")}. + * * @since 1.1 */ protected Socket(SocketImpl impl) throws SocketException { + checkPermission(impl); this.impl = impl; if (impl != null) { checkOldImpl(); @@ -171,6 +178,17 @@ protected Socket(SocketImpl impl) throws SocketException { } } + private static Void checkPermission(SocketImpl impl) { + if (impl == null) { + return null; + } + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(SecurityConstants.SET_SOCKETIMPL_PERMISSION); + } + return null; + } + /** * Creates a stream socket and connects it to the specified port * number on the named host. diff --git a/src/java.base/share/classes/java/net/URL.java b/src/java.base/share/classes/java/net/URL.java index c44a5641255..0d258708333 100644 --- a/src/java.base/share/classes/java/net/URL.java +++ b/src/java.base/share/classes/java/net/URL.java @@ -457,6 +457,16 @@ public URL(String protocol, String host, int port, String file, throw new MalformedURLException(s); } } + if ("jar".equalsIgnoreCase(protocol)) { + if (handler instanceof sun.net.www.protocol.jar.Handler) { + // URL.openConnection() would throw a confusing exception + // so generate a better exception here instead. + String s = ((sun.net.www.protocol.jar.Handler) handler).checkNestedProtocol(file); + if (s != null) { + throw new MalformedURLException(s); + } + } + } } /** diff --git a/src/java.base/share/classes/java/util/regex/Pattern.java b/src/java.base/share/classes/java/util/regex/Pattern.java index 53113d48ef7..37232f1d1cc 100644 --- a/src/java.base/share/classes/java/util/regex/Pattern.java +++ b/src/java.base/share/classes/java/util/regex/Pattern.java @@ -1424,7 +1424,11 @@ private Pattern(String p, int f) { localTCNCount = 0; if (!pattern.isEmpty()) { - compile(); + try { + compile(); + } catch (StackOverflowError soe) { + throw error("Stack overflow during pattern compilation"); + } } else { root = new Start(lastAccept); matchRoot = lastAccept; @@ -1963,6 +1967,10 @@ private int parsePastLine() { int ch = temp[cursor++]; while (ch != 0 && !isLineSeparator(ch)) ch = temp[cursor++]; + if (ch == 0 && cursor > patternLength) { + cursor = patternLength; + ch = temp[cursor++]; + } return ch; } @@ -1973,6 +1981,10 @@ private int peekPastLine() { int ch = temp[++cursor]; while (ch != 0 && !isLineSeparator(ch)) ch = temp[++cursor]; + if (ch == 0 && cursor > patternLength) { + cursor = patternLength; + ch = temp[cursor]; + } return ch; } @@ -3407,9 +3419,10 @@ private int u() { private int N() { if (read() == '{') { int i = cursor; - while (cursor < patternLength && read() != '}') {} - if (cursor > patternLength) - throw error("Unclosed character name escape sequence"); + while (read() != '}') { + if (cursor >= patternLength) + throw error("Unclosed character name escape sequence"); + } String name = new String(temp, i, cursor - i - 1); try { return Character.codePointOf(name); diff --git a/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java b/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java index 03ea911dcab..54ec8e00bd5 100644 --- a/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java +++ b/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java @@ -2165,6 +2165,10 @@ public synchronized void doTunneling() throws IOException { } while (retryTunnel < maxRedirects); if (retryTunnel >= maxRedirects || (respCode != HTTP_OK)) { + if (respCode != HTTP_PROXY_AUTH) { + // remove all but authenticate responses + responses.reset(); + } throw new IOException("Unable to tunnel through proxy."+ " Proxy returns \"" + statusLine + "\""); diff --git a/src/java.base/share/classes/sun/net/www/protocol/jar/Handler.java b/src/java.base/share/classes/sun/net/www/protocol/jar/Handler.java index 57b01b90300..d492e688cab 100644 --- a/src/java.base/share/classes/sun/net/www/protocol/jar/Handler.java +++ b/src/java.base/share/classes/sun/net/www/protocol/jar/Handler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, 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 @@ -121,6 +121,13 @@ protected int hashCode(URL u) { return h; } + public String checkNestedProtocol(String spec) { + if (spec.regionMatches(true, 0, "jar:", 0, 4)) { + return "Nested JAR URLs are not supported"; + } else { + return null; + } + } @Override @SuppressWarnings("deprecation") @@ -146,6 +153,12 @@ protected void parseURL(URL url, String spec, : false; spec = spec.substring(start, limit); + String exceptionMessage = checkNestedProtocol(spec); + if (exceptionMessage != null) { + // NPE will be transformed into MalformedURLException by the caller + throw new NullPointerException(exceptionMessage); + } + if (absoluteSpec) { file = parseAbsoluteSpec(spec); } else if (!refOnly) { diff --git a/src/java.base/share/classes/sun/security/ssl/SupportedGroupsExtension.java b/src/java.base/share/classes/sun/security/ssl/SupportedGroupsExtension.java index 1044b6d13de..df21c4f8215 100644 --- a/src/java.base/share/classes/sun/security/ssl/SupportedGroupsExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/SupportedGroupsExtension.java @@ -521,12 +521,6 @@ static class SupportedGroups { NamedGroup.SECP256_R1, NamedGroup.SECP384_R1, NamedGroup.SECP521_R1, - NamedGroup.SECT283_K1, - NamedGroup.SECT283_R1, - NamedGroup.SECT409_K1, - NamedGroup.SECT409_R1, - NamedGroup.SECT571_K1, - NamedGroup.SECT571_R1, // FFDHE 2048 NamedGroup.FFDHE_2048, @@ -541,15 +535,6 @@ static class SupportedGroups { NamedGroup.SECP256_R1, NamedGroup.SECP384_R1, NamedGroup.SECP521_R1, - NamedGroup.SECT283_K1, - NamedGroup.SECT283_R1, - NamedGroup.SECT409_K1, - NamedGroup.SECT409_R1, - NamedGroup.SECT571_K1, - NamedGroup.SECT571_R1, - - // non-NIST curves - NamedGroup.SECP256_K1, // FFDHE 2048 NamedGroup.FFDHE_2048, diff --git a/src/java.base/share/classes/sun/security/util/FilePermCompat.java b/src/java.base/share/classes/sun/security/util/FilePermCompat.java index b427e05e2e8..c3e1f8ef5df 100644 --- a/src/java.base/share/classes/sun/security/util/FilePermCompat.java +++ b/src/java.base/share/classes/sun/security/util/FilePermCompat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -42,8 +42,11 @@ public class FilePermCompat { public static final boolean compat; static { - String flag = GetPropertyAction.privilegedGetProperty( - "jdk.io.permissionsUseCanonicalPath", "false"); + String flag = SecurityProperties.privilegedGetOverridable( + "jdk.io.permissionsUseCanonicalPath"); + if (flag == null) { + flag = "false"; + } switch (flag) { case "true": nb = false; diff --git a/src/java.base/share/classes/sun/security/util/SecurityConstants.java b/src/java.base/share/classes/sun/security/util/SecurityConstants.java index ae935a66562..a13181b37a5 100644 --- a/src/java.base/share/classes/sun/security/util/SecurityConstants.java +++ b/src/java.base/share/classes/sun/security/util/SecurityConstants.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -97,6 +97,10 @@ private SecurityConstants () { public static final NetPermission GET_RESPONSECACHE_PERMISSION = new NetPermission("getResponseCache"); + // java.net.ServerSocket, java.net.Socket + public static final NetPermission SET_SOCKETIMPL_PERMISSION = + new NetPermission("setSocketImpl"); + // java.lang.SecurityManager, sun.applet.AppletPanel public static final RuntimePermission CREATE_CLASSLOADER_PERMISSION = new RuntimePermission("createClassLoader"); diff --git a/src/java.base/share/conf/security/java.security b/src/java.base/share/conf/security/java.security index 08753f5eda4..e4afe9e3ceb 100644 --- a/src/java.base/share/conf/security/java.security +++ b/src/java.base/share/conf/security/java.security @@ -1134,3 +1134,51 @@ jdk.sasl.disabledMechanisms= # jdk.security.caDistrustPolicies=SYMANTEC_TLS +# +# FilePermission path canonicalization +# +# This security property dictates how the path argument is processed and stored +# while constructing a FilePermission object. If the value is set to true, the +# path argument is canonicalized and FilePermission methods (such as implies, +# equals, and hashCode) are implemented based on this canonicalized result. +# Otherwise, the path argument is not canonicalized and FilePermission methods are +# implemented based on the original input. See the implementation note of the +# FilePermission class for more details. +# +# If a system property of the same name is also specified, it supersedes the +# security property value defined here. +# +# The default value for this property is false. +# +jdk.io.permissionsUseCanonicalPath=false + + +# +# Policies for the proxy_impersonator Kerberos ccache configuration entry +# +# The proxy_impersonator ccache configuration entry indicates that the ccache +# is a synthetic delegated credential for use with S4U2Proxy by an intermediate +# server. The ccache file should also contain the TGT of this server and +# an evidence ticket from the default principal of the ccache to this server. +# +# This security property determines how Java uses this configuration entry. +# There are 3 possible values: +# +# no-impersonate - Ignore this configuration entry, and always act as +# the owner of the TGT (if it exists). +# +# try-impersonate - Try impersonation when this configuration entry exists. +# If no matching TGT or evidence ticket is found, +# fallback to no-impersonate. +# +# always-impersonate - Always impersonate when this configuration entry exists. +# If no matching TGT or evidence ticket is found, +# no initial credential is read from the ccache. +# +# The default value is "always-impersonate". +# +# If a system property of the same name is also specified, it supersedes the +# security property value defined here. +# +#jdk.security.krb5.default.initiate.credential=always-impersonate + diff --git a/src/java.base/windows/classes/java/lang/ProcessImpl.java b/src/java.base/windows/classes/java/lang/ProcessImpl.java index d4063bdc606..8daa7ac58b7 100644 --- a/src/java.base/windows/classes/java/lang/ProcessImpl.java +++ b/src/java.base/windows/classes/java/lang/ProcessImpl.java @@ -38,6 +38,7 @@ import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayList; +import java.util.Locale; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; @@ -46,6 +47,8 @@ import jdk.internal.misc.JavaIOFileDescriptorAccess; import jdk.internal.misc.SharedSecrets; import jdk.internal.ref.CleanerFactory; +import sun.security.action.GetBooleanAction; +import sun.security.action.GetPropertyAction; /* This class is for the exclusive use of ProcessBuilder.start() to * create new processes. @@ -205,12 +208,15 @@ private static String[] getTokensFromCommand(String command) { private static final int VERIFICATION_CMD_BAT = 0; private static final int VERIFICATION_WIN32 = 1; - private static final int VERIFICATION_LEGACY = 2; + private static final int VERIFICATION_WIN32_SAFE = 2; // inside quotes not allowed + private static final int VERIFICATION_LEGACY = 3; + // See Command shell overview for documentation of special characters. + // https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-xp/bb490954(v=technet.10) private static final char ESCAPE_VERIFICATION[][] = { // We guarantee the only command file execution for implicit [cmd.exe] run. // http://technet.microsoft.com/en-us/library/bb490954.aspx {' ', '\t', '<', '>', '&', '|', '^'}, - + {' ', '\t', '<', '>'}, {' ', '\t', '<', '>'}, {' ', '\t'} }; @@ -227,8 +233,25 @@ private static String createCommandLine(int verificationType, cmdbuf.append(' '); String s = cmd[i]; if (needsEscaping(verificationType, s)) { - cmdbuf.append('"').append(s); + cmdbuf.append('"'); + if (verificationType == VERIFICATION_WIN32_SAFE) { + // Insert the argument, adding '\' to quote any interior quotes + int length = s.length(); + for (int j = 0; j < length; j++) { + char c = s.charAt(j); + if (c == DOUBLEQUOTE) { + int count = countLeadingBackslash(verificationType, s, j); + while (count-- > 0) { + cmdbuf.append(BACKSLASH); // double the number of backslashes + } + cmdbuf.append(BACKSLASH); // backslash to quote the quote + } + cmdbuf.append(c); + } + } else { + cmdbuf.append(s); + } // The code protects the [java.exe] and console command line // parser, that interprets the [\"] combination as an escape // sequence for the ["] char. @@ -241,8 +264,9 @@ private static String createCommandLine(int verificationType, // command line parser. The case of the [""] tail escape // sequence could not be realized due to the argument validation // procedure. - if ((verificationType != VERIFICATION_CMD_BAT) && s.endsWith("\\")) { - cmdbuf.append('\\'); + int count = countLeadingBackslash(verificationType, s, s.length()); + while (count-- > 0) { + cmdbuf.append(BACKSLASH); // double the number of backslashes } cmdbuf.append('"'); } else { @@ -252,26 +276,16 @@ private static String createCommandLine(int verificationType, return cmdbuf.toString(); } - private static boolean isQuoted(boolean noQuotesInside, String arg, - String errorMessage) { - int lastPos = arg.length() - 1; - if (lastPos >=1 && arg.charAt(0) == '"' && arg.charAt(lastPos) == '"') { - // The argument has already been quoted. - if (noQuotesInside) { - if (arg.indexOf('"', 1) != lastPos) { - // There is ["] inside. - throw new IllegalArgumentException(errorMessage); - } - } - return true; - } - if (noQuotesInside) { - if (arg.indexOf('"') >= 0) { - // There is ["] inside. - throw new IllegalArgumentException(errorMessage); - } - } - return false; + /** + * Return the argument without quotes (1st and last) if present, else the arg. + * @param str a string + * @return the string without 1st and last quotes + */ + private static String unQuote(String str) { + int len = str.length(); + return (len >= 2 && str.charAt(0) == DOUBLEQUOTE && str.charAt(len - 1) == DOUBLEQUOTE) + ? str.substring(1, len - 1) + : str; } private static boolean needsEscaping(int verificationType, String arg) { @@ -282,9 +296,26 @@ private static boolean needsEscaping(int verificationType, String arg) { // For [.exe] or [.com] file the unpaired/internal ["] // in the argument is not a problem. - boolean argIsQuoted = isQuoted( - (verificationType == VERIFICATION_CMD_BAT), - arg, "Argument has embedded quote, use the explicit CMD.EXE call."); + String unquotedArg = unQuote(arg); + boolean argIsQuoted = !arg.equals(unquotedArg); + boolean embeddedQuote = unquotedArg.indexOf(DOUBLEQUOTE) >= 0; + + switch (verificationType) { + case VERIFICATION_CMD_BAT: + if (embeddedQuote) { + throw new IllegalArgumentException("Argument has embedded quote, " + + "use the explicit CMD.EXE call."); + } + break; // break determine whether to quote + case VERIFICATION_WIN32_SAFE: + if (argIsQuoted && embeddedQuote) { + throw new IllegalArgumentException("Malformed argument has embedded quote: " + + unquotedArg); + } + break; + default: + break; + } if (!argIsQuoted) { char testEscape[] = ESCAPE_VERIFICATION[verificationType]; @@ -300,13 +331,13 @@ private static boolean needsEscaping(int verificationType, String arg) { private static String getExecutablePath(String path) throws IOException { - boolean pathIsQuoted = isQuoted(true, path, - "Executable name has embedded quote, split the arguments"); - + String name = unQuote(path); + if (name.indexOf(DOUBLEQUOTE) >= 0) { + throw new IllegalArgumentException("Executable name has embedded quote, " + + "split the arguments: " + name); + } // Win32 CreateProcess requires path to be normalized - File fileToRun = new File(pathIsQuoted - ? path.substring(1, path.length() - 1) - : path); + File fileToRun = new File(name); // From the [CreateProcess] function documentation: // @@ -321,13 +352,26 @@ private static String getExecutablePath(String path) // sequence:..." // // In practice ANY non-existent path is extended by [.exe] extension - // in the [CreateProcess] funcion with the only exception: + // in the [CreateProcess] function with the only exception: // the path ends by (.) return fileToRun.getPath(); } + /** + * An executable is any program that is an EXE or does not have an extension + * and the Windows createProcess will be looking for .exe. + * The comparison is case insensitive based on the name. + * @param executablePath the executable file + * @return true if the path ends in .exe or does not have an extension. + */ + private boolean isExe(String executablePath) { + File file = new File(executablePath); + String upName = file.getName().toUpperCase(Locale.ROOT); + return (upName.endsWith(".EXE") || upName.indexOf('.') < 0); + } + // Old version that can be bypassed private boolean isShellFile(String executablePath) { String upPath = executablePath.toUpperCase(); return (upPath.endsWith(".CMD") || upPath.endsWith(".BAT")); @@ -338,6 +382,21 @@ private String quoteString(String arg) { return argbuf.append('"').append(arg).append('"').toString(); } + // Count backslashes before start index of string. + // .bat files don't include backslashes as part of the quote + private static int countLeadingBackslash(int verificationType, + CharSequence input, int start) { + if (verificationType == VERIFICATION_CMD_BAT) + return 0; + int j; + for (j = start - 1; j >= 0 && input.charAt(j) == BACKSLASH; j--) { + // just scanning backwards + } + return (start - 1) - j; // number of BACKSLASHES + } + + private static final char DOUBLEQUOTE = '\"'; + private static final char BACKSLASH = '\\'; private final long handle; private final ProcessHandle processHandle; @@ -353,15 +412,13 @@ private ProcessImpl(String cmd[], throws IOException { String cmdstr; - SecurityManager security = System.getSecurityManager(); - boolean allowAmbiguousCommands = false; - if (security == null) { - allowAmbiguousCommands = true; - String value = System.getProperty("jdk.lang.Process.allowAmbiguousCommands"); - if (value != null) - allowAmbiguousCommands = !"false".equalsIgnoreCase(value); - } - if (allowAmbiguousCommands) { + final SecurityManager security = System.getSecurityManager(); + final String value = GetPropertyAction. + privilegedGetProperty("jdk.lang.Process.allowAmbiguousCommands", + (security == null ? "true" : "false")); + final boolean allowAmbiguousCommands = !"false".equalsIgnoreCase(value); + + if (allowAmbiguousCommands && security == null) { // Legacy mode. // Normalize path if possible. @@ -408,11 +465,12 @@ private ProcessImpl(String cmd[], // Quotation protects from interpretation of the [path] argument as // start of longer path with spaces. Quotation has no influence to // [.exe] extension heuristic. + boolean isShell = allowAmbiguousCommands ? isShellFile(executablePath) + : !isExe(executablePath); cmdstr = createCommandLine( - // We need the extended verification procedure for CMD files. - isShellFile(executablePath) - ? VERIFICATION_CMD_BAT - : VERIFICATION_WIN32, + // We need the extended verification procedures + isShell ? VERIFICATION_CMD_BAT + : (allowAmbiguousCommands ? VERIFICATION_WIN32 : VERIFICATION_WIN32_SAFE), quoteString(executablePath), cmd); } diff --git a/src/java.desktop/share/classes/java/awt/Font.java b/src/java.desktop/share/classes/java/awt/Font.java index 55171679cd6..e8d6f001083 100644 --- a/src/java.desktop/share/classes/java/awt/Font.java +++ b/src/java.desktop/share/classes/java/awt/Font.java @@ -1936,6 +1936,7 @@ private void readObject(java.io.ObjectInputStream s) // value is the default. if (fRequestedAttributes != null) { + try { values = getAttributeValues(); // init AttributeValues extras = AttributeValues.fromSerializableHashtable(fRequestedAttributes); @@ -1945,10 +1946,13 @@ private void readObject(java.io.ObjectInputStream s) values = getAttributeValues().merge(extras); this.nonIdentityTx = values.anyNonDefault(EXTRA_MASK); this.hasLayoutAttributes = values.anyNonDefault(LAYOUT_MASK); - + } catch (Throwable t) { + throw new IOException(t); + } finally { fRequestedAttributes = null; // don't need it any more } } + } /** * Returns the number of glyphs in this {@code Font}. Glyph codes diff --git a/src/java.desktop/share/classes/sun/font/CMap.java b/src/java.desktop/share/classes/sun/font/CMap.java index ae31082a8b8..0e9bddb8ec9 100644 --- a/src/java.desktop/share/classes/sun/font/CMap.java +++ b/src/java.desktop/share/classes/sun/font/CMap.java @@ -130,7 +130,7 @@ abstract class CMap { static final char noSuchChar = (char)0xfffd; static final int SHORTMASK = 0x0000ffff; - static final int INTMASK = 0xffffffff; + static final int INTMASK = 0x7fffffff; static final char[][] converterMaps = new char[7][]; @@ -919,7 +919,11 @@ static class CMapFormat8 extends CMap { bbuffer.position(12); bbuffer.get(is32); - nGroups = bbuffer.getInt(); + nGroups = bbuffer.getInt() & INTMASK; + // A map group record is three uint32's making for 12 bytes total + if (bbuffer.remaining() < (12 * (long)nGroups)) { + throw new RuntimeException("Format 8 table exceeded"); + } startCharCode = new int[nGroups]; endCharCode = new int[nGroups]; startGlyphID = new int[nGroups]; @@ -947,9 +951,13 @@ static class CMapFormat10 extends CMap { CMapFormat10(ByteBuffer bbuffer, int offset, char[] xlat) { + bbuffer.position(offset+12); firstCode = bbuffer.getInt() & INTMASK; entryCount = bbuffer.getInt() & INTMASK; - bbuffer.position(offset+20); + // each glyph is a uint16, so 2 bytes per value. + if (bbuffer.remaining() < (2 * (long)entryCount)) { + throw new RuntimeException("Format 10 table exceeded"); + } CharBuffer buffer = bbuffer.asCharBuffer(); glyphIdArray = new char[entryCount]; for (int i=0; i< entryCount; i++) { @@ -989,11 +997,15 @@ static class CMapFormat12 extends CMap { throw new RuntimeException("xlat array for cmap fmt=12"); } - numGroups = buffer.getInt(offset+12); + buffer.position(offset+12); + numGroups = buffer.getInt() & INTMASK; + // A map group record is three uint32's making for 12 bytes total + if (buffer.remaining() < (12 * (long)numGroups)) { + throw new RuntimeException("Format 12 table exceeded"); + } startCharCode = new long[numGroups]; endCharCode = new long[numGroups]; startGlyphID = new int[numGroups]; - buffer.position(offset+16); buffer = buffer.slice(); IntBuffer ibuffer = buffer.asIntBuffer(); for (int i=0; i 0) { buffer.position(offset+tableOffset); numUVSMapping[i] = buffer.getInt() & INTMASK; + // a UVS mapping record is one 3 byte int + uint16 + // making for 5 bytes per record. + if (buffer.remaining() < (5 * (long)numUVSMapping[i])) { + throw new RuntimeException("Variations exceed buffer"); + } unicodeValue[i] = new int[numUVSMapping[i]]; glyphID[i] = new char[numUVSMapping[i]]; diff --git a/src/java.desktop/share/classes/sun/font/FileFont.java b/src/java.desktop/share/classes/sun/font/FileFont.java index 6764c309851..42f38206b2c 100644 --- a/src/java.desktop/share/classes/sun/font/FileFont.java +++ b/src/java.desktop/share/classes/sun/font/FileFont.java @@ -172,7 +172,7 @@ synchronized void deregisterFontAndClearStrikeCache() { } } if (scaler != null) { - scaler.dispose(); + scaler.disposeScaler(); } scaler = FontScaler.getNullScaler(); } diff --git a/src/java.desktop/share/classes/sun/font/FontScaler.java b/src/java.desktop/share/classes/sun/font/FontScaler.java index 566170f2f69..690f42c4a7d 100644 --- a/src/java.desktop/share/classes/sun/font/FontScaler.java +++ b/src/java.desktop/share/classes/sun/font/FontScaler.java @@ -173,6 +173,12 @@ abstract GeneralPath getGlyphVectorOutline(long pScalerContext, int[] glyphs, scaler context objects! */ public void dispose() {} + /** + * Used when the native resources held by the scaler need + * to be released before the 2D disposer runs. + */ + public void disposeScaler() {} + /* At the moment these 3 methods are needed for Type1 fonts only. * For Truetype fonts we extract required info outside of scaler * on java layer. diff --git a/src/java.desktop/share/classes/sun/font/FreetypeFontScaler.java b/src/java.desktop/share/classes/sun/font/FreetypeFontScaler.java index a7413d0a7b8..b6f309d1e05 100644 --- a/src/java.desktop/share/classes/sun/font/FreetypeFontScaler.java +++ b/src/java.desktop/share/classes/sun/font/FreetypeFontScaler.java @@ -167,6 +167,9 @@ synchronized long getLayoutTableCache() throws FontScalerException { return getLayoutTableCacheNative(nativeScaler); } + /* This method should not be called directly, in case + * it is being invoked from a thread with a native context. + */ public synchronized void dispose() { if (nativeScaler != 0L) { disposeNativeScaler(font.get(), nativeScaler); @@ -174,6 +177,21 @@ public synchronized void dispose() { } } + public synchronized void disposeScaler() { + if (nativeScaler != 0L) { + /* + * The current thread may be calling this method from the context + * of a JNI up-call. It will hold the native lock from the + * original down-call so can directly enter dispose and free + * the resources. So we need to schedule the disposal to happen + * only once we've returned from native. So by running the dispose + * on another thread which does nothing except that disposal we + * are sure that this is safe. + */ + new Thread(null, () -> dispose(), "free scaler", 0, false).start(); + } + } + synchronized int getNumGlyphs() throws FontScalerException { if (nativeScaler != 0L) { return getNumGlyphsNative(nativeScaler); @@ -210,7 +228,7 @@ synchronized long getUnitsPerEm() { return getUnitsPerEMNative(nativeScaler); } - long createScalerContext(double[] matrix, + synchronized long createScalerContext(double[] matrix, int aa, int fm, float boldness, float italic, boolean disableHinting) { if (nativeScaler != 0L) { @@ -240,7 +258,7 @@ private native GeneralPath getGlyphOutlineNative(Font2D font, private native GeneralPath getGlyphVectorOutlineNative(Font2D font, long pScalerContext, long pScaler, int[] glyphs, int numGlyphs, float x, float y); - native Point2D.Float getGlyphPointNative(Font2D font, + private native Point2D.Float getGlyphPointNative(Font2D font, long pScalerContext, long pScaler, int glyphCode, int ptNumber); private native long getLayoutTableCacheNative(long pScaler); @@ -253,7 +271,7 @@ native Point2D.Float getGlyphPointNative(Font2D font, private native long getUnitsPerEMNative(long pScaler); - native long createScalerContextNative(long pScaler, double[] matrix, + private native long createScalerContextNative(long pScaler, double[] matrix, int aa, int fm, float boldness, float italic); /* Freetype scaler context does not contain any pointers that diff --git a/src/java.desktop/share/classes/sun/font/GlyphList.java b/src/java.desktop/share/classes/sun/font/GlyphList.java index 6d124869cd4..f7abe09f57d 100644 --- a/src/java.desktop/share/classes/sun/font/GlyphList.java +++ b/src/java.desktop/share/classes/sun/font/GlyphList.java @@ -303,6 +303,14 @@ public int[] getBounds() { */ public void setGlyphIndex(int i) { glyphindex = i; + if (images[i] == 0L) { + metrics[0] = (int)gposx; + metrics[1] = (int)gposy; + metrics[2] = 0; + metrics[3] = 0; + metrics[4] = 0; + return; + } float gx = StrikeCache.unsafe.getFloat(images[i]+StrikeCache.topLeftXOffset); float gy = @@ -341,6 +349,9 @@ public byte[] getGrayBits() { graybits = new byte[len]; } } + if (images[glyphindex] == 0L) { + return graybits; + } long pixelDataAddress = StrikeCache.unsafe.getAddress(images[glyphindex] + StrikeCache.pixelDataOffset); @@ -448,6 +459,9 @@ private void fillBounds(int[] bounds) { char gw, gh; float gx, gy, gx0, gy0, gx1, gy1; for (int i=0; i data.length) { + if (offset < 0 || length < 0 || offset + length < length || + offset + length > data.length) { throw new ArrayIndexOutOfBoundsException("bad offset/length"); } if (font.hasLayoutAttributes()) { @@ -3053,7 +3054,8 @@ public void drawBytes(byte data[], int offset, int length, int x, int y) { if (data == null) { throw new NullPointerException("byte data is null"); } - if (offset < 0 || length < 0 || offset + length > data.length) { + if (offset < 0 || length < 0 || offset + length < length || + offset + length > data.length) { throw new ArrayIndexOutOfBoundsException("bad offset/length"); } /* Byte data is interpreted as 8-bit ASCII. Re-use drawChars loops */ diff --git a/src/java.desktop/share/native/common/java2d/opengl/OGLBlitLoops.c b/src/java.desktop/share/native/common/java2d/opengl/OGLBlitLoops.c index c96791f76cc..8e577e11788 100644 --- a/src/java.desktop/share/native/common/java2d/opengl/OGLBlitLoops.c +++ b/src/java.desktop/share/native/common/java2d/opengl/OGLBlitLoops.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -208,21 +208,22 @@ OGLBlitSwToSurface(OGLContext *oglc, SurfaceDataRasInfo *srcInfo, j2d_glPixelZoom(scalex, -scaley); + GLvoid *pSrc = PtrCoord(srcInfo->rasBase, sx1, srcInfo->pixelStride, + sy1, srcInfo->scanStride); + // in case pixel stride is not a multiple of scanline stride the copy // has to be done line by line (see 6207877) if (srcInfo->scanStride % srcInfo->pixelStride != 0) { jint width = sx2-sx1; jint height = sy2-sy1; - GLvoid *pSrc = srcInfo->rasBase; - while (height > 0) { j2d_glDrawPixels(width, 1, pf->format, pf->type, pSrc); - j2d_glBitmap(0, 0, 0, 0, (GLfloat)0, (GLfloat)-1, NULL); + j2d_glBitmap(0, 0, 0, 0, (GLfloat)0, (GLfloat)-scaley, NULL); pSrc = PtrAddBytes(pSrc, srcInfo->scanStride); height--; } } else { - j2d_glDrawPixels(sx2-sx1, sy2-sy1, pf->format, pf->type, srcInfo->rasBase); + j2d_glDrawPixels(sx2-sx1, sy2-sy1, pf->format, pf->type, pSrc); } j2d_glPixelZoom(1.0, 1.0); @@ -317,12 +318,11 @@ OGLBlitToSurfaceViaTexture(OGLContext *oglc, SurfaceDataRasInfo *srcInfo, ty2 = ((GLdouble)sh) / th; if (swsurface) { + GLvoid *pSrc = PtrCoord(srcInfo->rasBase, + sx, srcInfo->pixelStride, + sy, srcInfo->scanStride); if (slowPath) { jint tmph = sh; - GLvoid *pSrc = PtrCoord(srcInfo->rasBase, - sx, srcInfo->pixelStride, - sy, srcInfo->scanStride); - while (tmph > 0) { j2d_glTexSubImage2D(GL_TEXTURE_2D, 0, 0, sh - tmph, sw, 1, @@ -332,16 +332,10 @@ OGLBlitToSurfaceViaTexture(OGLContext *oglc, SurfaceDataRasInfo *srcInfo, tmph--; } } else { - j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, sx); - j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, sy); - j2d_glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, sw, sh, pf->format, pf->type, - srcInfo->rasBase); - - j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); - j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); + pSrc); } // the texture image is "right side up", so we align the @@ -638,8 +632,9 @@ OGLBlitLoops_Blit(JNIEnv *env, J2dTraceLn4(J2D_TRACE_VERBOSE, " dx1=%f dy1=%f dx2=%f dy2=%f", dx1, dy1, dx2, dy2); - j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, sx1); - j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, sy1); + // Note: we will calculate x/y positions in the raster manually + j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); + j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, srcInfo.scanStride / srcInfo.pixelStride); j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, pf.alignment); @@ -696,8 +691,6 @@ OGLBlitLoops_Blit(JNIEnv *env, } } - j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); - j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, 4); } @@ -717,8 +710,8 @@ void flip(void *pDst, juint w, juint h, jint scanStride, jboolean convert) { juint step = 0; // vertical flip and convert argbpre to argb if necessary for (; i < h / 2; ++i) { - juint *r1 = PtrAddBytes(pDst, (i * scanStride)); - juint *r2 = PtrAddBytes(pDst, (h - i - 1) * scanStride); + juint *r1 = PtrPixelsRow(pDst, i, scanStride); + juint *r2 = PtrPixelsRow(pDst, h - i - 1, scanStride); if (tempRow) { // fast path memcpy(tempRow, r1, clippedStride); @@ -740,7 +733,7 @@ void flip(void *pDst, juint w, juint h, jint scanStride, jboolean convert) { } // convert the middle line if necessary if (convert && h % 2) { - juint *r1 = PtrAddBytes(pDst, (i * scanStride)); + juint *r1 = PtrPixelsRow(pDst, i, scanStride); for (step = 0; step < w; ++step) { LoadIntArgbPreTo1IntArgb(r1, 0, step, r1[step]); } @@ -813,7 +806,7 @@ OGLBlitLoops_SurfaceToSwBlit(JNIEnv *env, OGLContext *oglc, height = srcInfo.bounds.y2 - srcInfo.bounds.y1; pDst = PtrAddBytes(pDst, dstx * dstInfo.pixelStride); - pDst = PtrAddBytes(pDst, dsty * dstInfo.scanStride); + pDst = PtrPixelsRow(pDst, dsty, dstInfo.scanStride); j2d_glPixelStorei(GL_PACK_ROW_LENGTH, dstInfo.scanStride / dstInfo.pixelStride); diff --git a/src/java.desktop/share/native/libawt/java2d/loops/GraphicsPrimitiveMgr.h b/src/java.desktop/share/native/libawt/java2d/loops/GraphicsPrimitiveMgr.h index 58e203dc0cb..788ba931da2 100644 --- a/src/java.desktop/share/native/libawt/java2d/loops/GraphicsPrimitiveMgr.h +++ b/src/java.desktop/share/native/libawt/java2d/loops/GraphicsPrimitiveMgr.h @@ -490,6 +490,8 @@ extern struct _CompositeTypes { #define PtrCoord(p, x, xinc, y, yinc) PtrAddBytes(p, \ ((ptrdiff_t)(y))*(yinc) + \ ((ptrdiff_t)(x))*(xinc)) +#define PtrPixelsRow(p, y, scanStride) PtrAddBytes(p, \ + ((intptr_t) (y)) * (scanStride)) /* * The function to call with an array of NativePrimitive structures diff --git a/src/java.desktop/share/native/libawt/java2d/loops/LoopMacros.h b/src/java.desktop/share/native/libawt/java2d/loops/LoopMacros.h index d9019d83111..5a353e62cd3 100644 --- a/src/java.desktop/share/native/libawt/java2d/loops/LoopMacros.h +++ b/src/java.desktop/share/native/libawt/java2d/loops/LoopMacros.h @@ -137,7 +137,7 @@ do { \ juint w = WIDTH; \ jint tmpsxloc = SXLOC; \ - SRCPTR = PtrAddBytes(SRCBASE, ((SYLOC >> SHIFT) * srcScan)); \ + SRCPTR = PtrPixelsRow(SRCBASE, (SYLOC >> SHIFT), srcScan); \ Init ## DSTTYPE ## StoreVarsX(DSTPREFIX, DSTINFO); \ do { \ jint XVAR = (tmpsxloc >> SHIFT); \ @@ -2067,7 +2067,7 @@ void NAME_TRANSFORMHELPER_NN(SRC)(SurfaceDataRasInfo *pSrcInfo, \ \ Init ## SRC ## LoadVars(SrcRead, pSrcInfo); \ while (pRGB < pEnd) { \ - SRC ## DataType *pRow = PtrAddBytes(pBase, WholeOfLong(ylong) * scan); \ + SRC ## DataType *pRow = PtrPixelsRow(pBase, WholeOfLong(ylong), scan); \ Copy ## SRC ## ToIntArgbPre(pRGB, 0, \ SrcRead, pRow, WholeOfLong(xlong)); \ pRGB++; \ @@ -2115,7 +2115,7 @@ void NAME_TRANSFORMHELPER_BL(SRC)(SurfaceDataRasInfo *pSrcInfo, \ ydelta &= scan; \ \ xwhole += cx; \ - pRow = PtrAddBytes(pSrcInfo->rasBase, (ywhole + cy) * scan); \ + pRow = PtrPixelsRow(pSrcInfo->rasBase, ywhole + cy, scan); \ Copy ## SRC ## ToIntArgbPre(pRGB, 0, SrcRead, pRow, xwhole); \ Copy ## SRC ## ToIntArgbPre(pRGB, 1, SrcRead, pRow, xwhole+xdelta); \ pRow = PtrAddBytes(pRow, ydelta); \ @@ -2173,7 +2173,7 @@ void NAME_TRANSFORMHELPER_BC(SRC)(SurfaceDataRasInfo *pSrcInfo, \ ydelta1 += (isneg & -scan); \ \ xwhole += cx; \ - pRow = PtrAddBytes(pSrcInfo->rasBase, (ywhole + cy) * scan); \ + pRow = PtrPixelsRow(pSrcInfo->rasBase, ywhole + cy, scan); \ pRow = PtrAddBytes(pRow, ydelta0); \ Copy ## SRC ## ToIntArgbPre(pRGB, 0, SrcRead, pRow, xwhole+xdelta0); \ Copy ## SRC ## ToIntArgbPre(pRGB, 1, SrcRead, pRow, xwhole ); \ diff --git a/src/java.desktop/share/native/libfontmanager/DrawGlyphList.c b/src/java.desktop/share/native/libfontmanager/DrawGlyphList.c index c4dcdf99f60..0db65e3a9db 100644 --- a/src/java.desktop/share/native/libfontmanager/DrawGlyphList.c +++ b/src/java.desktop/share/native/libfontmanager/DrawGlyphList.c @@ -532,6 +532,12 @@ GlyphBlitVector* setupLCDBlitVector(JNIEnv *env, jobject glyphlist) { */ if (subPixPos && len > 0) { ginfo = (GlyphInfo*)imagePtrs[0]; + if (ginfo == NULL) { + (*env)->ReleasePrimitiveArrayCritical(env, glyphImages, + imagePtrs, JNI_ABORT); + free(gbv); + return (GlyphBlitVector*)NULL; + } /* rowBytes==width tests if its a B&W or LCD glyph */ if (ginfo->width == ginfo->rowBytes) { subPixPos = JNI_FALSE; @@ -561,6 +567,12 @@ GlyphBlitVector* setupLCDBlitVector(JNIEnv *env, jobject glyphlist) { jfloat px, py; ginfo = (GlyphInfo*)imagePtrs[g]; + if (ginfo == NULL) { + (*env)->ReleasePrimitiveArrayCritical(env, glyphImages, + imagePtrs, JNI_ABORT); + free(gbv); + return (GlyphBlitVector*)NULL; + } gbv->glyphs[g].glyphInfo = ginfo; gbv->glyphs[g].pixels = ginfo->image; gbv->glyphs[g].width = ginfo->width; @@ -636,6 +648,12 @@ GlyphBlitVector* setupLCDBlitVector(JNIEnv *env, jobject glyphlist) { } else { for (g=0; gReleasePrimitiveArrayCritical(env, glyphImages, + imagePtrs, JNI_ABORT); + free(gbv); + return (GlyphBlitVector*)NULL; + } gbv->glyphs[g].glyphInfo = ginfo; gbv->glyphs[g].pixels = ginfo->image; gbv->glyphs[g].width = ginfo->width; diff --git a/src/java.desktop/share/native/libfontmanager/freetypeScaler.c b/src/java.desktop/share/native/libfontmanager/freetypeScaler.c index 13fc86a6288..014074b050b 100644 --- a/src/java.desktop/share/native/libfontmanager/freetypeScaler.c +++ b/src/java.desktop/share/native/libfontmanager/freetypeScaler.c @@ -150,7 +150,31 @@ static unsigned long ReadTTFontFileFunc(FT_Stream stream, jobject bBuffer; int bread = 0; - if (numBytes == 0) return 0; + /* A call with numBytes == 0 is a seek. It should return 0 if the + * seek position is within the file and non-zero otherwise. + * For all other cases, ie numBytes !=0, return the number of bytes + * actually read. This applies to truncated reads and also failed reads. + */ + + if (numBytes == 0) { + if (offset >= scalerInfo->fileSize) { + return -1; + } else { + return 0; + } + } + + if (offset + numBytes < offset) { + return 0; // ft should not do this, but just in case. + } + + if (offset >= scalerInfo->fileSize) { + return 0; + } + + if (offset + numBytes > scalerInfo->fileSize) { + numBytes = scalerInfo->fileSize - offset; + } /* Large reads will bypass the cache and data copying */ if (numBytes > FILEDATACACHESIZE) { @@ -160,7 +184,11 @@ static unsigned long ReadTTFontFileFunc(FT_Stream stream, scalerInfo->font2D, sunFontIDs.ttReadBlockMID, bBuffer, offset, numBytes); - return bread; + if (bread < 0) { + return 0; + } else { + return bread; + } } else { /* We probably hit bug 4845371. For reasons that * are currently unclear, the call stacks after the initial @@ -175,9 +203,18 @@ static unsigned long ReadTTFontFileFunc(FT_Stream stream, (*env)->CallObjectMethod(env, scalerInfo->font2D, sunFontIDs.ttReadBytesMID, offset, numBytes); - (*env)->GetByteArrayRegion(env, byteArray, - 0, numBytes, (jbyte*)destBuffer); - return numBytes; + /* If there's an OutofMemoryError then byteArray will be null */ + if (byteArray == NULL) { + return 0; + } else { + jsize len = (*env)->GetArrayLength(env, byteArray); + if (len < numBytes) { + numBytes = len; // don't get more bytes than there are .. + } + (*env)->GetByteArrayRegion(env, byteArray, + 0, numBytes, (jbyte*)destBuffer); + return numBytes; + } } } /* Do we have a cache hit? */ else if (scalerInfo->fontDataOffset <= offset && @@ -199,6 +236,11 @@ static unsigned long ReadTTFontFileFunc(FT_Stream stream, sunFontIDs.ttReadBlockMID, bBuffer, offset, scalerInfo->fontDataLength); + if (bread <= 0) { + return 0; + } else if (bread < numBytes) { + numBytes = bread; + } memcpy(destBuffer, scalerInfo->fontData, numBytes); return numBytes; } @@ -541,16 +583,17 @@ Java_sun_font_FreetypeFontScaler_getGlyphAdvanceNative( to avoid unnecesary work with bitmaps. */ GlyphInfo *info; - jfloat advance; + jfloat advance = 0.0f; jlong image; image = Java_sun_font_FreetypeFontScaler_getGlyphImageNative( env, scaler, font2D, pScalerContext, pScaler, glyphCode); info = (GlyphInfo*) jlong_to_ptr(image); - advance = info->advanceX; - - free(info); + if (info != NULL) { + advance = info->advanceX; + free(info); + } return advance; } @@ -688,6 +731,13 @@ static void CopyFTSubpixelVToSubpixel(const void* srcImage, int srcRowBytes, } +/* JDK does not use glyph images for fonts with a + * pixel size > 100 (see THRESHOLD in OutlineTextRenderer.java) + * so if the glyph bitmap image dimension is > 1024 pixels, + * something is up. + */ +#define MAX_GLYPH_DIM 1024 + /* * Class: sun_font_FreetypeFontScaler * Method: getGlyphImageNative @@ -764,6 +814,14 @@ Java_sun_font_FreetypeFontScaler_getGlyphImageNative( /* generate bitmap if it is not done yet e.g. if algorithmic styling is performed and style was added to outline */ if (ftglyph->format == FT_GLYPH_FORMAT_OUTLINE) { + FT_BBox bbox; + FT_Outline_Get_CBox(&(ftglyph->outline), &bbox); + int w = (int)((bbox.xMax>>6)-(bbox.xMin>>6)); + int h = (int)((bbox.yMax>>6)-(bbox.yMin>>6)); + if (w > MAX_GLYPH_DIM || h > MAX_GLYPH_DIM) { + glyphInfo = getNullGlyphImage(); + return ptr_to_jlong(glyphInfo); + } error = FT_Render_Glyph(ftglyph, FT_LOAD_TARGET_MODE(target)); if (error != 0) { return ptr_to_jlong(getNullGlyphImage()); @@ -772,6 +830,11 @@ Java_sun_font_FreetypeFontScaler_getGlyphImageNative( width = (UInt16) ftglyph->bitmap.width; height = (UInt16) ftglyph->bitmap.rows; + if (width > MAX_GLYPH_DIM || height > MAX_GLYPH_DIM) { + glyphInfo = getNullGlyphImage(); + return ptr_to_jlong(glyphInfo); + } + imageSize = width*height; glyphInfo = (GlyphInfo*) malloc(sizeof(GlyphInfo) + imageSize); diff --git a/src/java.desktop/share/native/libfontmanager/hb-jdk-font.cc b/src/java.desktop/share/native/libfontmanager/hb-jdk-font.cc index 1c7eed0ab0e..2563f014557 100644 --- a/src/java.desktop/share/native/libfontmanager/hb-jdk-font.cc +++ b/src/java.desktop/share/native/libfontmanager/hb-jdk-font.cc @@ -339,6 +339,9 @@ reference_table(hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) { } length = env->GetArrayLength(tableBytes); buffer = calloc(length, sizeof(jbyte)); + if (buffer == NULL) { + return NULL; + } env->GetByteArrayRegion(tableBytes, 0, length, (jbyte*)buffer); if (cacheIdx >= LAYOUTCACHE_ENTRIES) { // not a cacheable table diff --git a/src/java.desktop/unix/classes/sun/font/XRGlyphCache.java b/src/java.desktop/unix/classes/sun/font/XRGlyphCache.java index 125721bd531..f1444128712 100644 --- a/src/java.desktop/unix/classes/sun/font/XRGlyphCache.java +++ b/src/java.desktop/unix/classes/sun/font/XRGlyphCache.java @@ -114,6 +114,9 @@ public XRGlyphCacheEntry[] cacheGlyphs(GlyphList glyphList) { for (int i = 0; i < glyphList.getNumGlyphs(); i++) { XRGlyphCacheEntry glyph; + if (imgPtrs[i] == 0L) { + continue; + } // Find uncached glyphs and queue them for upload if ((glyph = getEntryForPointer(imgPtrs[i])) == null) { glyph = new XRGlyphCacheEntry(imgPtrs[i], glyphList); diff --git a/src/java.desktop/unix/classes/sun/font/XRTextRenderer.java b/src/java.desktop/unix/classes/sun/font/XRTextRenderer.java index e4ee3cf071e..07905e2e21b 100644 --- a/src/java.desktop/unix/classes/sun/font/XRTextRenderer.java +++ b/src/java.desktop/unix/classes/sun/font/XRTextRenderer.java @@ -88,6 +88,9 @@ protected void drawGlyphList(SunGraphics2D sg2d, GlyphList gl) { for (int i = 0; i < gl.getNumGlyphs(); i++) { gl.setGlyphIndex(i); XRGlyphCacheEntry cacheEntry = cachedGlyphs[i]; + if (cacheEntry == null) { + continue; + } eltList.getGlyphs().addInt(cacheEntry.getGlyphID()); int glyphSet = cacheEntry.getGlyphSet(); diff --git a/src/java.desktop/unix/native/common/java2d/x11/X11FontScaler_md.c b/src/java.desktop/unix/native/common/java2d/x11/X11FontScaler_md.c index 745a65f53a3..2ab6f287b69 100644 --- a/src/java.desktop/unix/native/common/java2d/x11/X11FontScaler_md.c +++ b/src/java.desktop/unix/native/common/java2d/x11/X11FontScaler_md.c @@ -273,6 +273,7 @@ JNIEXPORT jlong JNICALL AWTFontGenerateImage(AWTFont pFont, AWTChar2b* xChar) { unsigned int imageSize; JNIEnv *env; + FONT_AWT_LOCK(); /* XTextExtents16(xFont, xChar, 1, &direction, &ascent, &descent, &xcs); */ XQueryTextExtents16(awt_display,xFont->fid, xChar, 1, @@ -280,8 +281,11 @@ JNIEXPORT jlong JNICALL AWTFontGenerateImage(AWTFont pFont, AWTChar2b* xChar) { width = xcs.rbearing - xcs.lbearing; height = xcs.ascent+xcs.descent; imageSize = width*height; - glyphInfo = (GlyphInfo*)malloc(sizeof(GlyphInfo)+imageSize); + if (glyphInfo == NULL) { + AWT_UNLOCK(); + return (jlong)(uintptr_t)NULL; + } glyphInfo->cellInfo = NULL; glyphInfo->width = width; glyphInfo->height = height; diff --git a/src/java.desktop/windows/native/libawt/java2d/d3d/D3DContext.cpp b/src/java.desktop/windows/native/libawt/java2d/d3d/D3DContext.cpp index a847b838265..7ebd8965d13 100644 --- a/src/java.desktop/windows/native/libawt/java2d/d3d/D3DContext.cpp +++ b/src/java.desktop/windows/native/libawt/java2d/d3d/D3DContext.cpp @@ -1150,7 +1150,9 @@ D3DContext::UploadTileToTexture(D3DResource *pTextureRes, void *pixels, { #ifndef PtrAddBytes #define PtrAddBytes(p, b) ((void *) (((intptr_t) (p)) + (b))) -#define PtrCoord(p, x, xinc, y, yinc) PtrAddBytes(p, (y)*(yinc) + (x)*(xinc)) +#define PtrCoord(p, x, xinc, y, yinc) PtrAddBytes(p, \ + ((ptrdiff_t)(y))*(yinc) + \ + ((ptrdiff_t)(x))*(xinc)) #endif // PtrAddBytes HRESULT res = S_OK; diff --git a/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl_Skel.java b/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl_Skel.java index 6807a328b1d..c0a06f1f017 100644 --- a/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl_Skel.java +++ b/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl_Skel.java @@ -27,13 +27,8 @@ package sun.rmi.registry; import java.io.IOException; -import java.io.InputStream; -import java.rmi.AccessException; -import java.rmi.server.RemoteCall; -import sun.rmi.transport.Connection; import sun.rmi.transport.StreamRemoteCall; -import sun.rmi.transport.tcp.TCPConnection; /** * Skeleton to dispatch RegistryImpl methods. @@ -56,7 +51,7 @@ public java.rmi.server.Operation[] getOperations() { return operations.clone(); } - public void dispatch(java.rmi.Remote obj, java.rmi.server.RemoteCall call, int opnum, long hash) + public void dispatch(java.rmi.Remote obj, java.rmi.server.RemoteCall remoteCall, int opnum, long hash) throws java.lang.Exception { if (opnum < 0) { if (hash == 7583982177005850366L) { @@ -78,6 +73,7 @@ public void dispatch(java.rmi.Remote obj, java.rmi.server.RemoteCall call, int o } sun.rmi.registry.RegistryImpl server = (sun.rmi.registry.RegistryImpl) obj; + StreamRemoteCall call = (StreamRemoteCall) remoteCall; switch (opnum) { case 0: // bind(String, Remote) { @@ -90,7 +86,8 @@ public void dispatch(java.rmi.Remote obj, java.rmi.server.RemoteCall call, int o java.io.ObjectInput in = call.getInputStream(); $param_String_1 = (java.lang.String) in.readObject(); $param_Remote_2 = (java.rmi.Remote) in.readObject(); - } catch (java.io.IOException | java.lang.ClassNotFoundException e) { + } catch (ClassCastException | IOException | ClassNotFoundException e) { + call.discardPendingRefs(); throw new java.rmi.UnmarshalException("error unmarshalling arguments", e); } finally { call.releaseInputStream(); @@ -123,7 +120,8 @@ public void dispatch(java.rmi.Remote obj, java.rmi.server.RemoteCall call, int o try { java.io.ObjectInput in = call.getInputStream(); $param_String_1 = (java.lang.String) in.readObject(); - } catch (java.io.IOException | java.lang.ClassNotFoundException e) { + } catch (ClassCastException | IOException | ClassNotFoundException e) { + call.discardPendingRefs(); throw new java.rmi.UnmarshalException("error unmarshalling arguments", e); } finally { call.releaseInputStream(); @@ -149,7 +147,8 @@ public void dispatch(java.rmi.Remote obj, java.rmi.server.RemoteCall call, int o java.io.ObjectInput in = call.getInputStream(); $param_String_1 = (java.lang.String) in.readObject(); $param_Remote_2 = (java.rmi.Remote) in.readObject(); - } catch (java.io.IOException | java.lang.ClassNotFoundException e) { + } catch (ClassCastException | IOException | java.lang.ClassNotFoundException e) { + call.discardPendingRefs(); throw new java.rmi.UnmarshalException("error unmarshalling arguments", e); } finally { call.releaseInputStream(); @@ -172,7 +171,8 @@ public void dispatch(java.rmi.Remote obj, java.rmi.server.RemoteCall call, int o try { java.io.ObjectInput in = call.getInputStream(); $param_String_1 = (java.lang.String) in.readObject(); - } catch (java.io.IOException | java.lang.ClassNotFoundException e) { + } catch (ClassCastException | IOException | ClassNotFoundException e) { + call.discardPendingRefs(); throw new java.rmi.UnmarshalException("error unmarshalling arguments", e); } finally { call.releaseInputStream(); diff --git a/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl_Stub.java b/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl_Stub.java index f8574869147..9f82b61331c 100644 --- a/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl_Stub.java +++ b/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl_Stub.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 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,6 +24,11 @@ */ package sun.rmi.registry; + +import java.io.IOException; + +import sun.rmi.transport.StreamRemoteCall; + /** * Stubs to invoke RegistryImpl remote methods. * Originally generated from RMIC but frozen to match RegistryImpl_Skel. @@ -57,7 +62,7 @@ public RegistryImpl_Stub(java.rmi.server.RemoteRef ref) { public void bind(java.lang.String $param_String_1, java.rmi.Remote $param_Remote_2) throws java.rmi.AccessException, java.rmi.AlreadyBoundException, java.rmi.RemoteException { try { - java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 0, interfaceHash); + StreamRemoteCall call = (StreamRemoteCall)ref.newCall(this, operations, 0, interfaceHash); try { java.io.ObjectOutput out = call.getOutputStream(); out.writeObject($param_String_1); @@ -82,15 +87,14 @@ public void bind(java.lang.String $param_String_1, java.rmi.Remote $param_Remote public java.lang.String[] list() throws java.rmi.AccessException, java.rmi.RemoteException { try { - java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 1, interfaceHash); + StreamRemoteCall call = (StreamRemoteCall)ref.newCall(this, operations, 1, interfaceHash); ref.invoke(call); java.lang.String[] $result; try { java.io.ObjectInput in = call.getInputStream(); $result = (java.lang.String[]) in.readObject(); - } catch (java.io.IOException e) { - throw new java.rmi.UnmarshalException("error unmarshalling return", e); - } catch (java.lang.ClassNotFoundException e) { + } catch (ClassCastException | IOException | ClassNotFoundException e) { + call.discardPendingRefs(); throw new java.rmi.UnmarshalException("error unmarshalling return", e); } finally { ref.done(call); @@ -109,7 +113,7 @@ public java.lang.String[] list() public java.rmi.Remote lookup(java.lang.String $param_String_1) throws java.rmi.AccessException, java.rmi.NotBoundException, java.rmi.RemoteException { try { - java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 2, interfaceHash); + StreamRemoteCall call = (StreamRemoteCall)ref.newCall(this, operations, 2, interfaceHash); try { java.io.ObjectOutput out = call.getOutputStream(); out.writeObject($param_String_1); @@ -121,9 +125,8 @@ public java.rmi.Remote lookup(java.lang.String $param_String_1) try { java.io.ObjectInput in = call.getInputStream(); $result = (java.rmi.Remote) in.readObject(); - } catch (java.io.IOException e) { - throw new java.rmi.UnmarshalException("error unmarshalling return", e); - } catch (java.lang.ClassNotFoundException e) { + } catch (ClassCastException | IOException | ClassNotFoundException e) { + call.discardPendingRefs(); throw new java.rmi.UnmarshalException("error unmarshalling return", e); } finally { ref.done(call); @@ -144,7 +147,7 @@ public java.rmi.Remote lookup(java.lang.String $param_String_1) public void rebind(java.lang.String $param_String_1, java.rmi.Remote $param_Remote_2) throws java.rmi.AccessException, java.rmi.RemoteException { try { - java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 3, interfaceHash); + StreamRemoteCall call = (StreamRemoteCall)ref.newCall(this, operations, 3, interfaceHash); try { java.io.ObjectOutput out = call.getOutputStream(); out.writeObject($param_String_1); @@ -167,7 +170,7 @@ public void rebind(java.lang.String $param_String_1, java.rmi.Remote $param_Remo public void unbind(java.lang.String $param_String_1) throws java.rmi.AccessException, java.rmi.NotBoundException, java.rmi.RemoteException { try { - java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 4, interfaceHash); + StreamRemoteCall call = (StreamRemoteCall)ref.newCall(this, operations, 4, interfaceHash); try { java.io.ObjectOutput out = call.getOutputStream(); out.writeObject($param_String_1); diff --git a/src/java.rmi/share/classes/sun/rmi/transport/DGCImpl_Skel.java b/src/java.rmi/share/classes/sun/rmi/transport/DGCImpl_Skel.java index f991a6e0530..1b413cffc19 100644 --- a/src/java.rmi/share/classes/sun/rmi/transport/DGCImpl_Skel.java +++ b/src/java.rmi/share/classes/sun/rmi/transport/DGCImpl_Skel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 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,8 @@ package sun.rmi.transport; +import java.io.IOException; + /** * Skeleton to dispatch DGC methods. * Originally generated by RMIC but frozen to match the stubs. @@ -43,12 +45,13 @@ public java.rmi.server.Operation[] getOperations() { return operations.clone(); } - public void dispatch(java.rmi.Remote obj, java.rmi.server.RemoteCall call, int opnum, long hash) + public void dispatch(java.rmi.Remote obj, java.rmi.server.RemoteCall remoteCall, int opnum, long hash) throws java.lang.Exception { if (hash != interfaceHash) throw new java.rmi.server.SkeletonMismatchException("interface hash mismatch"); sun.rmi.transport.DGCImpl server = (sun.rmi.transport.DGCImpl) obj; + StreamRemoteCall call = (StreamRemoteCall) remoteCall; switch (opnum) { case 0: // clean(ObjID[], long, VMID, boolean) { @@ -62,9 +65,8 @@ public void dispatch(java.rmi.Remote obj, java.rmi.server.RemoteCall call, int o $param_long_2 = in.readLong(); $param_VMID_3 = (java.rmi.dgc.VMID) in.readObject(); $param_boolean_4 = in.readBoolean(); - } catch (java.io.IOException e) { - throw new java.rmi.UnmarshalException("error unmarshalling arguments", e); - } catch (java.lang.ClassNotFoundException e) { + } catch (ClassCastException | IOException | ClassNotFoundException e) { + call.discardPendingRefs(); throw new java.rmi.UnmarshalException("error unmarshalling arguments", e); } finally { call.releaseInputStream(); @@ -88,9 +90,8 @@ public void dispatch(java.rmi.Remote obj, java.rmi.server.RemoteCall call, int o $param_arrayOf_ObjID_1 = (java.rmi.server.ObjID[]) in.readObject(); $param_long_2 = in.readLong(); $param_Lease_3 = (java.rmi.dgc.Lease) in.readObject(); - } catch (java.io.IOException e) { - throw new java.rmi.UnmarshalException("error unmarshalling arguments", e); - } catch (java.lang.ClassNotFoundException e) { + } catch (ClassCastException | IOException | ClassNotFoundException e) { + call.discardPendingRefs(); throw new java.rmi.UnmarshalException("error unmarshalling arguments", e); } finally { call.releaseInputStream(); diff --git a/src/java.rmi/share/classes/sun/rmi/transport/DGCImpl_Stub.java b/src/java.rmi/share/classes/sun/rmi/transport/DGCImpl_Stub.java index cc44ff845a8..99880f3b3b0 100644 --- a/src/java.rmi/share/classes/sun/rmi/transport/DGCImpl_Stub.java +++ b/src/java.rmi/share/classes/sun/rmi/transport/DGCImpl_Stub.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 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,16 +25,17 @@ package sun.rmi.transport; +import sun.rmi.transport.tcp.TCPConnection; + +import java.io.IOException; import java.io.ObjectInputFilter; -import java.io.ObjectInputStream; +import java.rmi.RemoteException; import java.rmi.dgc.Lease; import java.rmi.dgc.VMID; import java.rmi.server.UID; import java.security.AccessController; import java.security.PrivilegedAction; - -import sun.rmi.server.UnicastRef; -import sun.rmi.transport.tcp.TCPConnection; +import java.util.ArrayList; /** * Stubs to invoke DGC remote methods. @@ -72,7 +73,9 @@ public DGCImpl_Stub(java.rmi.server.RemoteRef ref) { public void clean(java.rmi.server.ObjID[] $param_arrayOf_ObjID_1, long $param_long_2, java.rmi.dgc.VMID $param_VMID_3, boolean $param_boolean_4) throws java.rmi.RemoteException { try { - java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 0, interfaceHash); + StreamRemoteCall call = (StreamRemoteCall)ref.newCall((java.rmi.server.RemoteObject) this, + operations, 0, interfaceHash); + call.setObjectInputFilter(DGCImpl_Stub::leaseFilter); try { java.io.ObjectOutput out = call.getOutputStream(); out.writeObject($param_arrayOf_ObjID_1); @@ -97,7 +100,10 @@ public void clean(java.rmi.server.ObjID[] $param_arrayOf_ObjID_1, long $param_lo public java.rmi.dgc.Lease dirty(java.rmi.server.ObjID[] $param_arrayOf_ObjID_1, long $param_long_2, java.rmi.dgc.Lease $param_Lease_3) throws java.rmi.RemoteException { try { - java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 1, interfaceHash); + StreamRemoteCall call = + (StreamRemoteCall)ref.newCall((java.rmi.server.RemoteObject) this, + operations, 1, interfaceHash); + call.setObjectInputFilter(DGCImpl_Stub::leaseFilter); try { java.io.ObjectOutput out = call.getOutputStream(); out.writeObject($param_arrayOf_ObjID_1); @@ -108,26 +114,16 @@ public java.rmi.dgc.Lease dirty(java.rmi.server.ObjID[] $param_arrayOf_ObjID_1, } ref.invoke(call); java.rmi.dgc.Lease $result; - Connection connection = ((StreamRemoteCall) call).getConnection(); + Connection connection = call.getConnection(); try { java.io.ObjectInput in = call.getInputStream(); - - if (in instanceof ObjectInputStream) { - /** - * Set a filter on the stream for the return value. - */ - ObjectInputStream ois = (ObjectInputStream) in; - AccessController.doPrivileged((PrivilegedAction)() -> { - ois.setObjectInputFilter(DGCImpl_Stub::leaseFilter); - return null; - }); - } $result = (java.rmi.dgc.Lease) in.readObject(); - } catch (java.io.IOException | java.lang.ClassNotFoundException e) { + } catch (ClassCastException | IOException | ClassNotFoundException e) { if (connection instanceof TCPConnection) { // Modified to prevent re-use of the connection after an exception ((TCPConnection) connection).getChannel().free(connection, false); } + call.discardPendingRefs(); throw new java.rmi.UnmarshalException("error unmarshalling return", e); } finally { ref.done(call); @@ -146,6 +142,11 @@ public java.rmi.dgc.Lease dirty(java.rmi.server.ObjID[] $param_arrayOf_ObjID_1, * ObjectInputFilter to filter DGCClient return value (a Lease). * The list of acceptable classes is very short and explicit. * The depth and array sizes are limited. + *

+ * The filter must accept normal and exception returns. + * A DGC server may throw exceptions that may have a cause + * and suppressed exceptions. + * Only exceptions in {@code java.base} and {@code java.rmi} are allowed. * * @param filterInfo access to class, arrayLength, etc. * @return {@link ObjectInputFilter.Status#ALLOWED} if allowed, @@ -172,7 +173,14 @@ private static ObjectInputFilter.Status leaseFilter(ObjectInputFilter.FilterInfo } return (clazz == UID.class || clazz == VMID.class || - clazz == Lease.class) + clazz == Lease.class || + (Throwable.class.isAssignableFrom(clazz) && + (Object.class.getModule() == clazz.getModule() || + RemoteException.class.getModule() == clazz.getModule())) || + clazz == StackTraceElement.class || + clazz == ArrayList.class || // for suppressed exceptions, if any + clazz == Object.class || + clazz.getName().equals("java.util.Collections$EmptyList")) ? ObjectInputFilter.Status.ALLOWED : ObjectInputFilter.Status.REJECTED; } diff --git a/src/java.rmi/share/classes/sun/rmi/transport/StreamRemoteCall.java b/src/java.rmi/share/classes/sun/rmi/transport/StreamRemoteCall.java index d0a0ced0404..2f1c981da5b 100644 --- a/src/java.rmi/share/classes/sun/rmi/transport/StreamRemoteCall.java +++ b/src/java.rmi/share/classes/sun/rmi/transport/StreamRemoteCall.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -29,6 +29,7 @@ import java.io.DataOutputStream; import java.io.IOException; import java.io.ObjectInput; +import java.io.ObjectInputFilter; import java.io.ObjectOutput; import java.io.StreamCorruptedException; import java.rmi.RemoteException; @@ -36,6 +37,9 @@ import java.rmi.UnmarshalException; import java.rmi.server.ObjID; import java.rmi.server.RemoteCall; +import java.security.AccessController; +import java.security.PrivilegedAction; + import sun.rmi.runtime.Log; import sun.rmi.server.UnicastRef; import sun.rmi.transport.tcp.TCPEndpoint; @@ -50,6 +54,7 @@ public class StreamRemoteCall implements RemoteCall { private ConnectionInputStream in = null; private ConnectionOutputStream out = null; private Connection conn; + private ObjectInputFilter filter = null; private boolean resultStarted = false; private Exception serverException = null; @@ -123,6 +128,13 @@ public void releaseOutputStream() throws IOException { } } + public void setObjectInputFilter(ObjectInputFilter filter) { + if (in != null) { + throw new IllegalStateException("set filter must occur before calling getInputStream"); + } + this.filter = filter; + } + /** * Get the InputStream the stub/skeleton should get results/arguments * from. @@ -132,6 +144,12 @@ public ObjectInput getInputStream() throws IOException { Transport.transportLog.log(Log.VERBOSE, "getting input stream"); in = new ConnectionInputStream(conn.getInputStream()); + if (filter != null) { + AccessController.doPrivileged((PrivilegedAction) () -> { + in.setObjectInputFilter(filter); + return null; + }); + } } return in; } @@ -251,6 +269,7 @@ public void executeCall() throws Exception { try { ex = in.readObject(); } catch (Exception e) { + discardPendingRefs(); throw new UnmarshalException("Error unmarshaling return", e); } @@ -259,6 +278,7 @@ public void executeCall() throws Exception { if (ex instanceof Exception) { exceptionReceivedFromServer((Exception) ex); } else { + discardPendingRefs(); throw new UnmarshalException("Return type not Exception"); } // Exception is thrown before fallthrough can occur diff --git a/src/java.security.jgss/macosx/native/libosxkrb5/nativeccache.c b/src/java.security.jgss/macosx/native/libosxkrb5/nativeccache.c index dc95524eb09..a4a9d6c8f57 100644 --- a/src/java.security.jgss/macosx/native/libosxkrb5/nativeccache.c +++ b/src/java.security.jgss/macosx/native/libosxkrb5/nativeccache.c @@ -261,6 +261,7 @@ JNIEXPORT jobject JNICALL Java_sun_security_krb5_Credentials_acquireDefaultNativ int netypes; jint *etypes = NULL; + int proxy_flag = 0; /* Initialize the Kerberos 5 context */ err = krb5_init_context (&kcontext); @@ -273,6 +274,48 @@ JNIEXPORT jobject JNICALL Java_sun_security_krb5_Credentials_acquireDefaultNativ err = krb5_cc_set_flags (kcontext, ccache, flags); /* turn off OPENCLOSE */ } + // First round read. The proxy_impersonator config flag is not supported. + // This ccache will not be used if this flag exists. + if (!err) { + err = krb5_cc_start_seq_get (kcontext, ccache, &cursor); + } + + if (!err) { + while ((err = krb5_cc_next_cred (kcontext, ccache, &cursor, &creds)) == 0) { + char *serverName = NULL; + + if (!err) { + err = krb5_unparse_name (kcontext, creds.server, &serverName); + printiferr (err, "while unparsing server name"); + } + + if (!err) { + if (!strcmp(serverName, "krb5_ccache_conf_data/proxy_impersonator@X-CACHECONF:")) { + proxy_flag = 1; + } + } + + if (serverName != NULL) { krb5_free_unparsed_name (kcontext, serverName); } + + krb5_free_cred_contents (kcontext, &creds); + + if (proxy_flag) break; + } + + if (err == KRB5_CC_END) { err = 0; } + printiferr (err, "while retrieving a ticket"); + } + + if (!err) { + err = krb5_cc_end_seq_get (kcontext, ccache, &cursor); + printiferr (err, "while finishing ticket retrieval"); + } + + if (proxy_flag) { + goto outer_cleanup; + } + // End of first round read + if (!err) { err = krb5_cc_start_seq_get (kcontext, ccache, &cursor); } @@ -400,6 +443,7 @@ JNIEXPORT jobject JNICALL Java_sun_security_krb5_Credentials_acquireDefaultNativ printiferr (err, "while finishing ticket retrieval"); } +outer_cleanup: if (!err) { flags = KRB5_TC_OPENCLOSE; /* restore OPENCLOSE mode */ err = krb5_cc_set_flags (kcontext, ccache, flags); diff --git a/src/java.security.jgss/share/classes/javax/security/auth/kerberos/JavaxSecurityAuthKerberosAccessImpl.java b/src/java.security.jgss/share/classes/javax/security/auth/kerberos/JavaxSecurityAuthKerberosAccessImpl.java index 9630c72eace..71cc0aa50ec 100644 --- a/src/java.security.jgss/share/classes/javax/security/auth/kerberos/JavaxSecurityAuthKerberosAccessImpl.java +++ b/src/java.security.jgss/share/classes/javax/security/auth/kerberos/JavaxSecurityAuthKerberosAccessImpl.java @@ -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 @@ -26,8 +26,6 @@ package javax.security.auth.kerberos; import sun.security.krb5.JavaxSecurityAuthKerberosAccess; -import sun.security.krb5.EncryptionKey; -import sun.security.krb5.PrincipalName; class JavaxSecurityAuthKerberosAccessImpl implements JavaxSecurityAuthKerberosAccess { @@ -35,4 +33,10 @@ public sun.security.krb5.internal.ktab.KeyTab keyTabTakeSnapshot( KeyTab ktab) { return ktab.takeSnapshot(); } + public KerberosTicket kerberosTicketGetProxy(KerberosTicket t) { + return t.proxy; + } + public void kerberosTicketSetProxy(KerberosTicket t, KerberosTicket p) { + t.proxy = p; + } } diff --git a/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KerberosTicket.java b/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KerberosTicket.java index aa14fe6b3b1..86135eb84ed 100644 --- a/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KerberosTicket.java +++ b/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KerberosTicket.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -29,11 +29,13 @@ import java.util.Date; import java.util.Arrays; import java.net.InetAddress; +import java.util.Objects; import javax.crypto.SecretKey; import javax.security.auth.Refreshable; import javax.security.auth.Destroyable; import javax.security.auth.RefreshFailedException; import javax.security.auth.DestroyFailedException; + import sun.security.util.HexDumpEncoder; /** @@ -190,9 +192,14 @@ public class KerberosTicket implements Destroyable, Refreshable, * @serial */ - private InetAddress[] clientAddresses; + /** + * Evidence ticket if proxy_impersonator. This field can be accessed + * by KerberosSecrets. It's serialized. + */ + KerberosTicket proxy = null; + private transient boolean destroyed = false; /** @@ -703,6 +710,7 @@ public String toString() { "Renew Till = " + String.valueOf(renewTill) + "\n" + "Client Addresses " + (clientAddresses == null ? " Null " : caddrString.toString() + + (proxy == null ? "" : "\nwith a proxy ticket") + "\n")); } @@ -740,6 +748,10 @@ public int hashCode() { // clientAddress may be null, the array's hashCode is 0 result = result * 37 + Arrays.hashCode(clientAddresses); + + if (proxy != null) { + result = result * 37 + proxy.hashCode(); + } return result * 37 + Arrays.hashCode(flags); } @@ -812,6 +824,10 @@ public boolean equals(Object other) { } } + if (!Objects.equals(proxy, otherTicket.proxy)) { + return false; + } + return true; } diff --git a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java index 7cdfa2be422..d50603f2ab7 100644 --- a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java +++ b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -617,6 +617,8 @@ public final byte[] initSecContext(InputStream is, int mechTokenSize) if (myCred == null) { myCred = Krb5InitCredential.getInstance(caller, myName, GSSCredential.DEFAULT_LIFETIME); + myCred = Krb5ProxyCredential.tryImpersonation( + caller, (Krb5InitCredential)myCred); } else if (!myCred.isInitiatorCredential()) { throw new GSSException(errorCode, -1, "No TGT available"); @@ -653,8 +655,8 @@ public KerberosTicket run() throws Exception { // highly consider just calling: // Subject.getSubject // SubjectComber.find - // instead of Krb5Util.getTicket - return Krb5Util.getTicket( + // instead of Krb5Util.getServiceTicket + return Krb5Util.getServiceTicket( GSSCaller.CALLER_UNKNOWN, // since it's useSubjectCredsOnly here, // don't worry about the null diff --git a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5InitCredential.java b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5InitCredential.java index 44a0c992a98..944dec09486 100644 --- a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5InitCredential.java +++ b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5InitCredential.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -55,6 +55,7 @@ public class Krb5InitCredential private Krb5NameElement name; private Credentials krb5Credentials; + public KerberosTicket proxyTicket; private Krb5InitCredential(Krb5NameElement name, byte[] asn1Encoding, @@ -153,7 +154,7 @@ static Krb5InitCredential getInstance(GSSCaller caller, Krb5NameElement name, Krb5MechFactory.NT_GSS_KRB5_PRINCIPAL); } - return new Krb5InitCredential(name, + Krb5InitCredential result = new Krb5InitCredential(name, tgt.getEncoded(), tgt.getClient(), tgt.getServer(), @@ -165,6 +166,9 @@ static Krb5InitCredential getInstance(GSSCaller caller, Krb5NameElement name, tgt.getEndTime(), tgt.getRenewTill(), tgt.getClientAddresses()); + result.proxyTicket = KerberosSecrets.getJavaxSecurityAuthKerberosAccess(). + kerberosTicketGetProxy(tgt); + return result; } static Krb5InitCredential getInstance(Krb5NameElement name, @@ -333,9 +337,9 @@ private static KerberosTicket getTgt(GSSCaller caller, Krb5NameElement name, public KerberosTicket run() throws Exception { // It's OK to use null as serverPrincipal. TGT is almost // the first ticket for a principal and we use list. - return Krb5Util.getTicket( + return Krb5Util.getInitialTicket( realCaller, - clientPrincipal, null, acc); + clientPrincipal, acc); }}); } catch (PrivilegedActionException e) { GSSException ge = diff --git a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5MechFactory.java b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5MechFactory.java index cc9626c14f7..d5cafea0445 100644 --- a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5MechFactory.java +++ b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5MechFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -124,6 +124,8 @@ public GSSCredentialSpi getCredentialElement(GSSNameSpi name, usage == GSSCredential.INITIATE_AND_ACCEPT) { credElement = Krb5InitCredential.getInstance (caller, (Krb5NameElement) name, initLifetime); + credElement = Krb5ProxyCredential.tryImpersonation( + caller, (Krb5InitCredential)credElement); checkInitCredPermission ((Krb5NameElement) credElement.getName()); } else if (usage == GSSCredential.ACCEPT_ONLY) { diff --git a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5NameElement.java b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5NameElement.java index 1d0217e9187..461e2481e5d 100644 --- a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5NameElement.java +++ b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5NameElement.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -144,7 +144,7 @@ static Krb5NameElement getInstance(String gssNameStr, Oid gssNameType) return new Krb5NameElement(principalName, gssNameStr, gssNameType); } - static Krb5NameElement getInstance(PrincipalName principalName) { + public static Krb5NameElement getInstance(PrincipalName principalName) { return new Krb5NameElement(principalName, principalName.getName(), Krb5MechFactory.NT_GSS_KRB5_PRINCIPAL); diff --git a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5ProxyCredential.java b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5ProxyCredential.java index 4c5690b3942..8fbe93a5768 100644 --- a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5ProxyCredential.java +++ b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5ProxyCredential.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -26,10 +26,17 @@ package sun.security.jgss.krb5; import org.ietf.jgss.*; +import sun.security.jgss.GSSCaller; import sun.security.jgss.spi.*; -import java.util.Date; + +import java.io.IOException; + +import sun.security.krb5.Credentials; +import sun.security.krb5.KrbException; import sun.security.krb5.internal.Ticket; +import javax.security.auth.kerberos.KerberosTicket; + /** * Implements the krb5 proxy credential element used in constrained * delegation. It is used in both impersonation (where there is no Kerberos 5 @@ -112,4 +119,24 @@ public GSSCredentialSpi impersonate(GSSNameSpi name) throws GSSException { throw new GSSException(GSSException.FAILURE, -1, "Only an initiate credentials can impersonate"); } + + // Try to see if a default credential should act as an impersonator. + static Krb5CredElement tryImpersonation(GSSCaller caller, + Krb5InitCredential initiator) throws GSSException { + + try { + KerberosTicket proxy = initiator.proxyTicket; + if (proxy != null) { + Credentials proxyCreds = Krb5Util.ticketToCreds(proxy); + return new Krb5ProxyCredential(initiator, + Krb5NameElement.getInstance(proxyCreds.getClient()), + proxyCreds.getTicket()); + } else { + return initiator; + } + } catch (KrbException | IOException e) { + throw new GSSException(GSSException.DEFECTIVE_CREDENTIAL, -1, + "Cannot create proxy credential"); + } + } } diff --git a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Util.java b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Util.java index 31b54b72554..8f79df1e67d 100644 --- a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Util.java +++ b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Util.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -139,11 +139,8 @@ public static KerberosTicket getTicketFromSubjectAndTgs(GSSCaller caller, /** * Retrieves the ticket corresponding to the client/server principal * pair from the Subject in the specified AccessControlContext. - * If the ticket can not be found in the Subject, and if - * useSubjectCredsOnly is false, then obtain ticket from - * a LoginContext. */ - static KerberosTicket getTicket(GSSCaller caller, + static KerberosTicket getServiceTicket(GSSCaller caller, String clientPrincipal, String serverPrincipal, AccessControlContext acc) throws LoginException { @@ -153,11 +150,31 @@ static KerberosTicket getTicket(GSSCaller caller, SubjectComber.find(accSubj, serverPrincipal, clientPrincipal, KerberosTicket.class); + return ticket; + } + + /** + * Retrieves the initial TGT corresponding to the client principal + * from the Subject in the specified AccessControlContext. + * If the ticket can not be found in the Subject, and if + * useSubjectCredsOnly is false, then obtain ticket from + * a LoginContext. + */ + static KerberosTicket getInitialTicket(GSSCaller caller, + String clientPrincipal, + AccessControlContext acc) throws LoginException { + + // Try to get ticket from acc's Subject + Subject accSubj = Subject.getSubject(acc); + KerberosTicket ticket = + SubjectComber.find(accSubj, null, clientPrincipal, + KerberosTicket.class); + // Try to get ticket from Subject obtained from GSSUtil if (ticket == null && !GSSUtil.useSubjectCredsOnly(caller)) { Subject subject = GSSUtil.login(caller, GSSUtil.GSS_KRB5_MECH_OID); ticket = SubjectComber.find(subject, - serverPrincipal, clientPrincipal, KerberosTicket.class); + null, clientPrincipal, KerberosTicket.class); } return ticket; } diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/Credentials.java b/src/java.security.jgss/share/classes/sun/security/krb5/Credentials.java index 17ce0e9bb2c..fc2fed379f1 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/Credentials.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/Credentials.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -56,13 +56,23 @@ public class Credentials { KerberosTime endTime; KerberosTime renewTill; HostAddresses cAddr; - EncryptionKey serviceKey; AuthorizationData authzData; private static boolean DEBUG = Krb5.DEBUG; private static CredentialsCache cache; static boolean alreadyLoaded = false; private static boolean alreadyTried = false; + private Credentials proxy = null; + + public Credentials getProxy() { + return proxy; + } + + public Credentials setProxy(Credentials proxy) { + this.proxy = proxy; + return this; + } + // Read native ticket with session key type in the given list private static native Credentials acquireDefaultNativeCreds(int[] eTypes); @@ -336,20 +346,19 @@ public static Credentials acquireTGTFromCache(PrincipalName princ, return null; } - sun.security.krb5.internal.ccache.Credentials tgtCred = - ccache.getDefaultCreds(); + Credentials tgtCred = ccache.getInitialCreds(); if (tgtCred == null) { return null; } - if (EType.isSupported(tgtCred.getEType())) { - return tgtCred.setKrbCreds(); + if (EType.isSupported(tgtCred.key.getEType())) { + return tgtCred; } else { if (DEBUG) { System.out.println( ">>> unsupported key type found the default TGT: " + - tgtCred.getEType()); + tgtCred.key.getEType()); } return null; } @@ -384,20 +393,19 @@ public static synchronized Credentials acquireDefaultCreds() { cache = CredentialsCache.getInstance(); } if (cache != null) { - sun.security.krb5.internal.ccache.Credentials temp = - cache.getDefaultCreds(); + Credentials temp = cache.getInitialCreds(); if (temp != null) { if (DEBUG) { System.out.println(">>> KrbCreds found the default ticket" + " granting ticket in credential cache."); } - if (EType.isSupported(temp.getEType())) { - result = temp.setKrbCreds(); + if (EType.isSupported(temp.key.getEType())) { + result = temp; } else { if (DEBUG) { System.out.println( ">>> unsupported key type found the default TGT: " + - temp.getEType()); + temp.key.getEType()); } } } @@ -474,10 +482,6 @@ public CredentialsCache getCache() { return cache; } - public EncryptionKey getServiceKey() { - return serviceKey; - } - /* * Prints out debug info. */ diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/JavaxSecurityAuthKerberosAccess.java b/src/java.security.jgss/share/classes/sun/security/krb5/JavaxSecurityAuthKerberosAccess.java index 501e6b309a9..84ca79bc9b3 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/JavaxSecurityAuthKerberosAccess.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/JavaxSecurityAuthKerberosAccess.java @@ -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 @@ -25,9 +25,8 @@ package sun.security.krb5; +import javax.security.auth.kerberos.KerberosTicket; import javax.security.auth.kerberos.KeyTab; -import sun.security.krb5.EncryptionKey; -import sun.security.krb5.PrincipalName; /** * An unsafe tunnel to get non-public access to classes in the @@ -39,4 +38,14 @@ public interface JavaxSecurityAuthKerberosAccess { */ public sun.security.krb5.internal.ktab.KeyTab keyTabTakeSnapshot( KeyTab ktab); + + /** + * Returns the proxy for a KerberosTicket. + */ + public KerberosTicket kerberosTicketGetProxy(KerberosTicket t); + + /** + * Sets the proxy for a KerberosTicket. + */ + public void kerberosTicketSetProxy(KerberosTicket t, KerberosTicket p); } diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/Realm.java b/src/java.security.jgss/share/classes/sun/security/krb5/Realm.java index bcaa342856c..cbd93e70742 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/Realm.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/Realm.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -187,7 +187,6 @@ protected static boolean isValidRealmString(String name) { return false; for (int i = 0; i < name.length(); i++) { if (name.charAt(i) == '/' || - name.charAt(i) == ':' || name.charAt(i) == '\0') { return false; } diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/ccache/CCacheInputStream.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/ccache/CCacheInputStream.java index e4cd1f3a157..8ec1659cc08 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/ccache/CCacheInputStream.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/ccache/CCacheInputStream.java @@ -325,16 +325,13 @@ boolean[] readFlags() throws IOException { } /** - * Reads the next cred in stream. - * @return the next cred, null if ticket or second_ticket unparseable. + * Reads the next cred or config entry in stream. + * @return the next cred or config entry, null if data unparseable. * - * Note: MIT krb5 1.8.1 might generate a config entry with server principal - * X-CACHECONF:/krb5_ccache_conf_data/fast_avail/krbtgt/REALM@REALM. The - * entry is used by KDC to inform the client that it support certain - * features. Its ticket is not a valid krb5 ticket and thus this method - * returns null. + * When data is unparseable, this method makes sure the correct number of + * bytes are consumed so it's safe to start reading the next element. */ - Credentials readCred(int version) throws IOException,RealmException, KrbApErrException, Asn1Exception { + Object readCred(int version) throws IOException,RealmException, KrbApErrException, Asn1Exception { PrincipalName cpname = null; try { cpname = readPrincipal(version); @@ -396,12 +393,23 @@ Credentials readCred(int version) throws IOException,RealmException, KrbApErrExc } try { + if (spname.getRealmString().equals("X-CACHECONF:")) { + String[] nameParts = spname.getNameStrings(); + if (nameParts[0].equals("krb5_ccache_conf_data")) { + return new CredentialsCache.ConfigEntry(nameParts[1], + nameParts.length > 2 ? new PrincipalName(nameParts[2]) : null, + ticketData); + } + } return new Credentials(cpname, spname, key, authtime, starttime, - endtime, renewTill, skey, tFlags, - addrs, auData, - ticketData != null ? new Ticket(ticketData) : null, - ticketData2 != null ? new Ticket(ticketData2) : null); + endtime, renewTill, skey, tFlags, + addrs, auData, + ticketData != null ? new Ticket(ticketData) : null, + ticketData2 != null ? new Ticket(ticketData2) : null); } catch (Exception e) { // If any of new Ticket(*) fails. + if (DEBUG) { + e.printStackTrace(System.out); + } return null; } } diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/ccache/CCacheOutputStream.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/ccache/CCacheOutputStream.java index dcc15e76d7d..cde9712bf3a 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/ccache/CCacheOutputStream.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/ccache/CCacheOutputStream.java @@ -31,7 +31,6 @@ package sun.security.krb5.internal.ccache; import java.io.IOException; -import java.io.FileOutputStream; import java.io.OutputStream; import sun.security.krb5.internal.util.KrbDataOutputStream; import sun.security.krb5.*; @@ -98,6 +97,21 @@ public void addCreds(Credentials creds) throws IOException, Asn1Exception { writeTicket(creds.secondTicket); } + public void addConfigEntry(PrincipalName cname, CredentialsCache.ConfigEntry e) + throws IOException { + cname.writePrincipal(this); + e.getSName().writePrincipal(this); + write16(0); write16(0); write32(0); + write32(0); write32(0); write32(0); write32(0); + write8(0); + write32(0); + write32(0); + write32(0); + write32(e.getData().length); + write(e.getData()); + write32(0); + } + void writeTicket(Ticket t) throws IOException, Asn1Exception { if (t == null) { write32(0); diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/ccache/Credentials.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/ccache/Credentials.java index 7128545a25a..c62e6293ff7 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/ccache/Credentials.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/ccache/Credentials.java @@ -169,6 +169,18 @@ public PrincipalName getServicePrincipal() throws RealmException { return sname; } + public Ticket getTicket() throws RealmException { + return ticket; + } + + public PrincipalName getServicePrincipal2() throws RealmException { + return secondTicket == null ? null : secondTicket.sname; + } + + public PrincipalName getClientPrincipal() throws RealmException { + return cname; + } + public sun.security.krb5.Credentials setKrbCreds() { // Note: We will not pass authorizationData to s.s.k.Credentials. The // field in that class will be passed to Krb5Context as the return @@ -208,7 +220,15 @@ public int getEType() { return key.getEType(); } + public EncryptionKey getKey() { + return key; + } + public int getTktEType() { return ticket.encPart.getEType(); } + + public int getTktEType2() { + return (secondTicket == null) ? 0 : secondTicket.encPart.getEType(); + } } diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/ccache/CredentialsCache.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/ccache/CredentialsCache.java index 8c61ed395c0..9489b92389a 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/ccache/CredentialsCache.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/ccache/CredentialsCache.java @@ -32,14 +32,9 @@ import sun.security.krb5.*; import sun.security.krb5.internal.*; -import java.util.StringTokenizer; -import java.util.Vector; + +import java.util.List; import java.io.IOException; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.BufferedReader; -import java.io.InputStreamReader; /** * CredentialsCache stores credentials(tickets, session keys, etc) in a semi-permanent store @@ -120,6 +115,62 @@ public static String cacheName() { public abstract void save() throws IOException, KrbException; public abstract Credentials[] getCredsList(); public abstract Credentials getDefaultCreds(); + public abstract sun.security.krb5.Credentials getInitialCreds(); public abstract Credentials getCreds(PrincipalName sname); public abstract Credentials getCreds(LoginOptions options, PrincipalName sname); + public abstract void addConfigEntry(ConfigEntry e); + public abstract List getConfigEntries(); + + public ConfigEntry getConfigEntry(String name) { + List entries = getConfigEntries(); + if (entries != null) { + for (ConfigEntry e : entries) { + if (e.getName().equals(name)) { + return e; + } + } + } + return null; + } + + public static class ConfigEntry { + + public ConfigEntry(String name, PrincipalName princ, byte[] data) { + this.name = name; + this.princ = princ; + this.data = data; + } + + private final String name; + private final PrincipalName princ; + private final byte[] data; // not worth cloning + + public String getName() { + return name; + } + + public PrincipalName getPrinc() { + return princ; + } + + public byte[] getData() { + return data; + } + + @Override + public String toString() { + return name + (princ != null ? ("." + princ) : "") + + ": " + new String(data); + } + + public PrincipalName getSName() { + try { + return new PrincipalName("krb5_ccache_conf_data/" + name + + (princ != null ? ("/" + princ) : "") + + "@X-CACHECONF:"); + } catch (RealmException e) { + throw new AssertionError(e); + } + } + } } diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/ccache/FileCredentialsCache.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/ccache/FileCredentialsCache.java index f22a1883c0b..69a60ecf359 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/ccache/FileCredentialsCache.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/ccache/FileCredentialsCache.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -35,6 +35,12 @@ import sun.security.krb5.*; import sun.security.krb5.internal.*; +import sun.security.util.SecurityProperties; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.StringTokenizer; import java.util.Vector; import java.io.IOException; @@ -181,9 +187,13 @@ synchronized void load(String name) throws IOException, KrbException { primaryPrincipal = p; credentialsList = new Vector(); while (cis.available() > 0) { - Credentials cred = cis.readCred(version); + Object cred = cis.readCred(version); if (cred != null) { - credentialsList.addElement(cred); + if (cred instanceof Credentials) { + credentialsList.addElement((Credentials)cred); + } else { + addConfigEntry((CredentialsCache.ConfigEntry)cred); + } } } } @@ -254,6 +264,9 @@ public synchronized void save() throws IOException, Asn1Exception { cos.addCreds(tmp[i]); } } + for (ConfigEntry e : getConfigEntries()) { + cos.addConfigEntry(primaryPrincipal, e); + } } } @@ -306,6 +319,17 @@ public Credentials getCreds(LoginOptions options, PrincipalName sname) { } } + private List configEntries = new ArrayList<>(); + + @Override + public void addConfigEntry(ConfigEntry e) { + configEntries.add(e); + } + + @Override + public List getConfigEntries() { + return Collections.unmodifiableList(configEntries); + } /** * Gets a credentials for a specified service. @@ -325,6 +349,81 @@ public Credentials getCreds(PrincipalName sname) { return null; } + public sun.security.krb5.Credentials getInitialCreds() { + + Credentials defaultCreds = getDefaultCreds(); + if (defaultCreds == null) { + return null; + } + sun.security.krb5.Credentials tgt = defaultCreds.setKrbCreds(); + + CredentialsCache.ConfigEntry entry = getConfigEntry("proxy_impersonator"); + if (entry == null) { + if (DEBUG) { + System.out.println("get normal credential"); + } + return tgt; + } + + boolean force; + String prop = SecurityProperties.privilegedGetOverridable( + "jdk.security.krb5.default.initiate.credential"); + if (prop == null) { + prop = "always-impersonate"; + } + switch (prop) { + case "no-impersonate": // never try impersonation + if (DEBUG) { + System.out.println("get normal credential"); + } + return tgt; + case "try-impersonate": + force = false; + break; + case "always-impersonate": + force = true; + break; + default: + throw new RuntimeException( + "Invalid jdk.security.krb5.default.initiate.credential"); + } + + try { + PrincipalName service = new PrincipalName( + new String(entry.getData(), StandardCharsets.UTF_8)); + if (!tgt.getClient().equals(service)) { + if (DEBUG) { + System.out.println("proxy_impersonator does not match service name"); + } + return force ? null : tgt; + } + PrincipalName client = getPrimaryPrincipal(); + Credentials proxy = null; + for (Credentials c : getCredsList()) { + if (c.getClientPrincipal().equals(client) + && c.getServicePrincipal().equals(service)) { + proxy = c; + break; + } + } + if (proxy == null) { + if (DEBUG) { + System.out.println("Cannot find evidence ticket in ccache"); + } + return force ? null : tgt; + } + if (DEBUG) { + System.out.println("Get proxied credential"); + } + return tgt.setProxy(proxy.setKrbCreds()); + } catch (KrbException e) { + if (DEBUG) { + System.out.println("Impersonation with ccache failed"); + } + return force ? null : tgt; + } + } + public Credentials getDefaultCreds() { Credentials[] list = getCredsList(); if (list == null) { diff --git a/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Klist.java b/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Klist.java index 95ba6e0d8c1..5a0c3bee077 100644 --- a/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Klist.java +++ b/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Klist.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -31,6 +31,8 @@ package sun.security.krb5.internal.tools; import java.net.InetAddress; +import java.util.List; + import sun.security.krb5.*; import sun.security.krb5.internal.*; import sun.security.krb5.internal.ccache.*; @@ -249,6 +251,8 @@ void displayCache() { String endtime; String renewTill; String servicePrincipal; + PrincipalName servicePrincipal2; + String clientPrincipal; if (creds[i].getStartTime() != null) { starttime = format(creds[i].getStartTime()); } else { @@ -260,6 +264,18 @@ void displayCache() { System.out.println("[" + (i + 1) + "] " + " Service Principal: " + servicePrincipal); + servicePrincipal2 = + creds[i].getServicePrincipal2(); + if (servicePrincipal2 != null) { + System.out.println(" Second Service: " + + servicePrincipal2); + } + clientPrincipal = + creds[i].getClientPrincipal().toString(); + if (!clientPrincipal.equals(defaultPrincipal)) { + System.out.println(" Client Principal: " + + clientPrincipal); + } System.out.println(" Valid starting: " + starttime); System.out.println(" Expires: " + endtime); if (creds[i].getRenewTill() != null) { @@ -270,8 +286,15 @@ void displayCache() { if (options[0] == 'e') { String eskey = EType.toString(creds[i].getEType()); String etkt = EType.toString(creds[i].getTktEType()); - System.out.println(" EType (skey, tkt): " - + eskey + ", " + etkt); + if (creds[i].getTktEType2() == 0) { + System.out.println(" EType (skey, tkt): " + + eskey + ", " + etkt); + } else { + String etkt2 = EType.toString(creds[i].getTktEType2()); + System.out.println(" EType (skey, tkts): " + + eskey + ", " + etkt + + ", " + etkt2); + } } if (options[1] == 'f') { System.out.println(" Flags: " + @@ -310,6 +333,15 @@ void displayCache() { } else { System.out.println("\nNo entries found."); } + + List configEntries + = cache.getConfigEntries(); + if (configEntries != null && !configEntries.isEmpty()) { + System.out.println("\nConfig entries:"); + for (CredentialsCache.ConfigEntry e : configEntries) { + System.out.println(" " + e); + } + } } void displayMessage(String target) { diff --git a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/XPath.java b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/XPath.java index 8a2c5b813be..f6102777054 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/XPath.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/XPath.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -40,7 +40,7 @@ * The XPath class wraps an expression object and provides general services * for execution of that expression. * @xsl.usage advanced - * @LastModified: Oct 2017 + * @LastModified: May 2019 */ public class XPath implements Serializable, ExpressionOwner { @@ -179,10 +179,12 @@ public XPath( else if (MATCH == type) parser.initMatchPattern(compiler, exprString, prefixResolver); else - throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_CANNOT_DEAL_XPATH_TYPE, new Object[]{Integer.toString(type)})); //"Can not deal with XPath type: " + type); + throw new RuntimeException(XSLMessages.createXPATHMessage( + XPATHErrorResources.ER_CANNOT_DEAL_XPATH_TYPE, + new Object[]{Integer.toString(type)})); // System.out.println("----------------"); - Expression expr = compiler.compile(0); + Expression expr = compiler.compileExpression(0); // System.out.println("expr: "+expr); this.setExpression(expr); @@ -234,7 +236,7 @@ else if (MATCH == type) //"Can not deal with XPath type: " + type); // System.out.println("----------------"); - Expression expr = compiler.compile(0); + Expression expr = compiler.compileExpression(0); // System.out.println("expr: "+expr); this.setExpression(expr); diff --git a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/axes/FilterExprWalker.java b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/axes/FilterExprWalker.java index 2f61f070216..1ab4d9653a6 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/axes/FilterExprWalker.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/axes/FilterExprWalker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -37,7 +37,7 @@ * Walker for the OP_VARIABLE, or OP_EXTFUNCTION, or OP_FUNCTION, or OP_GROUP, * op codes. * @see XPath FilterExpr descriptions - * @LastModified: Oct 2017 + * @LastModified: May 2019 */ public class FilterExprWalker extends AxesWalker { @@ -77,7 +77,7 @@ public void init(Compiler compiler, int opPos, int stepType) m_mustHardReset = true; case OpCodes.OP_GROUP : case OpCodes.OP_VARIABLE : - m_expr = compiler.compile(opPos); + m_expr = compiler.compileExpression(opPos); m_expr.exprSetParent(this); //if((OpCodes.OP_FUNCTION == stepType) && (m_expr instanceof com.sun.org.apache.xalan.internal.templates.FuncKey)) if(m_expr instanceof com.sun.org.apache.xpath.internal.operations.Variable) @@ -87,7 +87,7 @@ public void init(Compiler compiler, int opPos, int stepType) } break; default : - m_expr = compiler.compile(opPos + 2); + m_expr = compiler.compileExpression(opPos + 2); m_expr.exprSetParent(this); } // if(m_expr instanceof WalkingIterator) diff --git a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/axes/WalkerFactory.java b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/axes/WalkerFactory.java index fe3756060b4..2120541a6f6 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/axes/WalkerFactory.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/axes/WalkerFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -41,7 +41,7 @@ * which are built from the opcode map output, and an analysis engine * for the location path expressions in order to provide optimization hints. * - * @LastModified: Oct 2017 + * @LastModified: May 2019 */ public class WalkerFactory { @@ -1008,10 +1008,10 @@ private static StepPattern createDefaultStepPattern( case OpCodes.OP_EXTFUNCTION : case OpCodes.OP_FUNCTION : case OpCodes.OP_GROUP : - expr = compiler.compile(opPos); + expr = compiler.compileExpression(opPos); break; default : - expr = compiler.compile(opPos + 2); + expr = compiler.compileExpression(opPos + 2); } axis = Axis.FILTEREDLIST; diff --git a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/compiler/Compiler.java b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/compiler/Compiler.java index 4d0c68f315b..1b6ad648eb9 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/compiler/Compiler.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/compiler/Compiler.java @@ -1,6 +1,5 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -70,9 +69,12 @@ * of operation codes (op map) and then builds from that into an Expression * tree. * @xsl.usage advanced + * @LastModified: May 2019 */ public class Compiler extends OpMap { + // count the number of operations or calls to compileOperation + int countOp; /** * Construct a Compiler object with a specific ErrorListener and @@ -106,15 +108,40 @@ public Compiler() /** * Execute the XPath object from a given opcode position. + * + * Note that this method is added so that when StackOverflowError is caught + * the address space can be freed to this point allowing further activities + * such as reporting the error. + * * @param opPos The current position in the xpath.m_opMap array. * @return The result of the XPath. * * @throws TransformerException if there is a syntax or other error. * @xsl.usage advanced */ - public Expression compile(int opPos) throws TransformerException - { + public Expression compileExpression(int opPos) throws TransformerException + { + try { + countOp = 0; + return compile(opPos); + } catch (StackOverflowError sof) { + error(XPATHErrorResources.ER_COMPILATION_TOO_MANY_OPERATION, new Object[]{countOp}); + } + return null; + } + /** + * This method handles the actual compilation process. It is called from the + * compileExpression method as well as the subsequent processes. See the note + * for compileExpression. + * + * @param opPos The current position in the xpath.m_opMap array. + * @return The result of the XPath. + * + * @throws TransformerException if there is a syntax or other error. + */ + private Expression compile(int opPos) throws TransformerException + { int op = getOp(opPos); Expression expr = null; @@ -210,6 +237,7 @@ public Expression compile(int opPos) throws TransformerException private Expression compileOperation(Operation operation, int opPos) throws TransformerException { + ++countOp; int leftPos = getFirstChildPos(opPos); int rightPos = getNextOpPos(leftPos); diff --git a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/compiler/XPathParser.java b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/compiler/XPathParser.java index 54b9ff3d695..dcf044593b0 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/compiler/XPathParser.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/compiler/XPathParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -34,6 +34,7 @@ * Tokenizes and parses XPath expressions. This should really be named * XPathParserImpl, and may be renamed in the future. * @xsl.usage general + * @LastModified: May 2019 */ public class XPathParser { @@ -71,6 +72,9 @@ public class XPathParser protected final static int FILTER_MATCH_PRIMARY = 1; protected final static int FILTER_MATCH_PREDICATES = 2; + // counts open predicates + private int countPredicate; + /** * The parser constructor. */ @@ -157,6 +161,9 @@ public void initXPath( } else throw e; + } catch (StackOverflowError sof) { + error(XPATHErrorResources.ER_PREDICATE_TOO_MANY_OPEN, + new Object[]{m_token, m_queueMark, countPredicate}); } compiler.shrink(); @@ -190,7 +197,12 @@ public void initMatchPattern( m_ops.setOp(OpMap.MAPINDEX_LENGTH, 2); nextToken(); - Pattern(); + try { + Pattern(); + } catch (StackOverflowError sof) { + error(XPATHErrorResources.ER_PREDICATE_TOO_MANY_OPEN, + new Object[]{m_token, m_queueMark, countPredicate}); + } if (null != m_token) { @@ -741,7 +753,7 @@ void appendOp(int length, int op) */ protected void Expr() throws javax.xml.transform.TransformerException { - OrExpr(); + OrExpr(); } /** @@ -1883,11 +1895,12 @@ protected void NodeTest(int axesType) throws javax.xml.transform.TransformerExce */ protected void Predicate() throws javax.xml.transform.TransformerException { - if (tokenIs('[')) { + countPredicate++; nextToken(); PredicateExpr(); + countPredicate--; consumeExpected(']'); } } diff --git a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/res/XPATHErrorResources.java b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/res/XPATHErrorResources.java index 5fca3457283..54e4fe7b646 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/res/XPATHErrorResources.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/res/XPATHErrorResources.java @@ -1,6 +1,5 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -32,6 +31,7 @@ * Also you need to update the count of messages(MAX_CODE)or * the count of warnings(MAX_WARNING) [ Information purpose only] * @xsl.usage advanced + * @LastModified: May 2019 */ public class XPATHErrorResources extends ListResourceBundle { @@ -150,6 +150,10 @@ public class XPATHErrorResources extends ListResourceBundle "ER_FOUND_COMMA_BUT_NO_FOLLOWING_ARG"; public static final String ER_PREDICATE_ILLEGAL_SYNTAX = "ER_PREDICATE_ILLEGAL_SYNTAX"; + public static final String ER_PREDICATE_TOO_MANY_OPEN = + "ER_PREDICATE_TOO_MANY_OPEN"; + public static final String ER_COMPILATION_TOO_MANY_OPERATION = + "ER_COMPILATION_TOO_MANY_OPERATION"; public static final String ER_ILLEGAL_AXIS_NAME = "ER_ILLEGAL_AXIS_NAME"; public static final String ER_UNKNOWN_NODETYPE = "ER_UNKNOWN_NODETYPE"; public static final String ER_PATTERN_LITERAL_NEEDS_BE_QUOTED = @@ -464,6 +468,12 @@ public class XPATHErrorResources extends ListResourceBundle { ER_PREDICATE_ILLEGAL_SYNTAX, "'..[predicate]' or '.[predicate]' is illegal syntax. Use 'self::node()[predicate]' instead."}, + { ER_PREDICATE_TOO_MANY_OPEN, + "Stack overflow while parsing {0} at {1}. Too many open predicates({2})."}, + + { ER_COMPILATION_TOO_MANY_OPERATION, + "Stack overflow while compiling the expression. Too many operations({0})."}, + { ER_ILLEGAL_AXIS_NAME, "illegal axis name: {0}"}, diff --git a/src/jdk.accessibility/windows/native/common/AccessBridgeDebug.cpp b/src/jdk.accessibility/windows/native/common/AccessBridgeDebug.cpp index 2fc4e557f3a..4bf96669574 100644 --- a/src/jdk.accessibility/windows/native/common/AccessBridgeDebug.cpp +++ b/src/jdk.accessibility/windows/native/common/AccessBridgeDebug.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -41,34 +41,24 @@ extern "C" { static FILE* logFP = nullptr; -void initializeFileLogger(char * suffix) { - auto var = "JAVA_ACCESSBRIDGE_LOGFILE"; +void initializeFileLogger(char * fileName) { + auto var = "JAVA_ACCESSBRIDGE_LOGDIR"; const auto envfilePath = getenv(var); - if (envfilePath != nullptr) { - auto ext = const_cast(strrchr(envfilePath, '.')); - auto filePath = static_cast(nullptr); - auto len = strlen(envfilePath); - auto suffixlen = suffix != nullptr ? strlen(suffix) : (decltype(strlen(nullptr)))0; - - if (ext == nullptr) { - filePath = new char[len + suffixlen + 5]; - memset(filePath, 0, len + suffixlen + 5); - memcpy(filePath, envfilePath, len); - memcpy(filePath + len, suffix, suffixlen); - memcpy(filePath + len + suffixlen, ".log", 4); - } else { - auto extLen = strlen(ext); - - filePath = new char[len + suffixlen + 1]; - memset(filePath, 0, len + suffixlen + 1); - memcpy(filePath, envfilePath, len - extLen); - memcpy(filePath + len - extLen, suffix, suffixlen); - memcpy(filePath + len + suffixlen - extLen, ext, extLen); - } + if (envfilePath != nullptr && fileName != nullptr) { + auto envFilePathLength = strlen(envfilePath); + auto fileNameLength = strlen(fileName); + auto filePathSize = envFilePathLength + 1 + fileNameLength + 5; //1 for "/", 5 for ".log" and 0; + auto filePath = new char[filePathSize]; + memset(filePath, 0, filePathSize*sizeof(char)); + memcpy(filePath, envfilePath, envFilePathLength*sizeof(char)); + filePath[envFilePathLength] = '/'; + memcpy(filePath + envFilePathLength + 1, fileName, fileNameLength*sizeof(char)); + memcpy(filePath + envFilePathLength + 1 + fileNameLength, ".log", 4*sizeof(char)); logFP = fopen(filePath, "w"); if (logFP == nullptr) { - PrintDebugString("couldnot open file %s", filePath); + printf("\n%s\n", filePath); + PrintDebugString("Could not open file %s", filePath); } delete [] filePath; @@ -143,7 +133,7 @@ char *printError(char *msg) { #endif #endif if (logFP) { - fprintf(logFP, "[%lldu] ", getTimeStamp()); + fprintf(logFP, "[%llu] ", getTimeStamp()); va_list args; va_start(args, msg); vfprintf(logFP, msg, args); diff --git a/src/jdk.accessibility/windows/native/common/AccessBridgeDebug.h b/src/jdk.accessibility/windows/native/common/AccessBridgeDebug.h index 7950b3482e6..92459d30789 100644 --- a/src/jdk.accessibility/windows/native/common/AccessBridgeDebug.h +++ b/src/jdk.accessibility/windows/native/common/AccessBridgeDebug.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -54,7 +54,7 @@ extern "C" { void PrintJavaDebugString(char *msg, ...); void wPrintJavaDebugString(wchar_t *msg, ...); void wPrintDebugString(wchar_t *msg, ...); - void initializeFileLogger(char * suffix); + void initializeFileLogger(char * fileName); void finalizeFileLogger(); #ifdef __cplusplus diff --git a/src/jdk.accessibility/windows/native/libjavaaccessbridge/JavaAccessBridge.cpp b/src/jdk.accessibility/windows/native/libjavaaccessbridge/JavaAccessBridge.cpp index cebf172ba8a..6bb0f3600d9 100644 --- a/src/jdk.accessibility/windows/native/libjavaaccessbridge/JavaAccessBridge.cpp +++ b/src/jdk.accessibility/windows/native/libjavaaccessbridge/JavaAccessBridge.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -165,7 +165,7 @@ extern "C" { JavaAccessBridge::JavaAccessBridge(HINSTANCE hInstance) { windowsInstance = hInstance; ATs = (AccessBridgeATInstance *) 0; - initializeFileLogger("_java_access_bridge"); + initializeFileLogger("java_access_bridge"); initBroadcastMessageIDs(); // get the unique to us broadcast msg. IDs } diff --git a/src/jdk.accessibility/windows/native/libwindowsaccessbridge/WinAccessBridge.cpp b/src/jdk.accessibility/windows/native/libwindowsaccessbridge/WinAccessBridge.cpp index 9a1c8612e9a..d5c0b887ffe 100644 --- a/src/jdk.accessibility/windows/native/libwindowsaccessbridge/WinAccessBridge.cpp +++ b/src/jdk.accessibility/windows/native/libwindowsaccessbridge/WinAccessBridge.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -130,7 +130,7 @@ extern "C" { switch (fdwReason) { case DLL_PROCESS_ATTACH: // A Windows executable loaded us - initializeFileLogger("_windows_access_bridge"); + initializeFileLogger("windows_access_bridge"); PrintDebugString("[INFO]: DLL_PROCESS_ATTACH"); theWindowsAccessBridge = new WinAccessBridge(hinstDll); break; diff --git a/src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/JavaScriptScanner.java b/src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/JavaScriptScanner.java index 9de049515bf..4afd46b74c1 100644 --- a/src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/JavaScriptScanner.java +++ b/src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/JavaScriptScanner.java @@ -69,12 +69,10 @@ static class ParseException extends Exception { private boolean newline = true; Map tagParsers; - Set eventAttrs; Set uriAttrs; public JavaScriptScanner() { initTagParsers(); - initEventAttrs(); initURIAttrs(); } @@ -101,7 +99,10 @@ private void checkHtmlTag(String tag) { private void checkHtmlAttr(String name, String value) { String n = name.toLowerCase(Locale.ENGLISH); - if (eventAttrs.contains(n) + // See https://www.w3.org/TR/html52/webappapis.html#events-event-handlers + // An event handler has a name, which always starts with "on" and is followed by + // the name of the event for which it is intended. + if (n.startsWith("on") || uriAttrs.contains(n) && value != null && value.toLowerCase(Locale.ENGLISH).trim().startsWith("javascript:")) { reporter.report(); @@ -1061,34 +1062,6 @@ public void parse(int pos) { } - private void initEventAttrs() { - eventAttrs = new HashSet<>(Arrays.asList( - // See https://www.w3.org/TR/html-markup/global-attributes.html#common.attrs.event-handler - "onabort", "onblur", "oncanplay", "oncanplaythrough", - "onchange", "onclick", "oncontextmenu", "ondblclick", - "ondrag", "ondragend", "ondragenter", "ondragleave", - "ondragover", "ondragstart", "ondrop", "ondurationchange", - "onemptied", "onended", "onerror", "onfocus", "oninput", - "oninvalid", "onkeydown", "onkeypress", "onkeyup", - "onload", "onloadeddata", "onloadedmetadata", "onloadstart", - "onmousedown", "onmousemove", "onmouseout", "onmouseover", - "onmouseup", "onmousewheel", "onpause", "onplay", - "onplaying", "onprogress", "onratechange", "onreadystatechange", - "onreset", "onscroll", "onseeked", "onseeking", - "onselect", "onshow", "onstalled", "onsubmit", "onsuspend", - "ontimeupdate", "onvolumechange", "onwaiting", - - // See https://www.w3.org/TR/html4/sgml/dtd.html - // Most of the attributes that take a %Script are also defined as event handlers - // in HTML 5. The one exception is onunload. - // "onchange", "onclick", "ondblclick", "onfocus", - // "onkeydown", "onkeypress", "onkeyup", "onload", - // "onmousedown", "onmousemove", "onmouseout", "onmouseover", - // "onmouseup", "onreset", "onselect", "onsubmit", - "onunload" - )); - } - private void initURIAttrs() { uriAttrs = new HashSet<>(Arrays.asList( // See https://www.w3.org/TR/html4/sgml/dtd.html diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/JavaScriptScanner.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/JavaScriptScanner.java index 8699bed356b..9504488aaf0 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/JavaScriptScanner.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/JavaScriptScanner.java @@ -61,34 +61,8 @@ public Void visitStartElement(StartElementTree tree, Consumer f) { public Void visitAttribute(AttributeTree tree, Consumer f) { String name = tree.getName().toString().toLowerCase(Locale.ENGLISH); switch (name) { - // See https://www.w3.org/TR/html-markup/global-attributes.html#common.attrs.event-handler - case "onabort": case "onblur": case "oncanplay": case "oncanplaythrough": - case "onchange": case "onclick": case "oncontextmenu": case "ondblclick": - case "ondrag": case "ondragend": case "ondragenter": case "ondragleave": - case "ondragover": case "ondragstart": case "ondrop": case "ondurationchange": - case "onemptied": case "onended": case "onerror": case "onfocus": case "oninput": - case "oninvalid": case "onkeydown": case "onkeypress": case "onkeyup": - case "onload": case "onloadeddata": case "onloadedmetadata": case "onloadstart": - case "onmousedown": case "onmousemove": case "onmouseout": case "onmouseover": - case "onmouseup": case "onmousewheel": case "onpause": case "onplay": - case "onplaying": case "onprogress": case "onratechange": case "onreadystatechange": - case "onreset": case "onscroll": case "onseeked": case "onseeking": - case "onselect": case "onshow": case "onstalled": case "onsubmit": case "onsuspend": - case "ontimeupdate": case "onvolumechange": case "onwaiting": - - // See https://www.w3.org/TR/html4/sgml/dtd.html - // Most of the attributes that take a %Script are also defined as event handlers - // in HTML 5. The one exception is onunload. - // case "onchange": case "onclick": case "ondblclick": case "onfocus": - // case "onkeydown": case "onkeypress": case "onkeyup": case "onload": - // case "onmousedown": case "onmousemove": case "onmouseout": case "onmouseover": - // case "onmouseup": case "onreset": case "onselect": case "onsubmit": - case "onunload": - f.accept(getCurrentPath()); - break; - // See https://www.w3.org/TR/html4/sgml/dtd.html - // https://www.w3.org/TR/html5/ + // https://www.w3.org/TR/html52/fullindex.html#attributes-table // These are all the attributes that take a %URI or a valid URL potentially surrounded // by spaces case "action": case "cite": case "classid": case "codebase": case "data": @@ -102,6 +76,14 @@ public Void visitAttribute(AttributeTree tree, Consumer f) { } } break; + // See https://www.w3.org/TR/html52/webappapis.html#events-event-handlers + // An event handler has a name, which always starts with "on" and is followed by + // the name of the event for which it is intended. + default: + if (name.startsWith("on")) { + f.accept(getCurrentPath()); + } + break; } return super.visitAttribute(tree, f); } diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/regexp/JdkRegExp.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/regexp/JdkRegExp.java index 525a2a51852..e88471633c2 100644 --- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/regexp/JdkRegExp.java +++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/regexp/JdkRegExp.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 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 @@ -82,6 +82,8 @@ public JdkRegExp(final String source, final String flags) throws ParserException } } catch (final PatternSyntaxException e2) { throwParserException("syntax", e2.getMessage()); + } catch (StackOverflowError e3) { + throw new RuntimeException(e3); } } diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java index a602338939d..ccddc876fc1 100644 --- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java +++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 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 @@ -82,6 +82,8 @@ public JoniRegExp(final String pattern, final String flags) throws ParserExcepti } } catch (final PatternSyntaxException | JOniException e2) { throwParserException("syntax", e2.getMessage()); + } catch (StackOverflowError e3) { + throw new RuntimeException(e3); } } diff --git a/src/jdk.security.auth/share/classes/com/sun/security/auth/module/Krb5LoginModule.java b/src/jdk.security.auth/share/classes/com/sun/security/auth/module/Krb5LoginModule.java index 62138dee284..caf55b04e53 100644 --- a/src/jdk.security.auth/share/classes/com/sun/security/auth/module/Krb5LoginModule.java +++ b/src/jdk.security.auth/share/classes/com/sun/security/auth/module/Krb5LoginModule.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -644,6 +644,7 @@ private void attemptAuthentication(boolean getPasswdFromSharedState) // renew if ticket is old. Credentials newCred = renewCredentials(cred); if (newCred != null) { + newCred.setProxy(cred.getProxy()); cred = newCred; } } @@ -1070,6 +1071,10 @@ public boolean commit() throws LoginException { // create Kerberos Ticket if (isInitiator) { kerbTicket = Krb5Util.credsToTicket(cred); + if (cred.getProxy() != null) { + KerberosSecrets.getJavaxSecurityAuthKerberosAccess() + .kerberosTicketSetProxy(kerbTicket,Krb5Util.credsToTicket(cred.getProxy())); + } } if (storeKey && encKeys != null) { diff --git a/test/jdk/java/awt/image/DrawImage/IncorrectManagedImageSourceOffset.java b/test/jdk/java/awt/image/DrawImage/IncorrectManagedImageSourceOffset.java new file mode 100644 index 00000000000..5c5180e00b2 --- /dev/null +++ b/test/jdk/java/awt/image/DrawImage/IncorrectManagedImageSourceOffset.java @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2014, 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsEnvironment; +import java.awt.Image; +import java.awt.Transparency; +import java.awt.color.ColorSpace; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.ComponentColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.Raster; +import java.awt.image.VolatileImage; +import java.awt.image.WritableRaster; +import java.io.File; +import java.io.IOException; + +import javax.imageio.ImageIO; + +import sun.awt.image.SunWritableRaster; + +import static java.awt.Transparency.BITMASK; +import static java.awt.Transparency.OPAQUE; +import static java.awt.Transparency.TRANSLUCENT; +import static java.awt.image.BufferedImage.TYPE_3BYTE_BGR; +import static java.awt.image.BufferedImage.TYPE_4BYTE_ABGR; +import static java.awt.image.BufferedImage.TYPE_4BYTE_ABGR_PRE; +import static java.awt.image.BufferedImage.TYPE_BYTE_BINARY; +import static java.awt.image.BufferedImage.TYPE_BYTE_INDEXED; +import static java.awt.image.BufferedImage.TYPE_CUSTOM; +import static java.awt.image.BufferedImage.TYPE_INT_ARGB; +import static java.awt.image.BufferedImage.TYPE_INT_ARGB_PRE; +import static java.awt.image.BufferedImage.TYPE_INT_BGR; +import static java.awt.image.BufferedImage.TYPE_INT_RGB; + +/** + * @test + * @key headful + * @bug 8029253 6207877 + * @summary Tests asymmetric source offsets when managed image is drawn to VI. + * Results of the blit to compatibleImage are used for comparison. + * @author Sergey Bylokhov + * @modules java.desktop/sun.awt.image + * @run main/othervm -Dsun.java2d.accthreshold=0 IncorrectManagedImageSourceOffset + * @run main/othervm -Dsun.java2d.accthreshold=0 -Dsun.java2d.uiScale=1 IncorrectManagedImageSourceOffset + * @run main/othervm -Dsun.java2d.accthreshold=0 -Dsun.java2d.uiScale=2 IncorrectManagedImageSourceOffset + */ +public final class IncorrectManagedImageSourceOffset { + + // See the same test for unmanaged images: IncorrectUnmanagedImageSourceOffset + + private static final int[] TYPES = {TYPE_INT_RGB, TYPE_INT_ARGB, + TYPE_INT_ARGB_PRE, TYPE_INT_BGR, + TYPE_3BYTE_BGR, TYPE_4BYTE_ABGR, + TYPE_4BYTE_ABGR_PRE, + /*TYPE_USHORT_565_RGB, + TYPE_USHORT_555_RGB, TYPE_BYTE_GRAY, + TYPE_USHORT_GRAY,*/ TYPE_BYTE_BINARY, + TYPE_BYTE_INDEXED, TYPE_CUSTOM}; + private static final int[] TRANSPARENCIES = {OPAQUE, BITMASK, TRANSLUCENT}; + + public static void main(final String[] args) throws IOException { + for (final int viType : TRANSPARENCIES) { + for (final int biType : TYPES) { + BufferedImage bi = makeManagedBI(biType); + fill(bi); + test(bi, viType); + } + } + } + + private static void test(BufferedImage bi, int type) + throws IOException { + GraphicsEnvironment ge = GraphicsEnvironment + .getLocalGraphicsEnvironment(); + GraphicsConfiguration gc = ge.getDefaultScreenDevice() + .getDefaultConfiguration(); + VolatileImage vi = gc.createCompatibleVolatileImage(511, 255, type); + BufferedImage gold = gc.createCompatibleImage(511, 255, type); + // draw to compatible Image + Graphics2D big = gold.createGraphics(); + // force scaled blit + big.drawImage(bi, 7, 11, 127, 111, 7, 11, 127 * 2, 111, null); + big.dispose(); + // draw to volatile image + BufferedImage snapshot; + while (true) { + vi.validate(gc); + if (vi.validate(gc) != VolatileImage.IMAGE_OK) { + try { + Thread.sleep(100); + } catch (final InterruptedException ignored) { + } + continue; + } + Graphics2D vig = vi.createGraphics(); + // force scaled blit + vig.drawImage(bi, 7, 11, 127, 111, 7, 11, 127 * 2, 111, null); + vig.dispose(); + snapshot = vi.getSnapshot(); + if (vi.contentsLost()) { + try { + Thread.sleep(100); + } catch (final InterruptedException ignored) { + } + continue; + } + break; + } + // validate images + for (int x = 7; x < 127; ++x) { + for (int y = 11; y < 111; ++y) { + if (gold.getRGB(x, y) != snapshot.getRGB(x, y)) { + ImageIO.write(gold, "png", new File("gold.png")); + ImageIO.write(snapshot, "png", new File("bi.png")); + throw new RuntimeException("Test failed."); + } + } + } + } + + private static BufferedImage makeManagedBI(final int type) { + final BufferedImage bi; + if (type == TYPE_CUSTOM) { + bi = makeCustomManagedBI(); + } else { + bi = new BufferedImage(511, 255, type); + } + bi.setAccelerationPriority(1.0f); + return bi; + } + + /** + * Returns the custom buffered image, which mostly identical to + * BufferedImage.(w,h,TYPE_3BYTE_BGR), but uses the bigger scanlineStride. + * This means that the raster will have gaps, between the rows. + */ + private static BufferedImage makeCustomManagedBI() { + int w = 511, h = 255; + ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); + int[] nBits = {8, 8, 8}; + int[] bOffs = {2, 1, 0}; + ColorModel colorModel = new ComponentColorModel(cs, nBits, false, false, + Transparency.OPAQUE, + DataBuffer.TYPE_BYTE); + WritableRaster raster = + Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, w, h, + w * 3 + 2, 3, bOffs, null); + BufferedImage bi = new BufferedImage(colorModel, raster, true, null); + SunWritableRaster.makeTrackable(raster.getDataBuffer()); + SunWritableRaster.markDirty(bi); + return bi; + } + + private static void fill(final Image image) { + final Graphics2D graphics = (Graphics2D) image.getGraphics(); + graphics.setComposite(AlphaComposite.Src); + for (int i = 0; i < image.getHeight(null); ++i) { + graphics.setColor(new Color(i, 0, 0)); + graphics.fillRect(0, i, image.getWidth(null), 1); + } + graphics.dispose(); + } +} diff --git a/test/jdk/java/awt/image/DrawImage/IncorrectUnmanagedImageSourceOffset.java b/test/jdk/java/awt/image/DrawImage/IncorrectUnmanagedImageSourceOffset.java index 486d3449042..d0c49c94686 100644 --- a/test/jdk/java/awt/image/DrawImage/IncorrectUnmanagedImageSourceOffset.java +++ b/test/jdk/java/awt/image/DrawImage/IncorrectUnmanagedImageSourceOffset.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -27,30 +27,52 @@ import java.awt.GraphicsConfiguration; import java.awt.GraphicsEnvironment; import java.awt.Image; +import java.awt.Transparency; +import java.awt.color.ColorSpace; import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.ComponentColorModel; import java.awt.image.DataBuffer; import java.awt.image.DataBufferByte; import java.awt.image.DataBufferInt; import java.awt.image.DataBufferShort; +import java.awt.image.Raster; import java.awt.image.VolatileImage; +import java.awt.image.WritableRaster; import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; -import static java.awt.Transparency.*; -import static java.awt.image.BufferedImage.*; +import static java.awt.Transparency.BITMASK; +import static java.awt.Transparency.OPAQUE; +import static java.awt.Transparency.TRANSLUCENT; +import static java.awt.image.BufferedImage.TYPE_3BYTE_BGR; +import static java.awt.image.BufferedImage.TYPE_4BYTE_ABGR; +import static java.awt.image.BufferedImage.TYPE_4BYTE_ABGR_PRE; +import static java.awt.image.BufferedImage.TYPE_BYTE_BINARY; +import static java.awt.image.BufferedImage.TYPE_BYTE_INDEXED; +import static java.awt.image.BufferedImage.TYPE_CUSTOM; +import static java.awt.image.BufferedImage.TYPE_INT_ARGB; +import static java.awt.image.BufferedImage.TYPE_INT_ARGB_PRE; +import static java.awt.image.BufferedImage.TYPE_INT_BGR; +import static java.awt.image.BufferedImage.TYPE_INT_RGB; /** * @test * @key headful - * @bug 8029253 + * @bug 8029253 6207877 * @summary Tests asymmetric source offsets when unmanaged image is drawn to VI. * Results of the blit to compatibleImage are used for comparison. * @author Sergey Bylokhov + * @run main/othervm IncorrectUnmanagedImageSourceOffset + * @run main/othervm -Dsun.java2d.uiScale=1 IncorrectUnmanagedImageSourceOffset + * @run main/othervm -Dsun.java2d.uiScale=2 IncorrectUnmanagedImageSourceOffset */ public final class IncorrectUnmanagedImageSourceOffset { + // See the same test for managed images: IncorrectManagedImageSourceOffset + private static final int[] TYPES = {TYPE_INT_RGB, TYPE_INT_ARGB, TYPE_INT_ARGB_PRE, TYPE_INT_BGR, TYPE_3BYTE_BGR, TYPE_4BYTE_ABGR, @@ -58,7 +80,7 @@ public final class IncorrectUnmanagedImageSourceOffset { /*TYPE_USHORT_565_RGB, TYPE_USHORT_555_RGB, TYPE_BYTE_GRAY, TYPE_USHORT_GRAY,*/ TYPE_BYTE_BINARY, - TYPE_BYTE_INDEXED}; + TYPE_BYTE_INDEXED, TYPE_CUSTOM}; private static final int[] TRANSPARENCIES = {OPAQUE, BITMASK, TRANSLUCENT}; public static void main(final String[] args) throws IOException { @@ -122,7 +144,12 @@ private static void test(BufferedImage bi, int type) } private static BufferedImage makeUnmanagedBI(final int type) { - final BufferedImage bi = new BufferedImage(511, 255, type); + final BufferedImage bi; + if (type == TYPE_CUSTOM) { + bi = makeCustomUnmanagedBI(); + } else { + bi = new BufferedImage(511, 255, type); + } final DataBuffer db = bi.getRaster().getDataBuffer(); if (db instanceof DataBufferInt) { ((DataBufferInt) db).getData(); @@ -130,15 +157,30 @@ private static BufferedImage makeUnmanagedBI(final int type) { ((DataBufferShort) db).getData(); } else if (db instanceof DataBufferByte) { ((DataBufferByte) db).getData(); - } else { - try { - bi.setAccelerationPriority(0.0f); - } catch (final Throwable ignored) { - } } + bi.setAccelerationPriority(0.0f); return bi; } + /** + * Returns the custom buffered image, which mostly identical to + * BufferedImage.(w,h,TYPE_3BYTE_BGR), but uses the bigger scanlineStride. + * This means that the raster will have gaps, between the rows. + */ + private static BufferedImage makeCustomUnmanagedBI() { + int w = 511, h = 255; + ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); + int[] nBits = {8, 8, 8}; + int[] bOffs = {2, 1, 0}; + ColorModel colorModel = new ComponentColorModel(cs, nBits, false, false, + Transparency.OPAQUE, + DataBuffer.TYPE_BYTE); + WritableRaster raster = + Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, w, h, + w * 3 + 2, 3, bOffs, null); + return new BufferedImage(colorModel, raster, true, null); + } + private static void fill(final Image image) { final Graphics2D graphics = (Graphics2D) image.getGraphics(); graphics.setComposite(AlphaComposite.Src); diff --git a/test/jdk/java/awt/image/DrawImage/SimpleManagedImage.java b/test/jdk/java/awt/image/DrawImage/SimpleManagedImage.java new file mode 100644 index 00000000000..e0fefa74306 --- /dev/null +++ b/test/jdk/java/awt/image/DrawImage/SimpleManagedImage.java @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2014, 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsEnvironment; +import java.awt.Image; +import java.awt.Transparency; +import java.awt.color.ColorSpace; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.ComponentColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.Raster; +import java.awt.image.VolatileImage; +import java.awt.image.WritableRaster; +import java.io.File; +import java.io.IOException; + +import javax.imageio.ImageIO; + +import sun.awt.image.SunWritableRaster; + +import static java.awt.Transparency.BITMASK; +import static java.awt.Transparency.OPAQUE; +import static java.awt.Transparency.TRANSLUCENT; +import static java.awt.image.BufferedImage.TYPE_3BYTE_BGR; +import static java.awt.image.BufferedImage.TYPE_4BYTE_ABGR; +import static java.awt.image.BufferedImage.TYPE_4BYTE_ABGR_PRE; +import static java.awt.image.BufferedImage.TYPE_BYTE_BINARY; +import static java.awt.image.BufferedImage.TYPE_BYTE_INDEXED; +import static java.awt.image.BufferedImage.TYPE_CUSTOM; +import static java.awt.image.BufferedImage.TYPE_INT_ARGB; +import static java.awt.image.BufferedImage.TYPE_INT_ARGB_PRE; +import static java.awt.image.BufferedImage.TYPE_INT_BGR; +import static java.awt.image.BufferedImage.TYPE_INT_RGB; + +/** + * @test + * @key headful + * @bug 8029253 6207877 + * @summary Tests the case when managed image is drawn to VI. + * Results of the blit to compatibleImage are used for comparison. + * @author Sergey Bylokhov + * @modules java.desktop/sun.awt.image + * @run main/othervm -Dsun.java2d.accthreshold=0 SimpleManagedImage + * @run main/othervm -Dsun.java2d.accthreshold=0 -Dsun.java2d.uiScale=1 SimpleManagedImage + * @run main/othervm -Dsun.java2d.accthreshold=0 -Dsun.java2d.uiScale=2 SimpleManagedImage + */ +public final class SimpleManagedImage { + + // See the same test for unmanaged images: SimpleUnmanagedImage + + private static final int[] TYPES = {TYPE_INT_RGB, TYPE_INT_ARGB, + TYPE_INT_ARGB_PRE, TYPE_INT_BGR, + TYPE_3BYTE_BGR, TYPE_4BYTE_ABGR, + TYPE_4BYTE_ABGR_PRE, + /*TYPE_USHORT_565_RGB, + TYPE_USHORT_555_RGB, TYPE_BYTE_GRAY, + TYPE_USHORT_GRAY,*/ TYPE_BYTE_BINARY, + TYPE_BYTE_INDEXED, TYPE_CUSTOM}; + private static final int[] TRANSPARENCIES = {OPAQUE, BITMASK, TRANSLUCENT}; + + public static void main(final String[] args) throws IOException { + for (final int viType : TRANSPARENCIES) { + for (final int biType : TYPES) { + BufferedImage bi = makeManagedBI(biType); + fill(bi); + test(bi, viType); + } + } + } + + private static void test(BufferedImage bi, int type) + throws IOException { + GraphicsEnvironment ge = GraphicsEnvironment + .getLocalGraphicsEnvironment(); + GraphicsConfiguration gc = ge.getDefaultScreenDevice() + .getDefaultConfiguration(); + VolatileImage vi = gc.createCompatibleVolatileImage(1000, 1000, type); + BufferedImage gold = gc.createCompatibleImage(1000, 1000, type); + // draw to compatible Image + init(gold); + Graphics2D big = gold.createGraphics(); + big.drawImage(bi, 7, 11, null); + big.dispose(); + // draw to volatile image + BufferedImage snapshot; + while (true) { + vi.validate(gc); + if (vi.validate(gc) != VolatileImage.IMAGE_OK) { + try { + Thread.sleep(100); + } catch (final InterruptedException ignored) { + } + continue; + } + init(vi); + Graphics2D vig = vi.createGraphics(); + vig.drawImage(bi, 7, 11, null); + vig.dispose(); + snapshot = vi.getSnapshot(); + if (vi.contentsLost()) { + try { + Thread.sleep(100); + } catch (final InterruptedException ignored) { + } + continue; + } + break; + } + // validate images + for (int x = 0; x < 1000; ++x) { + for (int y = 0; y < 1000; ++y) { + if (gold.getRGB(x, y) != snapshot.getRGB(x, y)) { + ImageIO.write(gold, "png", new File("gold.png")); + ImageIO.write(snapshot, "png", new File("bi.png")); + throw new RuntimeException("Test failed."); + } + } + } + } + + private static BufferedImage makeManagedBI(final int type) { + final BufferedImage bi; + if (type == TYPE_CUSTOM) { + bi = makeCustomManagedBI(); + } else { + bi = new BufferedImage(511, 255, type); + } + bi.setAccelerationPriority(1.0f); + return bi; + } + + /** + * Returns the custom buffered image, which mostly identical to + * BufferedImage.(w,h,TYPE_3BYTE_BGR), but uses the bigger scanlineStride. + * This means that the raster will have gaps, between the rows. + */ + private static BufferedImage makeCustomManagedBI() { + int w = 511, h = 255; + ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); + int[] nBits = {8, 8, 8}; + int[] bOffs = {2, 1, 0}; + ColorModel colorModel = new ComponentColorModel(cs, nBits, false, false, + Transparency.OPAQUE, + DataBuffer.TYPE_BYTE); + WritableRaster raster = + Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, w, h, + w * 3 + 2, 3, bOffs, null); + BufferedImage bi = new BufferedImage(colorModel, raster, true, null); + SunWritableRaster.makeTrackable(raster.getDataBuffer()); + SunWritableRaster.markDirty(bi); + return bi; + } + + private static void init(final Image image) { + final Graphics2D graphics = (Graphics2D) image.getGraphics(); + graphics.setComposite(AlphaComposite.Src); + graphics.setColor(new Color(0, 0, 0, 0)); + graphics.fillRect(0, 0, image.getWidth(null), image.getHeight(null)); + graphics.dispose(); + } + + private static void fill(final Image image) { + final Graphics2D graphics = (Graphics2D) image.getGraphics(); + graphics.setComposite(AlphaComposite.Src); + for (int i = 0; i < image.getHeight(null); ++i) { + graphics.setColor(new Color(i, 0, 0)); + graphics.fillRect(0, i, image.getWidth(null), 1); + } + graphics.dispose(); + } +} diff --git a/test/jdk/java/awt/image/DrawImage/SimpleUnmanagedImage.java b/test/jdk/java/awt/image/DrawImage/SimpleUnmanagedImage.java new file mode 100644 index 00000000000..01921249460 --- /dev/null +++ b/test/jdk/java/awt/image/DrawImage/SimpleUnmanagedImage.java @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2014, 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsEnvironment; +import java.awt.Image; +import java.awt.Transparency; +import java.awt.color.ColorSpace; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.ComponentColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferByte; +import java.awt.image.DataBufferInt; +import java.awt.image.DataBufferShort; +import java.awt.image.Raster; +import java.awt.image.VolatileImage; +import java.awt.image.WritableRaster; +import java.io.File; +import java.io.IOException; + +import javax.imageio.ImageIO; + +import static java.awt.Transparency.BITMASK; +import static java.awt.Transparency.OPAQUE; +import static java.awt.Transparency.TRANSLUCENT; +import static java.awt.image.BufferedImage.TYPE_3BYTE_BGR; +import static java.awt.image.BufferedImage.TYPE_4BYTE_ABGR; +import static java.awt.image.BufferedImage.TYPE_4BYTE_ABGR_PRE; +import static java.awt.image.BufferedImage.TYPE_BYTE_BINARY; +import static java.awt.image.BufferedImage.TYPE_BYTE_INDEXED; +import static java.awt.image.BufferedImage.TYPE_CUSTOM; +import static java.awt.image.BufferedImage.TYPE_INT_ARGB; +import static java.awt.image.BufferedImage.TYPE_INT_ARGB_PRE; +import static java.awt.image.BufferedImage.TYPE_INT_BGR; +import static java.awt.image.BufferedImage.TYPE_INT_RGB; + +/** + * @test + * @key headful + * @bug 8029253 6207877 + * @summary Tests the case when unmanaged image is drawn to VI. + * Results of the blit to compatibleImage are used for comparison. + * @author Sergey Bylokhov + * @run main/othervm SimpleUnmanagedImage + * @run main/othervm -Dsun.java2d.uiScale=1 SimpleUnmanagedImage + * @run main/othervm -Dsun.java2d.uiScale=2 SimpleUnmanagedImage + */ +public final class SimpleUnmanagedImage { + + // See the same test for managed images: SimpleManagedImage + + private static final int[] TYPES = {TYPE_INT_RGB, TYPE_INT_ARGB, + TYPE_INT_ARGB_PRE, TYPE_INT_BGR, + TYPE_3BYTE_BGR, TYPE_4BYTE_ABGR, + TYPE_4BYTE_ABGR_PRE, + /*TYPE_USHORT_565_RGB, + TYPE_USHORT_555_RGB, TYPE_BYTE_GRAY, + TYPE_USHORT_GRAY,*/ TYPE_BYTE_BINARY, + TYPE_BYTE_INDEXED, TYPE_CUSTOM}; + private static final int[] TRANSPARENCIES = {OPAQUE, BITMASK, TRANSLUCENT}; + + public static void main(final String[] args) throws IOException { + for (final int viType : TRANSPARENCIES) { + for (final int biType : TYPES) { + BufferedImage bi = makeUnmanagedBI(biType); + fill(bi); + test(bi, viType); + } + } + } + + private static void test(BufferedImage bi, int type) + throws IOException { + GraphicsEnvironment ge = GraphicsEnvironment + .getLocalGraphicsEnvironment(); + GraphicsConfiguration gc = ge.getDefaultScreenDevice() + .getDefaultConfiguration(); + VolatileImage vi = gc.createCompatibleVolatileImage(1000, 1000, type); + BufferedImage gold = gc.createCompatibleImage(1000, 1000, type); + // draw to compatible Image + init(gold); + Graphics2D big = gold.createGraphics(); + big.drawImage(bi, 7, 11, null); + big.dispose(); + // draw to volatile image + BufferedImage snapshot; + while (true) { + vi.validate(gc); + if (vi.validate(gc) != VolatileImage.IMAGE_OK) { + try { + Thread.sleep(100); + } catch (final InterruptedException ignored) { + } + continue; + } + init(vi); + Graphics2D vig = vi.createGraphics(); + vig.drawImage(bi, 7, 11, null); + vig.dispose(); + snapshot = vi.getSnapshot(); + if (vi.contentsLost()) { + try { + Thread.sleep(100); + } catch (final InterruptedException ignored) { + } + continue; + } + break; + } + // validate images + for (int x = 0; x < 1000; ++x) { + for (int y = 0; y < 1000; ++y) { + if (gold.getRGB(x, y) != snapshot.getRGB(x, y)) { + ImageIO.write(gold, "png", new File("gold.png")); + ImageIO.write(snapshot, "png", new File("bi.png")); + throw new RuntimeException("Test failed."); + } + } + } + } + + private static BufferedImage makeUnmanagedBI(final int type) { + final BufferedImage bi; + if (type == TYPE_CUSTOM) { + bi = makeCustomUnmanagedBI(); + } else { + bi = new BufferedImage(511, 255, type); + } + final DataBuffer db = bi.getRaster().getDataBuffer(); + if (db instanceof DataBufferInt) { + ((DataBufferInt) db).getData(); + } else if (db instanceof DataBufferShort) { + ((DataBufferShort) db).getData(); + } else if (db instanceof DataBufferByte) { + ((DataBufferByte) db).getData(); + } + bi.setAccelerationPriority(0.0f); + return bi; + } + + /** + * Returns the custom buffered image, which mostly identical to + * BufferedImage.(w,h,TYPE_3BYTE_BGR), but uses the bigger scanlineStride. + * This means that the raster will have gaps, between the rows. + */ + private static BufferedImage makeCustomUnmanagedBI() { + int w = 511, h = 255; + ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); + int[] nBits = {8, 8, 8}; + int[] bOffs = {2, 1, 0}; + ColorModel colorModel = new ComponentColorModel(cs, nBits, false, false, + Transparency.OPAQUE, + DataBuffer.TYPE_BYTE); + WritableRaster raster = + Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, w, h, + w * 3 + 2, 3, bOffs, null); + return new BufferedImage(colorModel, raster, true, null); + } + + private static void init(final Image image) { + final Graphics2D graphics = (Graphics2D) image.getGraphics(); + graphics.setComposite(AlphaComposite.Src); + graphics.setColor(new Color(0, 0, 0, 0)); + graphics.fillRect(0, 0, image.getWidth(null), image.getHeight(null)); + graphics.dispose(); + } + + private static void fill(final Image image) { + final Graphics2D graphics = (Graphics2D) image.getGraphics(); + graphics.setComposite(AlphaComposite.Src); + for (int i = 0; i < image.getHeight(null); ++i) { + graphics.setColor(new Color(i, 0, 0)); + graphics.fillRect(0, i, image.getWidth(null), 1); + } + graphics.dispose(); + } +} diff --git a/test/jdk/java/rmi/testlibrary/TestSocketFactory.java b/test/jdk/java/rmi/testlibrary/TestSocketFactory.java index 42a7146b0cc..ef44585a908 100644 --- a/test/jdk/java/rmi/testlibrary/TestSocketFactory.java +++ b/test/jdk/java/rmi/testlibrary/TestSocketFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 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 @@ -92,7 +92,8 @@ public class TestSocketFactory extends RMISocketFactory static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; - public static final boolean DEBUG = false; + // True to enable logging of matches and replacements. + private static volatile boolean debugLogging = false; /** * Debugging output can be synchronized with logging of RMI actions. @@ -100,8 +101,8 @@ public class TestSocketFactory extends RMISocketFactory * @param format a printf format * @param args any args */ - private static void DEBUG(String format, Object... args) { - if (DEBUG) { + public static void DEBUG(String format, Object... args) { + if (debugLogging) { System.err.printf(format, args); } } @@ -116,6 +117,17 @@ public TestSocketFactory() { this.replaceBytes = EMPTY_BYTE_ARRAY; } + /** + * Set debug to true to generate logging output of matches and substitutions. + * @param debug {@code true} to generate logging output + * @return the previous value + */ + public static boolean setDebug(boolean debug) { + boolean oldDebug = debugLogging; + debugLogging = debug; + return oldDebug; + } + /** * Set the match and replacement bytes, with an empty trigger. * The match and replacements are propagated to all existing sockets. diff --git a/test/jdk/java/security/testlibrary/Proc.java b/test/jdk/java/security/testlibrary/Proc.java index abbc86a33be..cff7e790e7e 100644 --- a/test/jdk/java/security/testlibrary/Proc.java +++ b/test/jdk/java/security/testlibrary/Proc.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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,9 @@ import java.io.File; import java.io.IOException; import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -110,6 +113,7 @@ public class Proc { private List args = new ArrayList<>(); private Map env = new HashMap<>(); private Map prop = new HashMap(); + private Map secprop = new HashMap(); private boolean inheritIO = false; private boolean noDump = false; @@ -176,6 +180,11 @@ public Proc prop(String a, String b) { prop.put(a, b); return this; } + // Specifies a security property. Can be called multiple times. + public Proc secprop(String a, String b) { + secprop.put(a, b); + return this; + } // Inherit the value of a system property public Proc inheritProp(String k) { String v = System.getProperty(k); @@ -282,6 +291,17 @@ public Proc start() throws IOException { cmd.add(cp.stream().collect(Collectors.joining(File.pathSeparator))); } + if (!secprop.isEmpty()) { + Path p = Path.of(getId("security")); + try (OutputStream fos = Files.newOutputStream(p); + PrintStream ps = new PrintStream(fos)) { + secprop.forEach((k,v) -> ps.println(k + "=" + v)); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + prop.put("java.security.properties", p.toString()); + } + for (Entry e: prop.entrySet()) { cmd.add("-D" + e.getKey() + "=" + e.getValue()); } @@ -380,6 +400,12 @@ public int waitFor() throws Exception { } return p.waitFor(); } + // Wait for process end with expected exit code + public void waitFor(int expected) throws Exception { + if (p.waitFor() != expected) { + throw new RuntimeException("Exit code not " + expected); + } + } // The following methods are used inside a proc diff --git a/test/jdk/sun/security/util/FilePermCompat/Flag.java b/test/jdk/sun/security/util/FilePermCompat/Flag.java index dab4cff5b14..00c7fbc2677 100644 --- a/test/jdk/sun/security/util/FilePermCompat/Flag.java +++ b/test/jdk/sun/security/util/FilePermCompat/Flag.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -23,22 +23,84 @@ /* * @test - * @bug 8164705 + * @bug 8164705 8209901 + * @library /test/jdk/java/security/testlibrary + * @modules java.base/jdk.internal.misc * @summary check jdk.filepermission.canonicalize - * @run main/othervm/policy=flag.policy - * -Djdk.io.permissionsUseCanonicalPath=true Flag true true - * @run main/othervm/policy=flag.policy - * -Djdk.io.permissionsUseCanonicalPath=false Flag false true - * @run main/othervm/policy=flag.policy Flag false true */ import java.io.File; import java.io.FilePermission; import java.lang.*; +import java.nio.file.Path; public class Flag { public static void main(String[] args) throws Exception { + if (args.length == 0) { + String policy = Path.of( + System.getProperty("test.src"), "flag.policy").toString(); + + // effectively true + Proc.create("Flag") + .prop("java.security.manager", "") + .prop("java.security.policy", policy) + .prop("jdk.io.permissionsUseCanonicalPath", "true") + .args("run", "true", "true") + .start() + .waitFor(0); + Proc.create("Flag") + .prop("java.security.manager", "") + .prop("java.security.policy", policy) + .secprop("jdk.io.permissionsUseCanonicalPath", "true") + .args("run", "true", "true") + .start() + .waitFor(0); + Proc.create("Flag") + .prop("java.security.manager", "") + .prop("java.security.policy", policy) + .secprop("jdk.io.permissionsUseCanonicalPath", "false") + .prop("jdk.io.permissionsUseCanonicalPath", "true") + .args("run", "true", "true") + .start() + .waitFor(0); + + // effectively false + Proc.create("Flag") + .prop("java.security.manager", "") + .prop("java.security.policy", policy) + .prop("jdk.io.permissionsUseCanonicalPath", "false") + .args("run", "false", "true") + .start() + .waitFor(0); + Proc.create("Flag") + .prop("java.security.manager", "") + .prop("java.security.policy", policy) + .secprop("jdk.io.permissionsUseCanonicalPath", "false") + .args("run", "false", "true") + .start() + .waitFor(0); + Proc.create("Flag") + .prop("java.security.manager", "") + .prop("java.security.policy", policy) + .secprop("jdk.io.permissionsUseCanonicalPath", "true") + .prop("jdk.io.permissionsUseCanonicalPath", "false") + .args("run", "false", "true") + .start() + .waitFor(0); + Proc.create("Flag") + .prop("java.security.manager", "") + .prop("java.security.policy", policy) + .args("run", "false", "true") + .start() + .waitFor(0); + } else { + run(args); + } + } + + static void run(String[] args) throws Exception { + boolean test1; boolean test2; @@ -55,8 +117,8 @@ public static void main(String[] args) throws Exception { test2 = false; } - if (test1 != Boolean.parseBoolean(args[0]) || - test2 != Boolean.parseBoolean(args[1])) { + if (test1 != Boolean.parseBoolean(args[1]) || + test2 != Boolean.parseBoolean(args[2])) { throw new Exception("Test failed: " + test1 + " " + test2); } } diff --git a/test/langtools/jdk/javadoc/tool/TestScriptInComment.java b/test/langtools/jdk/javadoc/tool/TestScriptInComment.java index 2b404fc8a2b..5167ba3ae06 100644 --- a/test/langtools/jdk/javadoc/tool/TestScriptInComment.java +++ b/test/langtools/jdk/javadoc/tool/TestScriptInComment.java @@ -25,7 +25,7 @@ /** * @test - * @bug 8138725 + * @bug 8138725 8226765 * @summary test --allow-script-in-comments * @modules jdk.javadoc/jdk.javadoc.internal.tool */ @@ -65,6 +65,10 @@ enum Comment { WS("< script >#ALERT", false, "-Xdoclint:none"), // script tag with invalid white space SP("", true), // script tag with an attribute ON("x", true), // event handler attribute + OME("1", true), // onmouseenter event handler attribute + OML("1", true), // onmouseleave event handler attribute + OFI("x", true), // onfocusin event handler attribute + OBE("x", true), // bogus/future event handler attribute URI("x", true); // javascript URI /**