/
githubmirror
/
riscv-port
Обзор
Документация
Войти
/
githubmirror
/
riscv-port
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/java.base/share/classes/jdk/internal/util/Exceptions.java
319 строк
11 KB
Michael McMahon
8362581: Timeouts in java/nio/channels/SocketChannel/OpenLeak.java on UNIX
27 июл 2025, 01:22
27 июл 2025, 01:22
de59da2
Код
Авторство
О чём код?
/* * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package jdk.internal.util; import java.io.IOException; import java.lang.reflect.Constructor; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.net.UnixDomainSocketAddress; import java.net.URISyntaxException; import java.util.Arrays; import java.util.function.Consumer; import java.util.stream.Stream; import sun.security.util.SecurityProperties; import jdk.internal.misc.VM; /** * Contains static utility methods which can filter exception * message strings for sensitive information. * * Code using this mechanism should use formatMsg() * to generate a formatted (enhanced or restricted) string for exception * messages. * * The methods above take variable numbers of SensitiveInfo objects * as parameters which contain the text that may have to be filtered. * * The SensitiveInfo objects should be generated with one of the following: * public static SensitiveInfo filterSocketInfo(String s) * public static SensitiveInfo filterNonSocketInfo(String s) * public static SensitiveInfo filterJarName(String name) * public static SensitiveInfo filterUserName(String name) */ public final class Exceptions { private Exceptions() {} private static volatile boolean enhancedSocketExceptionText; private static volatile boolean enhancedNonSocketExceptionText; private static volatile boolean enhancedUserExceptionText; private static volatile boolean enhancedJarExceptionText; private static volatile boolean initialized = false; /** * Base class for generating exception messages that may * contain sensitive information which in certain contexts * needs to be filtered out, in case it gets revealed in * unexpected places. Exception messages are either enhanced * or restricted. Enhanced messages include sensitive information. * Restricted messages don't. * * Sub-class for any new category that needs to be independently * controlled. Consider using a unique value for the * SecurityProperties.includedInExceptions(String value) mechanism * Current values defined are "jar", "userInfo" * "hostInfo", "hostInfoExclSocket". * * New code can also piggy back on existing categories * * A SensitiveInfo contains the following components * all of which default to empty strings. * * prefix, the sensitive info itself, a suffix * and a replacement string. * * The composeFilteredText(boolean enhance) method generates * an enhanced string when enhance is true. * This comprises (enhance == true) * prefix + info + suffix * When (enhance == false), then by default the output is: * "" empty string * However, if a replacement is set, then when enhance == false * the output is the replacement string. */ public abstract static class SensitiveInfo { String info, suffix, prefix, replacement; boolean enhanced; SensitiveInfo(String info) { this.info = info; prefix = suffix = replacement = ""; } public SensitiveInfo prefixWith(String prefix) { this.prefix = prefix; return this; } public SensitiveInfo suffixWith(String suffix) { this.suffix = suffix; return this; } public SensitiveInfo replaceWith(String replacement) { this.replacement = replacement; return this; } public boolean enhanced() { return enhanced; } /** * Implementation should call composeFilteredText(boolean flag) * where flag contains the boolean value of whether * the category is enabled or not. */ public abstract String output(); protected String composeFilteredText(boolean enhance) { if (enhance) { this.enhanced = true; return prefix + info + suffix; } else { return replacement; } } } static final class SocketInfo extends SensitiveInfo { public SocketInfo(String host) { super(host); } @Override public String output() { setup(); return super.composeFilteredText(enhancedSocketExceptionText); } } static final class NonSocketInfo extends SensitiveInfo { public NonSocketInfo(String host) { super(host); } @Override public String output() { setup(); return super.composeFilteredText(enhancedNonSocketExceptionText); } } static final class JarInfo extends SensitiveInfo { public JarInfo(String name) { super(name); } @Override public String output() { setup(); return super.composeFilteredText(enhancedJarExceptionText); } } static final class UserInfo extends SensitiveInfo { public UserInfo(String host) { super(host); } @Override public String output() { setup(); return super.composeFilteredText(enhancedUserExceptionText); } } // remove leading, trailing and duplicated space characters static String trim(String s) { int len = s.length(); if (len == 0) return s; StringBuilder sb = new StringBuilder(); // initial value deals with leading spaces boolean inSpace = true; for (int i=0; i<len; i++) { char c = s.charAt(i); if (c == ' ') { if (inSpace) continue; inSpace = true; } else inSpace = false; sb.append(c); } int sblen = sb.length(); // last char could be a space if (sblen > 0 && sb.charAt(sblen - 1) == ' ') sb.deleteCharAt(sblen - 1); return sb.toString(); } public static SensitiveInfo filterSocketInfo(String host) { return new SocketInfo(host); } public static SensitiveInfo filterNonSocketInfo(String host) { return new NonSocketInfo(host); } public static SensitiveInfo filterJarName(String name) { return new JarInfo(name); } public static SensitiveInfo filterUserName(String name) { return new UserInfo(name); } /** * Transform each SensitiveInfo into a String argument which is passed * to String.format(). This string is then trimmed. */ public static String formatMsg(String format, SensitiveInfo... infos) { String[] args = new String[infos.length]; int i = 0; for (SensitiveInfo info : infos) { args[i++] = info.output(); } return trim(String.format(format, (Object[])args)); } /** * Simplification of above. Equivalent to: * formatMsg("%s", SensitiveInfo[1]); // ie with one arg */ public static String formatMsg(SensitiveInfo info) { return trim(info.output()); } public static void setup() { if (initialized || !VM.isBooted()) return; enhancedSocketExceptionText = SecurityProperties.includedInExceptions("hostInfo"); enhancedNonSocketExceptionText = SecurityProperties.includedInExceptions("hostInfoExclSocket") | enhancedSocketExceptionText; enhancedUserExceptionText = SecurityProperties.includedInExceptions("userInfo"); enhancedJarExceptionText = SecurityProperties.INCLUDE_JAR_NAME_IN_EXCEPTIONS; initialized = true; } public static boolean enhancedNonSocketExceptions() { setup(); return enhancedNonSocketExceptionText; } public static boolean enhancedSocketExceptions() { setup(); return enhancedSocketExceptionText; } /** * The enhanced message text is the socket address appended to * the original IOException message */ public static IOException ioException(IOException e, SocketAddress addr) { setup(); if (!enhancedSocketExceptionText || addr == null) { return e; } if (addr instanceof UnixDomainSocketAddress) { return ofUnixDomain(e, (UnixDomainSocketAddress)addr); } else if (addr instanceof InetSocketAddress) { return ofInet(e, (InetSocketAddress)addr); } else { return e; } } private static IOException ofInet(IOException e, InetSocketAddress addr) { return create(e, String.join(": ", e.getMessage(), addr.toString())); } private static IOException ofUnixDomain(IOException e, UnixDomainSocketAddress addr) { String path = addr.getPath().toString(); StringBuilder sb = new StringBuilder(); sb.append(e.getMessage()); sb.append(": "); sb.append(path); String enhancedMsg = sb.toString(); return create(e, enhancedMsg); } // return a new instance of the same type with the given detail // msg, or if the type doesn't support detail msgs, return given // instance. private static <T extends Exception> T create(T e, String msg) { try { Class<? extends Exception> clazz = e.getClass(); @SuppressWarnings("unchecked") Constructor<T> ctor = (Constructor<T>)clazz.getConstructor(String.class); T e1 = (ctor.newInstance(msg)); e1.setStackTrace(e.getStackTrace()); return e1; } catch (Exception e0) { // Some eg AsynchronousCloseException have no detail msg return e; } } }