From e473dae488c107849db2f6c0370a26812d6401cf Mon Sep 17 00:00:00 2001 From: Mike Zhang Date: Wed, 23 Sep 2020 16:33:53 -0400 Subject: [PATCH] (v0.23) Disallow MUE in class file UTF8 In versions 48 and above, no MUE is allowed. In 47 and below, the character '/' is not allowed in class names. Signed-off-by: Mike Zhang --- runtime/bcutil/bcutil.c | 26 ++++++++++++++++++-- runtime/bcutil/cfreader.c | 30 ++++++++++++++++-------- runtime/bcutil/test/natives/bcunatives.c | 4 ++-- runtime/oti/bcutil_api.h | 3 ++- runtime/oti/cfr.h | 3 +++ 5 files changed, 51 insertions(+), 15 deletions(-) diff --git a/runtime/bcutil/bcutil.c b/runtime/bcutil/bcutil.c index 01a4a926a24..faea621d0cd 100644 --- a/runtime/bcutil/bcutil.c +++ b/runtime/bcutil/bcutil.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 1991, 2019 IBM Corp. and others + * Copyright (c) 1991, 2020 IBM Corp. and others * * This program and the accompanying materials are made available under * the terms of the Eclipse Public License 2.0 which accompanies this @@ -222,17 +222,27 @@ bcutil_J9VMDllMain(J9JavaVM* vm, IDATA stage, void* reserved) This function ignores surrogates and treats them as two separate three byte encodings. This is valid. + The bit CFR_FOUND_CHARS_IN_EXTENDED_MUE_FORM is set in mueAsciiStatus if a + non-null UTF character is extended using modified UTF-8 (MUE)format, + similar to the null character. For classfile versions 48 and up, the JVM is + supposed to reject MUE characters. + The bit CFR_FOUND_SEPARATOR_IN_MUE_FORM is set in mueAsciiStatus if the + character '/' was found in MUE form, which is specifically + disallowed in class names even for classfile version 47 and lower. + If mueAsciiStatus is left NULL it is not used. + Returns compressed length or -1. */ I_32 -j9bcutil_verifyCanonisizeAndCopyUTF8 (U_8 *dest, U_8 *source, U_32 length) +j9bcutil_verifyCanonisizeAndCopyUTF8 (U_8 *dest, U_8 *source, U_32 length, U_8 *mueAsciiStatus) { U_8 *originalDest = dest; U_8 *originalSource = source; U_8 *sourceEnd = source + length; UDATA firstByte, nextByte, outWord, charLength, compression = 0; I_32 result = -1; + U_8 mueStatus = 0; Trc_BCU_verifyCanonisizeAndCopyUTF8_Entry(dest, source, length); @@ -291,6 +301,10 @@ j9bcutil_verifyCanonisizeAndCopyUTF8 (U_8 *dest, U_8 *source, U_32 length) /* Overwrite the multibyte UTF8 character only if shorter */ if ((outWord != 0) && (outWord < 0x80)) { + /* character '/' handled specially in class name utf8 */ + if ((UDATA)'/' == outWord) { + mueStatus |= CFR_FOUND_SEPARATOR_IN_MUE_FORM; + } /* One byte must be shorter in here */ dest = originalDest + (source - originalSource - charLength - compression); *dest++ = (U_8) outWord; @@ -306,8 +320,16 @@ j9bcutil_verifyCanonisizeAndCopyUTF8 (U_8 *dest, U_8 *source, U_32 length) } } + if (compression > 0) { + mueStatus |= CFR_FOUND_CHARS_IN_EXTENDED_MUE_FORM; + } + result = (I_32) (length - compression); + if (NULL != mueAsciiStatus) { + *mueAsciiStatus = mueStatus; + } + fail: Trc_BCU_verifyCanonisizeAndCopyUTF8_Exit(result); diff --git a/runtime/bcutil/cfreader.c b/runtime/bcutil/cfreader.c index fc1763217e7..d80f9f406f8 100644 --- a/runtime/bcutil/cfreader.c +++ b/runtime/bcutil/cfreader.c @@ -1228,9 +1228,11 @@ readPool(J9CfrClassFile* classfile, U_8* data, U_8* dataEnd, U_8* segment, U_8* return -2; } CHECK_EOF(size); - verifyResult = j9bcutil_verifyCanonisizeAndCopyUTF8(info->bytes, index, size); + verifyResult = j9bcutil_verifyCanonisizeAndCopyUTF8(info->bytes, index, size, &(info->flags1)); info->slot1 = (U_32) verifyResult; - if (verifyResult < 0) { + if ((verifyResult < 0) || + (J9_ARE_ALL_BITS_SET(info->flags1, CFR_FOUND_CHARS_IN_EXTENDED_MUE_FORM) && (classfile->majorVersion >= 48)) + ) { errorCode = J9NLS_CFR_ERR_BAD_UTF8__ID; offset = (U_32) (index - data - 1); goto _errorFound; @@ -2587,7 +2589,7 @@ checkClass(J9PortLibrary *portLib, J9CfrClassFile* classfile, U_8* segment, U_32 goto _errorFound; } - if((value & CFR_ACC_FINAL)&&(value & CFR_ACC_ABSTRACT)) { + if ((value & CFR_ACC_FINAL)&&(value & CFR_ACC_ABSTRACT)) { errorCode = J9NLS_CFR_ERR_FINAL_ABSTRACT_CLASS__ID; offset = endOfConstantPool; goto _errorFound; @@ -2602,39 +2604,47 @@ checkClass(J9PortLibrary *portLib, J9CfrClassFile* classfile, U_8* segment, U_32 } value = classfile->thisClass; - if((!value)||(value >= classfile->constantPoolCount)) { + if ((!value)||(value >= classfile->constantPoolCount)) { errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID; offset = endOfConstantPool + 2; goto _errorFound; } - if((classfile->constantPool)&&(classfile->constantPool[value].tag != CFR_CONSTANT_Class)) { + if ((classfile->constantPool) && (classfile->constantPool[value].tag != CFR_CONSTANT_Class)) { errorCode = J9NLS_CFR_ERR_NOT_CLASS__ID; offset = endOfConstantPool + 2; goto _errorFound; } + if ((classfile->constantPool) && (CFR_CONSTANT_Class == classfile->constantPool[value].tag)) { + value = classfile->constantPool[classfile->thisClass].slot1; + if (J9_ARE_ALL_BITS_SET(classfile->constantPool[value].flags1, CFR_FOUND_SEPARATOR_IN_MUE_FORM) && (classfile->majorVersion < 48)) { + errorCode = J9NLS_CFR_ERR_BAD_CLASS_NAME__ID; + offset = endOfConstantPool + 2; + goto _errorFound; + } + } value = classfile->superClass; - if(value >= classfile->constantPoolCount) { + if (value >= classfile->constantPoolCount) { errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID; offset = endOfConstantPool + 4; goto _errorFound; } - if(value == 0) { + if (0 == value) { /* Check against j.l.O. */ if(!utf8Equal(&classfile->constantPool[classfile->constantPool[classfile->thisClass].slot1], "java/lang/Object", 16)) { errorCode = J9NLS_CFR_ERR_NULL_SUPER__ID; offset = endOfConstantPool + 4; goto _errorFound; } - } else if(classfile->constantPool[value].tag != CFR_CONSTANT_Class) { + } else if (classfile->constantPool[value].tag != CFR_CONSTANT_Class) { errorCode = J9NLS_CFR_ERR_SUPER_NOT_CLASS__ID; offset = endOfConstantPool + 4; goto _errorFound; } - for(i = 0; i < classfile->interfacesCount; i++) { + for (i = 0; i < classfile->interfacesCount; i++) { U_32 j; J9CfrConstantPoolInfo* cpInfo; value = classfile->interfaces[i]; @@ -2662,7 +2672,7 @@ checkClass(J9PortLibrary *portLib, J9CfrClassFile* classfile, U_8* segment, U_32 } /* Check that interfaces subclass object. */ - if(classfile->accessFlags & CFR_ACC_INTERFACE) { + if (classfile->accessFlags & CFR_ACC_INTERFACE) { /* Check against j.l.O. */ if(!utf8Equal(&classfile->constantPool[classfile->constantPool[classfile->superClass].slot1], "java/lang/Object", 16)) { errorCode = J9NLS_CFR_ERR_INTERFACE_SUPER_NOT_OBJECT__ID; diff --git a/runtime/bcutil/test/natives/bcunatives.c b/runtime/bcutil/test/natives/bcunatives.c index 388674b2ab9..0a514201b14 100644 --- a/runtime/bcutil/test/natives/bcunatives.c +++ b/runtime/bcutil/test/natives/bcunatives.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2001, 2014 IBM Corp. and others + * Copyright (c) 2001, 2020 IBM Corp. and others * * This program and the accompanying materials are made available under * the terms of the Eclipse Public License 2.0 which accompanies this @@ -55,7 +55,7 @@ Java_com_ibm_j9_test_bcutil_TestNatives_verifyCanonisizeAndCopyUTF8(JNIEnv *env, src[i] = (char) jSrc[i]; } - result = j9bcutil_verifyCanonisizeAndCopyUTF8(dest, src, length); + result = j9bcutil_verifyCanonisizeAndCopyUTF8(dest, src, length, NULL); for (i =0; i < length; i++) { jDest[i] = dest[i]; diff --git a/runtime/oti/bcutil_api.h b/runtime/oti/bcutil_api.h index c1d0cada70b..ed03ae8af6a 100644 --- a/runtime/oti/bcutil_api.h +++ b/runtime/oti/bcutil_api.h @@ -141,10 +141,11 @@ j9bcutil_freeTranslationBuffers (J9PortLibrary * portLib, J9TranslationBufferSet * @param *dest * @param *source * @param length +* @param mueAsciiStatus If any non-null ASCII characters are represented in modified UTF-8 2 byte format instead of in 1 byte * @return I_32 */ I_32 -j9bcutil_verifyCanonisizeAndCopyUTF8 (U_8 *dest, U_8 *source, U_32 length); +j9bcutil_verifyCanonisizeAndCopyUTF8 (U_8 *dest, U_8 *source, U_32 length, U_8 *mueAsciiStatus); /** diff --git a/runtime/oti/cfr.h b/runtime/oti/cfr.h index e268fd9ccf3..514665d76d9 100644 --- a/runtime/oti/cfr.h +++ b/runtime/oti/cfr.h @@ -945,6 +945,9 @@ typedef struct J9CfrClassFile { #define ANON_CLASSNAME_CHARACTER_SEPARATOR '/' +#define CFR_FOUND_CHARS_IN_EXTENDED_MUE_FORM 0x1 +#define CFR_FOUND_SEPARATOR_IN_MUE_FORM 0x2 + #ifdef __cplusplus } #endif