diff --git a/src/java.base/share/native/libjava/jni_util.c b/src/java.base/share/native/libjava/jni_util.c index baeaf4883ab..b7dc5670613 100644 --- a/src/java.base/share/native/libjava/jni_util.c +++ b/src/java.base/share/native/libjava/jni_util.c @@ -434,7 +434,7 @@ newString8859_1(JNIEnv *env, const char *str) } static const char* -getString8859_1Chars(JNIEnv *env, jstring jstr) +getString8859_1Chars(JNIEnv *env, jstring jstr, jboolean strict) { int i; char *result; @@ -453,6 +453,13 @@ getString8859_1Chars(JNIEnv *env, jstring jstr) for (i=0; iReleaseStringCritical(env, jstr, str); + free(result); + JNU_ThrowIllegalArgumentException(env, "NUL character not allowed in platform string"); + return 0; + } + if (unicode <= 0x00ff) result[i] = (char)unicode; else @@ -502,7 +509,7 @@ newString646_US(JNIEnv *env, const char *str) } static const char* -getString646_USChars(JNIEnv *env, jstring jstr) +getString646_USChars(JNIEnv *env, jstring jstr, jboolean strict) { int i; char *result; @@ -521,6 +528,12 @@ getString646_USChars(JNIEnv *env, jstring jstr) for (i=0; iReleaseStringCritical(env, jstr, str); + free(result); + JNU_ThrowIllegalArgumentException(env, "NUL character not allowed in platform string"); + return 0; + } if (unicode <= 0x007f ) result[i] = (char)unicode; else @@ -577,7 +590,7 @@ newStringCp1252(JNIEnv *env, const char *str) } static const char* -getStringCp1252Chars(JNIEnv *env, jstring jstr) +getStringCp1252Chars(JNIEnv *env, jstring jstr, jboolean strict) { int i; char *result; @@ -596,6 +609,13 @@ getStringCp1252Chars(JNIEnv *env, jstring jstr) for (i=0; iReleaseStringCritical(env, jstr, str); + free(result); + JNU_ThrowIllegalArgumentException(env, + "NUL character not allowed in platform string"); + return 0; + } if (c < 256) { if ((c >= 0x80) && (c <= 0x9f)) { result[i] = '?'; @@ -814,13 +834,22 @@ JNU_NewStringPlatform(JNIEnv *env, const char *str) return newStringJava(env, str); } +static const char * +getStringPlatformChars0(JNIEnv *env, jstring jstr, jboolean *isCopy, jboolean); + JNIEXPORT const char * GetStringPlatformChars(JNIEnv *env, jstring jstr, jboolean *isCopy) { - return JNU_GetStringPlatformChars(env, jstr, isCopy); + return getStringPlatformChars0(env, jstr, isCopy, JNI_FALSE); } -static const char* getStringBytes(JNIEnv *env, jstring jstr) { +JNIEXPORT const char * +GetStringPlatformCharsStrict(JNIEnv *env, jstring jstr, jboolean *isCopy) +{ + return getStringPlatformChars0(env, jstr, isCopy, JNI_TRUE); +} + +static const char* getStringBytes(JNIEnv *env, jstring jstr, jboolean strict) { char *result = NULL; jbyteArray hab = 0; @@ -839,15 +868,25 @@ static const char* getStringBytes(JNIEnv *env, jstring jstr) { } (*env)->GetByteArrayRegion(env, hab, 0, len, (jbyte *)result); result[len] = 0; /* NULL-terminate */ + if (strict) { + for (int i=0; iDeleteLocalRef(env, hab); } return result; } static const char* -getStringUTF8(JNIEnv *env, jstring jstr) +getStringUTF8(JNIEnv *env, jstring jstr, jboolean strict) { int i; char *result; @@ -858,7 +897,7 @@ getStringUTF8(JNIEnv *env, jstring jstr) int ri; jbyte coder = (*env)->GetByteField(env, jstr, String_coder_ID); if (coder != java_lang_String_LATIN1) { - return getStringBytes(env, jstr); + return getStringBytes(env, jstr, strict); } if ((*env)->EnsureLocalCapacity(env, 2) < 0) { return NULL; @@ -875,6 +914,11 @@ getStringUTF8(JNIEnv *env, jstring jstr) rlen = len; // we need two bytes for each latin-1 char above 127 (negative jbytes) for (i = 0; i < len; i++) { + if (strict && str[i] == 0) { + (*env)->ReleasePrimitiveArrayCritical(env, value, str, 0); + JNU_ThrowIllegalArgumentException(env, "NUL character not allowed in platform string"); + return NULL; + } if (str[i] < 0) { rlen++; } @@ -903,24 +947,36 @@ getStringUTF8(JNIEnv *env, jstring jstr) JNIEXPORT const char * JNICALL JNU_GetStringPlatformChars(JNIEnv *env, jstring jstr, jboolean *isCopy) +{ + return getStringPlatformChars0(env, jstr, isCopy, JNI_FALSE); +} + +JNIEXPORT const char * JNICALL +JNU_GetStringPlatformCharsStrict(JNIEnv *env, jstring jstr, jboolean *isCopy) +{ + return getStringPlatformChars0(env, jstr, isCopy, JNI_TRUE); +} + +static const char * +getStringPlatformChars0(JNIEnv *env, jstring jstr, jboolean *isCopy, jboolean strict) { if (isCopy) *isCopy = JNI_TRUE; if (fastEncoding == FAST_UTF_8) - return getStringUTF8(env, jstr); + return getStringUTF8(env, jstr, strict); if (fastEncoding == FAST_8859_1) - return getString8859_1Chars(env, jstr); + return getString8859_1Chars(env, jstr, strict); if (fastEncoding == FAST_646_US) - return getString646_USChars(env, jstr); + return getString646_USChars(env, jstr, strict); if (fastEncoding == FAST_CP1252) - return getStringCp1252Chars(env, jstr); + return getStringCp1252Chars(env, jstr, strict); if (fastEncoding == NO_ENCODING_YET) { JNU_ThrowInternalError(env, "platform encoding not initialized"); return 0; } else - return getStringBytes(env, jstr); + return getStringBytes(env, jstr, strict); } JNIEXPORT void JNICALL diff --git a/src/java.base/share/native/libjava/jni_util.h b/src/java.base/share/native/libjava/jni_util.h index d924c05fc1a..238a20b18ea 100644 --- a/src/java.base/share/native/libjava/jni_util.h +++ b/src/java.base/share/native/libjava/jni_util.h @@ -99,9 +99,28 @@ JNU_ThrowIOExceptionWithMessageAndLastError(JNIEnv *env, const char *message); JNIEXPORT const char * GetStringPlatformChars(JNIEnv *env, jstring jstr, jboolean *isCopy); +/* Convert between Java strings and i18n C strings + * Performs additional sanity checks on converted string + * such as presence of null characters which are not allowed. + * NULL may be returned with IllegalArgumentException pending + */ +JNIEXPORT const char * +GetStringPlatformCharsStrict(JNIEnv *env, jstring jstr, jboolean *isCopy); + JNIEXPORT jstring JNICALL JNU_NewStringPlatform(JNIEnv *env, const char *str); +/* Convert between Java strings and i18n C strings + * Performs additional sanity checks on converted string + * such as presence of null characters which are not allowed. + * NULL may be returned with IllegalArgumentException pending + */ +JNIEXPORT const char * JNICALL +JNU_GetStringPlatformCharsStrict(JNIEnv *env, jstring jstr, jboolean *isCopy); + +/* Convert between Java strings and i18n C strings + * Deprecated: Use JNU_GetStringPlatformCharsStrict + */ JNIEXPORT const char * JNICALL JNU_GetStringPlatformChars(JNIEnv *env, jstring jstr, jboolean *isCopy); diff --git a/src/java.base/unix/native/libnet/Inet4AddressImpl.c b/src/java.base/unix/native/libnet/Inet4AddressImpl.c index 4b4d8812c8e..4db86234b23 100644 --- a/src/java.base/unix/native/libnet/Inet4AddressImpl.c +++ b/src/java.base/unix/native/libnet/Inet4AddressImpl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2023, 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 @@ -100,7 +100,7 @@ Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, JNU_ThrowNullPointerException(env, "host argument is null"); return NULL; } - hostname = JNU_GetStringPlatformChars(env, host, NULL); + hostname = JNU_GetStringPlatformCharsStrict(env, host, NULL); CHECK_NULL_RETURN(hostname, NULL); // try once, with our static buffer diff --git a/src/java.base/unix/native/libnet/Inet6AddressImpl.c b/src/java.base/unix/native/libnet/Inet6AddressImpl.c index 41094dff321..a28b2f99be0 100644 --- a/src/java.base/unix/native/libnet/Inet6AddressImpl.c +++ b/src/java.base/unix/native/libnet/Inet6AddressImpl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2023, 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 @@ -219,7 +219,7 @@ Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, JNU_ThrowNullPointerException(env, "host argument is null"); return NULL; } - hostname = JNU_GetStringPlatformChars(env, host, NULL); + hostname = JNU_GetStringPlatformCharsStrict(env, host, NULL); CHECK_NULL_RETURN(hostname, NULL); // try once, with our static buffer diff --git a/src/java.base/windows/native/libnet/Inet4AddressImpl.c b/src/java.base/windows/native/libnet/Inet4AddressImpl.c index 33f379024c0..97f3ef4e8e1 100644 --- a/src/java.base/windows/native/libnet/Inet4AddressImpl.c +++ b/src/java.base/windows/native/libnet/Inet4AddressImpl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2023, 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 @@ -76,7 +76,7 @@ Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, JNU_ThrowNullPointerException(env, "host argument is null"); return NULL; } - hostname = JNU_GetStringPlatformChars(env, host, NULL); + hostname = JNU_GetStringPlatformCharsStrict(env, host, NULL); CHECK_NULL_RETURN(hostname, NULL); // try once, with our static buffer diff --git a/src/java.base/windows/native/libnet/Inet6AddressImpl.c b/src/java.base/windows/native/libnet/Inet6AddressImpl.c index a011b2fe5fa..324024c842e 100644 --- a/src/java.base/windows/native/libnet/Inet6AddressImpl.c +++ b/src/java.base/windows/native/libnet/Inet6AddressImpl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2023, 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 @@ -71,7 +71,7 @@ Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, JNU_ThrowNullPointerException(env, "host argument is null"); return NULL; } - hostname = JNU_GetStringPlatformChars(env, host, NULL); + hostname = JNU_GetStringPlatformCharsStrict(env, host, NULL); CHECK_NULL_RETURN(hostname, NULL); // try once, with our static buffer diff --git a/src/java.base/windows/native/libnet/NTLMAuthSequence.c b/src/java.base/windows/native/libnet/NTLMAuthSequence.c index 1309a9c3da2..3864ceedd51 100644 --- a/src/java.base/windows/native/libnet/NTLMAuthSequence.c +++ b/src/java.base/windows/native/libnet/NTLMAuthSequence.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2023, 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 @@ -79,18 +79,18 @@ JNIEXPORT jlong JNICALL Java_sun_net_www_protocol_http_ntlm_NTLMAuthSequence_get SECURITY_STATUS ss = SEC_E_INTERNAL_ERROR; if (user != 0) { - pUser = JNU_GetStringPlatformChars(env, user, &isCopy); + pUser = JNU_GetStringPlatformCharsStrict(env, user, &isCopy); if (pUser == NULL) return 0; // pending Exception } if (domain != 0) { - pDomain = JNU_GetStringPlatformChars(env, domain, &isCopy); + pDomain = JNU_GetStringPlatformCharsStrict(env, domain, &isCopy); if (pDomain == NULL) { goto cleanup; } } if (password != 0) { - pPassword = JNU_GetStringPlatformChars(env, password, &isCopy); + pPassword = JNU_GetStringPlatformCharsStrict(env, password, &isCopy); if (pPassword == NULL) { goto cleanup; } diff --git a/test/jdk/java/net/InetAddress/NullCharInHostnameDriver.java b/test/jdk/java/net/InetAddress/NullCharInHostnameDriver.java new file mode 100644 index 00000000000..931470f9df2 --- /dev/null +++ b/test/jdk/java/net/InetAddress/NullCharInHostnameDriver.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8300038 + * @modules java.base/java.net + * @compile/module=java.base java/net/NullCharInHostname.java + * @summary Make new version of JNU_GetStringPlatformChars which checks for null characters + * @run main/othervm java.base/java.net.NullCharInHostname + * @run main/othervm -Dfile.encoding=COMPAT java.base/java.net.NullCharInHostname + */ + +public class NullCharInHostnameDriver { } diff --git a/test/jdk/java/net/InetAddress/java.base/java/net/NullCharInHostname.java b/test/jdk/java/net/InetAddress/java.base/java/net/NullCharInHostname.java new file mode 100644 index 00000000000..a78c41398ce --- /dev/null +++ b/test/jdk/java/net/InetAddress/java.base/java/net/NullCharInHostname.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2023, 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. + */ + +package java.net; + +import java.net.spi.InetAddressResolver.LookupPolicy; + +public class NullCharInHostname { + public static void main(String[] args) { + var name = "foo\u0000bar"; + System.out.println("file.encoding = " + System.getProperty("file.encoding")); + System.out.println("native.encoding = " + System.getProperty("native.encoding")); + + // This should throw IAE as it calls the internal impl + try { + var impl = new Inet6AddressImpl(); + var addrs = impl.lookupAllHostAddr(name, LookupPolicy.of(LookupPolicy.IPV4)); + } catch (UnknownHostException e0) { + throw new RuntimeException(e0); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } + + // This should throw UHE as before and not IAE for compatibility + try { + var addrs = InetAddress.getByName(name); + } catch (IllegalArgumentException e) { + throw new RuntimeException(e); + } catch (UnknownHostException e0) { + e0.printStackTrace(); + } + } +}