Skip to content

Commit

Permalink
Merge pull request #4876 from gacholio/ann
Browse files Browse the repository at this point in the history
Use a class annotation to prevent instrumentation
  • Loading branch information
DanHeidinga committed Mar 14, 2019
2 parents 7775dc3 + 68e3ebb commit 6f876cb
Show file tree
Hide file tree
Showing 16 changed files with 174 additions and 49 deletions.
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2001, 2018 IBM Corp. and others
* Copyright (c) 2001, 2019 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
Expand Down Expand Up @@ -556,7 +556,7 @@ public static void j9bcutil_dumpRomClass(PrintStream out, J9ROMClassPointer romC

out.append(String.format("Sun Access Flags (0x%s): ", Long.toHexString(romClass.modifiers().longValue())));
dumpModifiers(out, romClass.modifiers().longValue(), MODIFIERSOURCE_CLASS, ONLY_SPEC_MODIFIERS);

out.append(nl);
out.append(String.format("J9 Access Flags (0x%s): ", Long.toHexString(romClass.extraModifiers().longValue())));
dumpClassJ9ExtraModifiers(out, romClass.extraModifiers().longValue());
out.append(nl);
Expand Down Expand Up @@ -708,6 +708,8 @@ private static void dumpClassJ9ExtraModifiers(PrintStream out, long accessFlags)
out.append("(preverified) ");
if ((accessFlags & J9JavaAccessFlags.J9AccClassAnonClass) != 0)
out.append("(anonClass) ");
if ((accessFlags & J9JavaAccessFlags.J9AccClassIsUnmodifiable) != 0)
out.append("(unmodifiable) ");
}

private static void dumpEnclosingMethod(PrintStream out, J9ROMClassPointer romClass, long flags) throws CorruptDataException {
Expand Down
4 changes: 3 additions & 1 deletion jcl/src/java.base/share/classes/com/ibm/jit/JITHelpers.java
Expand Up @@ -3,7 +3,7 @@
package com.ibm.jit;

/*******************************************************************************
* Copyright (c) 1998, 2018 IBM Corp. and others
* Copyright (c) 1998, 2019 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
Expand All @@ -24,6 +24,7 @@
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
*******************************************************************************/

import com.ibm.oti.vm.J9UnmodifiableClass;
import java.lang.reflect.Field;
import java.lang.reflect.Array;
import com.ibm.oti.vm.VM;
Expand All @@ -41,6 +42,7 @@
* The <code>JITHelpers</code> class contains methods used by the JIT to optimize certain primitive operations.
*/
@SuppressWarnings("javadoc")
@J9UnmodifiableClass
public final class JITHelpers {

private static final JITHelpers helpers;
Expand Down
@@ -0,0 +1,41 @@
/*[INCLUDE-IF Sidecar17]*/
/*******************************************************************************
* Copyright (c) 2019, 2019 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
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
* or the Apache License, Version 2.0 which accompanies this distribution and
* is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* This Source Code may also be made available under the following
* Secondary Licenses when the conditions for such availability set
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
* General Public License, version 2 with the GNU Classpath
* Exception [1] and GNU General Public License, version 2 with the
* OpenJDK Assembly Exception [2].
*
* [1] https://www.gnu.org/software/classpath/license.html
* [2] http://openjdk.java.net/legal/assembly-exception.html
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
*******************************************************************************/

package com.ibm.oti.vm;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})

// WARNING: Do not rename or repackage this class without changing
// J9_UNMODIFIABLE_CLASS_ANNOTATION in j9.h to match. Under no
// circumstances include any character whose ASCII value is
// less than that of '/' (see canClassBeInstrumented in jvmtiHook.c).

public @interface J9UnmodifiableClass {
}

4 changes: 3 additions & 1 deletion jcl/src/java.base/share/classes/java/lang/J9VMInternals.java
Expand Up @@ -2,6 +2,7 @@

package java.lang;

import com.ibm.oti.vm.J9UnmodifiableClass;
import java.lang.ref.SoftReference;
import java.lang.reflect.*;
import java.security.AccessController;
Expand Down Expand Up @@ -30,7 +31,7 @@


/*******************************************************************************
* Copyright (c) 1998, 2018 IBM Corp. and others
* Copyright (c) 1998, 2019 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
Expand All @@ -51,6 +52,7 @@
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
*******************************************************************************/

