1 /*
  2  * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  */
 23 
 24 #include <string.h>
 25 #include "jvmti.h"
 26 
 27 extern "C" {
 28 
 29 static const char* EXP_INTERF_SIG = "LP/Q/HCInterf;";
 30 static const char* SIG_START      = "LP/Q/HiddenClassSig";
 31 static const char* IDENTITYOBJECT_IF = "Ljava/lang/IdentityObject;";
 32 static const size_t SIG_START_LEN = strlen(SIG_START);
 33 static const int    ACC_INTERFACE = 0x0200; // Interface class modifiers bit
 34 
 35 static jvmtiEnv *jvmti = NULL;
 36 static jint class_load_count = 0;
 37 static jint class_prep_count = 0;
 38 static bool failed = false;
 39 
 40 #define LOG0(str)             { printf(str); fflush(stdout); }
 41 #define LOG1(str, arg)        { printf(str, arg); fflush(stdout); }
 42 #define LOG2(str, arg1, arg2) { printf(str, arg1, arg2); fflush(stdout); }
 43 
 44 #define CHECK_JVMTI_ERROR(jni, err, msg) \
 45   if (err != JVMTI_ERROR_NONE) { \
 46     LOG1("CHECK_JVMTI_ERROR: JVMTI function returned error: %d\n", err); \
 47     jni->FatalError(msg); \
 48     return; \
 49   }
 50 
 51 /* Return the jmethodID of j.l.Class.isHidden() method. */
 52 static jmethodID
 53 is_hidden_mid(JNIEnv* jni) {
 54   char* csig = NULL;
 55   jint count = 0;
 56   jmethodID *methods = NULL;
 57   jclass clazz  = jni->FindClass("java/lang/Class");
 58   if (clazz == NULL) {
 59     jni->FatalError("is_hidden_mid: Error: FindClass returned NULL for java/lang/Class\n");
 60     return NULL;
 61   }
 62 
 63   // find the jmethodID of j.l.Class.isHidden() method
 64   jmethodID mid = jni->GetMethodID(clazz, "isHidden", "()Z");
 65   if (mid == NULL) {
 66     jni->FatalError("is_hidden_mid: Error in jni GetMethodID: Cannot find j.l.Class.isHidden method\n");
 67   }
 68   return mid;
 69 }
 70 
 71 /* Return true if the klass is hidden. */
 72 static bool
 73 is_hidden(JNIEnv* jni, jclass klass) {
 74   static jmethodID is_hid_mid = NULL;
 75 
 76   if (is_hid_mid == NULL) {
 77     is_hid_mid = is_hidden_mid(jni);
 78   }
 79   // invoke j.l.Class.isHidden() method
 80   bool res = jni->CallBooleanMethod(klass, is_hid_mid);
 81   if (jni->ExceptionCheck()) {
 82     jni->ExceptionDescribe();
 83     jni->FatalError("is_hidden: Exception in jni CallBooleanMethod\n");
 84   }
 85   return res;
 86 }
 87 
 88 /* Check the class signature matches the expected. */
 89 static void
 90 check_class_signature(jvmtiEnv* jvmti, JNIEnv* jni, jclass klass, bool is_hidden, const char* exp_sig) {
 91   jint class_modifiers = 0;
 92   char* sig = NULL;
 93   char* gsig = NULL;
 94   jvmtiError err;
 95 
 96   // get class signature
 97   err = jvmti->GetClassSignature(klass, &sig, &gsig);
 98   CHECK_JVMTI_ERROR(jni, err, "check_hidden_class: Error in JVMTI GetClassSignature");
 99 
100   LOG1("check_class_signature: class with sig: %s\n", sig);
101   LOG1("check_class_signature: class with gsig: %s\n", gsig);
102 
103   if (strcmp(sig, exp_sig) != 0) {
104     LOG2("check_class_signature: FAIL: Hidden class signature %s does not match expected: %s\n", sig, exp_sig);
105     failed = true;
106   }
107   if (is_hidden && gsig == NULL) {
108     LOG0("check_class_signature: FAIL: unexpected NULL generic signature for hidden class\n");
109     failed = true;
110   }
111 }
112 
113 /* Test hidden class flags: it should not be interface, array nor modifiable. */
114 static void
115 check_hidden_class_flags(jvmtiEnv* jvmti, JNIEnv* jni, jclass klass) {
116   jint modifiers = 0;
117   jboolean flag = false;
118   jvmtiError err;
119 
120   err = jvmti->GetClassModifiers(klass, &modifiers);
121   CHECK_JVMTI_ERROR(jni, err, "check_hidden_class_flags: Error in JVMTI GetClassModifiers");
122   LOG1("check_hidden_class_flags: hidden class modifiers: 0x%x\n", modifiers);
123   if ((modifiers & ACC_INTERFACE) != 0) {
124     LOG0("check_hidden_class_flags: FAIL: unexpected ACC_INTERFACE bit in hidden class modifiers\n");
125     failed = true;
126     return;
127   }
128 
129   err = jvmti->IsInterface(klass, &flag);
130   CHECK_JVMTI_ERROR(jni, err, "check_hidden_class_flags: Error in JVMTI IsInterface");
131   if (flag) {
132     LOG0("check_hidden_class_flags: FAIL: hidden class is not expected to be interface\n");
133     failed = true;
134     return;
135   }
136 
137   err = jvmti->IsArrayClass(klass, &flag);
138   CHECK_JVMTI_ERROR(jni, err, "check_hidden_class_flags: Error in JVMTI IsArrayClass");
139   if (flag) {
140     LOG0("check_hidden_class_flags: FAIL: hidden class is not expected to be array\n");
141     failed = true;
142     return;
143   }
144   err = jvmti->IsModifiableClass(klass, &flag);
145   CHECK_JVMTI_ERROR(jni, err, "check_hidden_class_flags: Error in JVMTI IsModifiableClass");
146   if (flag) {
147     LOG0("check_hidden_class_flags: FAIL: hidden class is not expected to be modifiable\n");
148     failed = true;
149   }
150 }
151 
152 /* Test GetClassLoaderClasses: it should not return any hidden classes. */
153 static void
154 check_hidden_class_loader(jvmtiEnv* jvmti, JNIEnv* jni, jclass klass) {
155   jint count = 0;
156   jobject loader = NULL;
157   jclass* loader_classes = NULL;
158   jboolean found = false;
159   jvmtiError err;
160 
161   err = jvmti->GetClassLoader(klass, &loader);
162   CHECK_JVMTI_ERROR(jni, err, "check_hidden_class_loader: Error in JVMTI GetClassLoader");
163 
164   jni->EnsureLocalCapacity(256); // to avoid warnings: JNI local refs NN exceeds capacity
165 
166   err = jvmti->GetClassLoaderClasses(loader, &count, &loader_classes);
167   CHECK_JVMTI_ERROR(jni, err, "check_hidden_class_loader: Error in JVMTI GetClassLoaderClasses");
168 
169   for (int idx = 0; idx < count; idx++) {
170     char* sig = NULL;
171     jclass kls = loader_classes[idx];
172 
173     // GetClassLoaderClasses should not return any hidden classes
174     if (!is_hidden(jni, kls)) {
175       continue;
176     }
177     // get class signature
178     err = jvmti->GetClassSignature(kls, &sig, NULL);
179     CHECK_JVMTI_ERROR(jni, err, "check_hidden_class_loader: Error in JVMTI GetClassSignature");
180 
181     LOG1("check_hidden_class_loader: FAIL: JVMTI GetClassLoaderClasses returned hidden class: %s\n", sig);
182     failed = true;
183     return;
184   }
185   LOG0("check_hidden_class_loader: not found hidden class in its loader classes as expected\n");
186 }
187 
188 /* Test the hidden class implements expected interface. */
189 static void
190 check_hidden_class_impl_interf(jvmtiEnv* jvmti, JNIEnv* jni, jclass klass) {
191   char* sig = NULL;
192   jint count = 0;
193   jclass* interfaces = NULL;
194   jvmtiError err;
195 
196   // check that hidden class implements just one interface (or two if IdentityObject has been injected)
197   err = jvmti->GetImplementedInterfaces(klass, &count, &interfaces);
198   CHECK_JVMTI_ERROR(jni, err, "check_hidden_class_impl_interf: Error in JVMTI GetImplementedInterfaces");
199   if (count != 1 && count != 2) {
200     LOG1("check_hidden_class_impl_interf: FAIL: implemented interfaces count: %d, expected to be in [1-2] range\n", count);
201     failed = true;
202     return;
203   }
204   bool found = false;
205   for (int i = 0; i < count; i++) {
206     // get interface signature
207     err = jvmti->GetClassSignature(interfaces[i], &sig, NULL);
208     CHECK_JVMTI_ERROR(jni, err, "check_hidden_class_impl_interf: Error in JVMTI GetClassSignature for implemented interface");
209     // check the interface signature is matching the expected
210     if (strcmp(sig, EXP_INTERF_SIG) == 0) {
211       found = true;
212     }
213   }
214 
215   if (!found) {
216     LOG2("check_hidden_class_impl_interf: FAIL: implemented interface signature: %s, expected to be: %s\n",
217            sig, EXP_INTERF_SIG);
218     failed = true;
219   }
220 }
221 
222 /* Test hidden class. */
223 static void
224 check_hidden_class(jvmtiEnv* jvmti, JNIEnv* jni, jclass klass, const char* exp_sig) {
225   char* source_file_name = NULL;
226 
227   LOG1("\n### Native agent: check_hidden_class started: class: %s\n", exp_sig);
228 
229   check_class_signature(jvmti, jni, klass, true /* not hidden */,  exp_sig);
230   if (failed) return;
231 
232   check_hidden_class_flags(jvmti, jni, klass);
233   if (failed) return;
234 
235   check_hidden_class_loader(jvmti, jni, klass);
236   if (failed) return;
237 
238   check_hidden_class_impl_interf(jvmti, jni, klass);
239   if (failed) return;
240 
241   LOG0("### Native agent: check_hidden_class finished\n");
242 }
243 
244 /* Test hidden class array. */
245 static void
246 check_hidden_class_array(jvmtiEnv* jvmti, JNIEnv* jni, jclass klass_array, const char* exp_sig) {
247   char* source_file_name = NULL;
248 
249   LOG1("\n### Native agent: check_hidden_class_array started: array: %s\n", exp_sig);
250 
251   check_class_signature(jvmti, jni, klass_array, false /* is hidden */, exp_sig);
252   if (failed) return;
253 
254   LOG0("### Native agent: check_hidden_class_array finished\n");
255 }
256 
257 /* Process a CLASS_LOAD or aClassPrepare event. */
258 static void process_class_event(jvmtiEnv* jvmti, JNIEnv* jni, jclass klass,
259                                 jint* event_count_ptr, const char* event_name) {
260   char* sig = NULL;
261   char* gsig = NULL;
262   jvmtiError err;
263 
264   // get class signature
265   err = jvmti->GetClassSignature(klass, &sig, &gsig);
266   CHECK_JVMTI_ERROR(jni, err, "ClassLoad event: Error in JVMTI GetClassSignature");
267 
268   // check if this is an expected class event for hidden class
269   if (strlen(sig) > strlen(SIG_START) &&
270       strncmp(sig, SIG_START, SIG_START_LEN) == 0 &&
271       is_hidden(jni, klass)) {
272     (*event_count_ptr)++;
273     if (gsig == NULL) {
274       LOG1("%s event: FAIL: GetClassSignature returned NULL generic signature for hidden class\n", event_name);
275       failed = true;
276     }
277     LOG2("%s event: hidden class with sig: %s\n", event_name, sig);
278     LOG2("%s event: hidden class with gsig: %s\n", event_name, gsig);
279   }
280 }
281 
282 /* Check CLASS_LOAD event is generated for the given hidden class. */
283 static void JNICALL
284 ClassLoad(jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jclass klass) {
285   process_class_event(jvmti, jni, klass, &class_load_count, "ClassLoad");
286 }
287 
288 /* Check CLASS_PREPARE event is generated for the given hidden class. */
289 static void JNICALL
290 ClassPrepare(jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jclass klass) {
291   process_class_event(jvmti, jni, klass, &class_prep_count, "ClassPrepare");
292 }
293 
294 /* Enable CLASS_LOAD event notification mode. */
295 static void JNICALL
296 VMInit(jvmtiEnv* jvmti, JNIEnv* jni, jthread thread) {
297   jvmtiError err;
298 
299   printf("VMInit event: SIG_START: %s, SIG_START_LEN: %d\n", SIG_START, (int)SIG_START_LEN);
300   fflush(stdout);
301 
302   // enable ClassLoad event notification mode
303   err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_CLASS_LOAD, NULL);
304   CHECK_JVMTI_ERROR(jni, err, "VMInit event: Error in enabling ClassLoad events notification");
305 
306   // enable ClassPrepare event notification mode
307   err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_CLASS_PREPARE, NULL);
308   CHECK_JVMTI_ERROR(jni, err, "VMInit event: Error in enabling ClassPrepare events notification");
309 }
310 
311 JNIEXPORT jint JNICALL
312 Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
313   jvmtiEventCallbacks callbacks;
314   jvmtiError err;
315 
316   LOG0("Agent_OnLoad: started\n");
317   if (jvm->GetEnv((void **) (&jvmti), JVMTI_VERSION) != JNI_OK) {
318     LOG0("Agent_OnLoad: Error in GetEnv in obtaining jvmtiEnv*\n");
319     failed = true;
320     return JNI_ERR;
321   }
322 
323   // set required event callbacks
324   memset(&callbacks, 0, sizeof(callbacks));
325   callbacks.ClassLoad = &ClassLoad;
326   callbacks.ClassPrepare = &ClassPrepare;
327   callbacks.VMInit = &VMInit;
328 
329   err = jvmti->SetEventCallbacks(&callbacks, sizeof(jvmtiEventCallbacks));
330   if (err != JVMTI_ERROR_NONE) {
331     LOG1("Agent_OnLoad: Error in JVMTI SetEventCallbacks: %d\n", err);
332     failed = true;
333     return JNI_ERR;
334   }
335 
336   // enable VM_INIT event notification mode
337   err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, NULL);
338   if (err != JVMTI_ERROR_NONE) {
339     LOG1("Agent_OnLoad: Error in JVMTI SetEventNotificationMode: %d\n", err);
340     failed = true;
341     return JNI_ERR;
342   }
343 
344   LOG0("Agent_OnLoad: finished\n");
345   return JNI_OK;
346 }
347 
348 /* Native method: checkHiddenClass(). */
349 JNIEXPORT void JNICALL
350 Java_P_Q_HiddenClassSigTest_checkHiddenClass(JNIEnv *jni, jclass klass, jclass hidden_klass, jstring exp_sig_str) {
351   const char* exp_sig = jni->GetStringUTFChars(exp_sig_str, NULL);
352 
353   if (exp_sig == NULL) {
354     jni->FatalError("check_hidden_class: Error: JNI GetStringChars returned NULL for jstring\n");
355     return;
356   }
357   check_hidden_class(jvmti, jni, hidden_klass, exp_sig);
358 
359   jni->ReleaseStringUTFChars(exp_sig_str, exp_sig);
360 }
361 
362 /* Native method: checkHiddenClassArray(). */
363 JNIEXPORT void JNICALL
364 Java_P_Q_HiddenClassSigTest_checkHiddenClassArray(JNIEnv *jni, jclass klass, jclass hidden_klass_array, jstring exp_sig_str) {
365   const char* exp_sig = jni->GetStringUTFChars(exp_sig_str, NULL);
366 
367   if (exp_sig == NULL) {
368     jni->FatalError("check_hidden_class_array: Error: JNI GetStringChars returned NULL for jstring\n");
369     return;
370   }
371   check_hidden_class_array(jvmti, jni, hidden_klass_array, exp_sig);
372 
373   jni->ReleaseStringUTFChars(exp_sig_str, exp_sig);
374 }
375 
376 /* Native method: checkFailed(). */
377 JNIEXPORT jboolean JNICALL
378 Java_P_Q_HiddenClassSigTest_checkFailed(JNIEnv *jni, jclass klass) {
379   if (class_load_count == 0) {
380     // expected ClassLoad event was not generated for hidden class
381     LOG0("Native Agent: FAIL: missed ClassLoad event for hidden class\n");
382     failed = true;
383   }
384   if (class_prep_count == 0) {
385     // expected ClassPrepare event was not generated for hidden class
386     LOG0("Native Agent: FAIL: missed ClassPrepare event for hidden class\n");
387     failed = true;
388   }
389   return failed;
390 }
391 
392 } // extern "C"