@J9UnmodifiableClass
final class J9VMInternals {
/*[PR VMDESIGN 1891] Move j9Version and j9Config from Class to J9VMInternals */
/*[IF]*/
Expand Down
@@ -1,6 +1,6 @@
/*[INCLUDE-IF Sidecar19-SE]*/
/*******************************************************************************
* Copyright (c) 2017, 2017 IBM Corp. and others
* Copyright (c) 2017, 2019 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
Expand All @@ -22,6 +22,9 @@
*******************************************************************************/
package java.lang.invoke;

import com.ibm.oti.vm.J9UnmodifiableClass;

@J9UnmodifiableClass
class VarHandleInternal {
/*[IF ]*/
/* Methods with VarHandle send target
Expand Down
8 changes: 7 additions & 1 deletion runtime/bcutil/ClassFileOracle.cpp
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2001, 2018 IBM Corp. and others
* Copyright (c) 2001, 2019 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
Expand Down Expand Up @@ -56,6 +56,7 @@ ClassFileOracle::KnownAnnotation ClassFileOracle::_knownAnnotations[] = {
#define CONTENDED_SIGNATURE "Ljdk/internal/vm/annotation/Contended;"
{CONTENDED_SIGNATURE, sizeof(CONTENDED_SIGNATURE)},
#undef CONTENDED_SIGNATURE
{J9_UNMODIFIABLE_CLASS_ANNOTATION, sizeof(J9_UNMODIFIABLE_CLASS_ANNOTATION)},
{0, 0}
};

Expand Down Expand Up @@ -180,6 +181,7 @@ ClassFileOracle::ClassFileOracle(BufferManager *bufferManager, J9CfrClassFile *c
_nestMembers(NULL),
#endif /* J9VM_OPT_VALHALLA_NESTMATES */
_isClassContended(false),
_isClassUnmodifiable(context->isClassUnmodifiable()),
_isInnerClass(false)
{
Trc_BCU_Assert_NotEquals( classFile, NULL );
Expand Down Expand Up @@ -447,12 +449,16 @@ ClassFileOracle::walkAttributes()
knownAnnotations = addAnnotationBit(knownAnnotations, CONTENDED_ANNOTATION);
knownAnnotations = addAnnotationBit(knownAnnotations, JAVA8_CONTENDED_ANNOTATION);
}
knownAnnotations = addAnnotationBit(knownAnnotations, UNMODIFIABLE_ANNOTATION);
_annotationsAttribute = (J9CfrAttributeRuntimeVisibleAnnotations *)attrib;
if (0 == _annotationsAttribute->rawDataLength) {
UDATA foundAnnotations = walkAnnotations(_annotationsAttribute->numberOfAnnotations, _annotationsAttribute->annotations, knownAnnotations);
if (containsKnownAnnotation(foundAnnotations, CONTENDED_ANNOTATION) || containsKnownAnnotation(foundAnnotations, JAVA8_CONTENDED_ANNOTATION)) {
_isClassContended = true;
}
if (containsKnownAnnotation(foundAnnotations, UNMODIFIABLE_ANNOTATION)) {
_isClassUnmodifiable = true;
}
}
break;
}
Expand Down
5 changes: 4 additions & 1 deletion runtime/bcutil/ClassFileOracle.hpp
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2001, 2018 IBM Corp. and others
* Copyright (c) 2001, 2019 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
Expand Down Expand Up @@ -907,6 +907,7 @@ class NameAndTypeIterator
bool hasEmptyFinalizeMethod() const { return _hasEmptyFinalizeMethod; }
bool hasFinalFields() const { return _hasFinalFields; }
bool isClassContended() const { return _isClassContended; }
bool isClassUnmodifiable() const { return _isClassUnmodifiable; }
bool hasNonStaticNonAbstractMethods() const { return _hasNonStaticNonAbstractMethods; }
bool hasFinalizeMethod() const { return _hasFinalizeMethod; }
bool isCloneable() const { return _isCloneable; }
Expand Down Expand Up @@ -949,6 +950,7 @@ class NameAndTypeIterator
JDK_INTERNAL_REFLECT_CALLERSENSITIVE_ANNOTATION,
JAVA8_CONTENDED_ANNOTATION,
CONTENDED_ANNOTATION,
UNMODIFIABLE_ANNOTATION,
KNOWN_ANNOTATION_COUNT
};

Expand Down Expand Up @@ -988,6 +990,7 @@ class NameAndTypeIterator
bool _isSerializable;
bool _isSynthetic;
bool _isClassContended;
bool _isClassUnmodifiable;
bool _hasVerifyExcludeAttribute;
bool _hasFrameIteratorSkipAnnotation;
bool _hasClinit;
Expand Down
12 changes: 8 additions & 4 deletions runtime/bcutil/ROMClassBuilder.cpp
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2001, 2018 IBM Corp. and others
* Copyright (c) 2001, 2019 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
Expand Down Expand Up @@ -1064,7 +1064,7 @@ ROMClassBuilder::finishPrepareAndLaydown(
* + UNUSED
* + UNUSED
* + UNUSED
* + AccClassAnonClass;
* + AccClassAnonClass
*
* + AccSynthetic (matches Oracle modifier position)
* + AccClassUseBisectionSearch
Expand All @@ -1078,10 +1078,10 @@ ROMClassBuilder::finishPrepareAndLaydown(
*
* + AccClassBytecodesModified
* + AccClassHasEmptyFinalize
* + UNUSED
* + AccClassIsUnmodifiable
* + AccClassHasVerifyData
*
* + J9AccClassIsContended
* + AccClassIsContended
* + AccClassHasFinalFields
* + AccClassHasClinit
* + AccClassHasNonStaticNonAbstractMethods
Expand Down Expand Up @@ -1127,6 +1127,10 @@ ROMClassBuilder::computeExtraModifiers(ClassFileOracle *classFileOracle, ROMClas
modifiers |= J9AccClassIsContended;
}

if ( classFileOracle->isClassUnmodifiable() ) {
modifiers |= J9AccClassIsUnmodifiable;
}

U_32 classNameindex = classFileOracle->getClassNameIndex();

#define WEAK_NAME "java/lang/ref/WeakReference"
Expand Down
17 changes: 16 additions & 1 deletion runtime/bcutil/ROMClassCreationContext.hpp
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2001, 2018 IBM Corp. and others
* Copyright (c) 2001, 2019 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
Expand Down Expand Up @@ -223,6 +223,21 @@ class ROMClassCreationContext
bool isClassAnon() const { return J9_FINDCLASS_FLAG_ANON == (_findClassFlags & J9_FINDCLASS_FLAG_ANON); }
bool alwaysSplitBytecodes() const { return J9_ARE_ANY_BITS_SET(_bctFlags, BCT_AlwaysSplitBytecodes); }

bool isClassUnmodifiable() const {
bool unmodifiable = false;
if (NULL != _javaVM) {
if ((J2SE_VERSION(_javaVM) >= J2SE_V11) && isClassAnon()) {
unmodifiable = true;
} else if (NULL == J9VMJAVALANGOBJECT_OR_NULL(_javaVM)) {
/* Object is currently only allowed to be redefined in fast HCR */
if (areExtensionsEnabled(_javaVM)) {
unmodifiable = true;
}
}
}
return unmodifiable;
}

bool isIntermediateClassDataShareable() const {
bool shareable = false;
U_8 *intermediateData = getIntermediateClassDataFromPreviousROMClass();
Expand Down
63 changes: 48 additions & 15 deletions runtime/jvmti/jvmtiHook.c
Expand Up @@ -2231,26 +2231,59 @@ jvmtiHookGCCycleEnd(J9HookInterface** hook, UDATA eventNum, void* eventData, voi
}

/**
* Determines if the class described by <tt>classLoadData</tt> can
* Determines if the class described by <tt>data</tt> can
* be instrumented.
* @param classLoadData
* @param data The class file load hook event data
* @return TRUE if the class can be instrumented.
*/
static BOOLEAN
canClassBeInstrumented(J9VMClassLoadHookEvent* classLoadData)
{
BOOLEAN result = TRUE;

/* Skip any class that does not have a name specified */
if (classLoadData->className == NULL) {
result = FALSE;
} else if (strcmp(classLoadData->className, "java/lang/J9VMInternals") == 0) {
result = FALSE;
} else if (strcmp(classLoadData->className, "java/lang/invoke/VarHandleInternal") == 0) {
result = FALSE;
canClassBeInstrumented(J9VMClassLoadHookEvent* data)
{
BOOLEAN modifiable = TRUE;
/* Only clasess on the bootpath may be marked unmodifiable */
if (data->classLoader == data->currentThread->javaVM->systemClassLoader) {
U_8 *classData = data->classData;
UDATA const classDataLength = data->classDataLength;
UDATA const annotationLength = sizeof(J9_UNMODIFIABLE_CLASS_ANNOTATION_DATA);
/* Before the constant pool in the class file, there's at least:
*
* u4 magic
* u2 minor_version
* u2 major_version
* u2 constant_pool_count
*
* Totalling 10 bytes.
*/
UDATA const minimumSize = 10;
if (classDataLength > (annotationLength + minimumSize)) {
/* Make sure this at least looks like a class file */
if ((0xCA == classData[0]) && (0xFE == classData[1]) && (0xBA == classData[2]) && (0xBE == classData[3])) {
U_8 *dataEnd = classData + classDataLength - annotationLength;
classData += minimumSize;
/* Search for the bytes representing the UTF8 annotation name */
while (classData < dataEnd) {
static J9_UNMODIFIABLE_CLASS_ANNOTATION_DATA annotBytes = {
(char)1, /* tag byte for UTF8 in the constant pool */
(char)(LITERAL_STRLEN(J9_UNMODIFIABLE_CLASS_ANNOTATION) >> 8), /* high byte of size (big endian) */
(char)(LITERAL_STRLEN(J9_UNMODIFIABLE_CLASS_ANNOTATION) & 0xFF), /* low byte of size (big endian) */
J9_UNMODIFIABLE_CLASS_ANNOTATION /* UTF8 data */
};
UDATA scanSize = annotationLength;
U_8 *scanBytes = (U_8*)&annotBytes;
do {
if (*scanBytes++ != *classData++) {
goto notFound;
}
scanSize -= 1;
} while (0 != scanSize);
modifiable = FALSE;
break;
notFound: ;
}
}
}
}

return result;
return modifiable;
}


Expand Down
22 changes: 22 additions & 0 deletions runtime/oti/j9.h
Expand Up @@ -341,4 +341,26 @@ static const struct { \
#define J9_SHARED_CACHE_DEFAULT_BOOT_SHARING(vm) FALSE
#endif /* defined(OPENJ9_BUILD) */

/* Annotation name which indicates that a class is not allowed to be modified by
* JVMTI ClassFileLoadHook or RedefineClasses.
*/
#define J9_UNMODIFIABLE_CLASS_ANNOTATION "Lcom/ibm/oti/vm/J9UnmodifiableClass;"

typedef struct {
char tag;
char zero;
char size;
char data[LITERAL_STRLEN(J9_UNMODIFIABLE_CLASS_ANNOTATION)];
} J9_UNMODIFIABLE_CLASS_ANNOTATION_DATA;

#if defined(__cplusplus)
static_assert((sizeof(J9_UNMODIFIABLE_CLASS_ANNOTATION_DATA) == (3 + LITERAL_STRLEN(J9_UNMODIFIABLE_CLASS_ANNOTATION))), "Annotation structure is not packed correctly");
/* '/' is the lowest numbered character which appears in the annotation name (assume
* that no '$' exists in there). The name length must be smaller than '/' in order
* to ensure that there are no overlapping substrings which would mandate a more
* complex matching algorithm.
*/
static_assert((LITERAL_STRLEN(J9_UNMODIFIABLE_CLASS_ANNOTATION) < (size_t)'/'), "Annotation contains invalid characters");
#endif /* __cplusplus */

#endif /* J9_H */
1 change: 1 addition & 0 deletions runtime/oti/j9javaaccessflags.h
Expand Up @@ -47,6 +47,7 @@
#define J9AccClassHasBeenOverridden 0x100000
#define J9AccClassHasClinit 0x4000000
#define J9AccClassHasEmptyFinalize 0x200000
#define J9AccClassIsUnmodifiable 0x400000
#define J9AccClassHasFinalFields 0x2000000
#define J9AccClassHasJDBCNatives 0x400000
#define J9AccClassHasNonStaticNonAbstractMethods 0x8000000
Expand Down
1 change: 1 addition & 0 deletions runtime/oti/j9modifiers_api.h
Expand Up @@ -64,6 +64,7 @@
#define J9ROMCLASS_FINALIZE_NEEDED(romClass) _J9ROMCLASS_J9MODIFIER_IS_SET((romClass), J9AccClassFinalizeNeeded)
#define J9ROMCLASS_IS_CLONEABLE(romClass) _J9ROMCLASS_J9MODIFIER_IS_SET((romClass), J9AccClassCloneable)
#define J9ROMCLASS_ANNOTATION_REFERS_DOUBLE_SLOT_ENTRY(romClass) _J9ROMCLASS_J9MODIFIER_IS_SET((romClass), J9AccClassAnnnotionRefersDoubleSlotEntry)
#define J9ROMCLASS_IS_UNMODIFIABLE(romClass) _J9ROMCLASS_J9MODIFIER_IS_SET((romClass), J9AccClassIsUnmodifiable)

/*
* Note that resolvefield ignores this flag if the cache line size cannot be determined.
Expand Down

0 comments on commit 6f876cb

Please sign in to comment.