1 /*
  2  * Copyright (c) 2019, 2024, 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 #include "jvmti_common.hpp"
 27 
 28 extern "C" {
 29 
 30 static const char* EXP_INTERF_SIG = "LP/Q/HCInterf;";
 31 static const char* SIG_START      = "LP/Q/HiddenClassSig";
 32 static const char* IDENTITYOBJECT_IF = "Ljava/lang/IdentityObject;";
 33 static const size_t SIG_START_LEN = strlen(SIG_START);
 34 static const int    ACC_INTERFACE = 0x0200; // Interface class modifiers bit
 35 
 36 static jvmtiEnv *jvmti = nullptr;
 37 static jint class_load_count = 0;
 38 static jint class_prep_count = 0;
 39 static bool failed = false;
 40 // JVMTI_ERROR_WRONG_PHASE guard
 41 static jrawMonitorID event_mon = nullptr;
 42 static bool is_vm_dead = false;
 43 
 44 #define LOG0(str)             { printf(str); fflush(stdout); }
 45 #define LOG1(str, arg)        { printf(str, arg); fflush(stdout); }
 46 #define LOG2(str, arg1, arg2) { printf(str, arg1, arg2); fflush(stdout); }
 47 
 48 #define CHECK_JVMTI_ERROR(jni, err, msg) \
 49   if (err != JVMTI_ERROR_NONE) { \
 50     LOG1("CHECK_JVMTI_ERROR: JVMTI function returned error: %d\n", err); \
 51     jni->FatalError(msg); \
 52     return; \
 53   }
 54 
 55 /* Return the jmethodID of j.l.Class.isHidden() method. */
 56 static jmethodID
 57 is_hidden_mid(JNIEnv* jni) {
 58   char* csig = nullptr;
 59   jint count = 0;
 60   jmethodID *methods = nullptr;
 61   jclass clazz  = jni->FindClass("java/lang/Class");
 62   if (clazz == nullptr) {
 63     jni->FatalError("is_hidden_mid: Error: FindClass returned null for java/lang/Class\n");
 64     return nullptr;
 65   }
 66 
 67   // find the jmethodID of j.l.Class.isHidden() method
 68   jmethodID mid = jni->GetMethodID(clazz, "isHidden", "()Z");
 69   if (mid == nullptr) {
 70     jni->FatalError("is_hidden_mid: Error in jni GetMethodID: Cannot find j.l.Class.isHidden method\n");
 71   }
 72   return mid;
 73 }
 74 
 75 /* Return true if the klass is hidden. */
 76 static bool
 77 is_hidden(JNIEnv* jni, jclass klass) {
 78   static jmethodID is_hid_mid = nullptr;
 79 
 80   if (is_hid_mid == nullptr) {
 81     is_hid_mid = is_hidden_mid(jni);
 82   }
 83   // invoke j.l.Class.isHidden() method
 84   bool res = jni->CallBooleanMethod(klass, is_hid_mid);
 85   if (jni->ExceptionCheck()) {
 86     jni->ExceptionDescribe();
 87     jni->FatalError("is_hidden: Exception in jni CallBooleanMethod\n");
 88   }
 89   return res;
 90 }
 91 
 92 /* Check the class signature matches the expected. */
 93 static void
 94 check_class_signature(jvmtiEnv* jvmti, JNIEnv* jni, jclass klass, bool is_hidden, const char* exp_sig) {
 95   jint class_modifiers = 0;
 96   char* sig = nullptr;
 97   char* gsig = nullptr;
 98   jvmtiError err;
 99 
100   // get class signature
101   err = jvmti->GetClassSignature(klass, &sig, &gsig);
102   CHECK_JVMTI_ERROR(jni, err, "check_hidden_class: Error in JVMTI GetClassSignature");
103 
104   LOG1("check_class_signature: class with sig: %s\n", sig);
105   LOG1("check_class_signature: class with gsig: %s\n", gsig);
106 
107   if (strcmp(sig, exp_sig) != 0) {
108     LOG2("check_class_signature: FAIL: Hidden class signature %s does not match expected: %s\n", sig, exp_sig);
109     failed = true;
110   }
111   if (is_hidden && gsig == nullptr) {
112     LOG0("check_class_signature: FAIL: unexpected null generic signature for hidden class\n");
113     failed = true;
114   }
115 }
116 
117 /* Test hidden class flags: it should not be interface, array nor modifiable. */
118 static void
119 check_hidden_class_flags(jvmtiEnv* jvmti, JNIEnv* jni, jclass klass) {
120   jint modifiers = 0;
121   jboolean flag = false;
122   jvmtiError err;
123 
124   err = jvmti->GetClassModifiers(klass, &modifiers);
125   CHECK_JVMTI_ERROR(jni, err, "check_hidden_class_flags: Error in JVMTI GetClassModifiers");
126   LOG1("check_hidden_class_flags: hidden class modifiers: 0x%x\n", modifiers);
127   if ((modifiers & ACC_INTERFACE) != 0) {
128     LOG0("check_hidden_class_flags: FAIL: unexpected ACC_INTERFACE bit in hidden class modifiers\n");
129     failed = true;
130     return;
131   }
132 
133   err = jvmti->IsInterface(klass, &flag);
134   CHECK_JVMTI_ERROR(jni, err, "check_hidden_class_flags: Error in JVMTI IsInterface");
135   if (flag) {
136     LOG0("check_hidden_class_flags: FAIL: hidden class is not expected to be interface\n");
137     failed = true;
138     return;
139   }
140 
141   err = jvmti->IsArrayClass(klass, &flag);
142   CHECK_JVMTI_ERROR(jni, err, "check_hidden_class_flags: Error in JVMTI IsArrayClass");
143   if (flag) {
144     LOG0("check_hidden_class_flags: FAIL: hidden class is not expected to be array\n");
145     failed = true;
146     return;
147   }
148   err = jvmti->IsModifiableClass(klass, &flag);
149   CHECK_JVMTI_ERROR(jni, err, "check_hidden_class_flags: Error in JVMTI IsModifiableClass");
150   if (flag) {
151     LOG0("check_hidden_class_flags: FAIL: hidden class is not expected to be modifiable\n");
152     failed = true;
153   }
154 }
155 
156 /* Test GetClassLoaderClasses: it should not return any hidden classes. */
157 static void
158 check_hidden_class_loader(jvmtiEnv* jvmti, JNIEnv* jni, jclass klass) {
159   jint count = 0;
160   jobject loader = nullptr;
161   jclass* loader_classes = nullptr;
162   jboolean found = false;
163   jvmtiError err;
164 
165   err = jvmti->GetClassLoader(klass, &loader);
166   CHECK_JVMTI_ERROR(jni, err, "check_hidden_class_loader: Error in JVMTI GetClassLoader");
167 
168   jni->EnsureLocalCapacity(256); // to avoid warnings: JNI local refs NN exceeds capacity
169 
170   err = jvmti->GetClassLoaderClasses(loader, &count, &loader_classes);
171   CHECK_JVMTI_ERROR(jni, err, "check_hidden_class_loader: Error in JVMTI GetClassLoaderClasses");
172 
173   for (int idx = 0; idx < count; idx++) {
174     char* sig = nullptr;
175     jclass kls = loader_classes[idx];
176 
177     // GetClassLoaderClasses should not return any hidden classes
178     if (!is_hidden(jni, kls)) {
179       continue;
180     }
181     // get class signature
182     err = jvmti->GetClassSignature(kls, &sig, nullptr);
183     CHECK_JVMTI_ERROR(jni, err, "check_hidden_class_loader: Error in JVMTI GetClassSignature");
184 
185     LOG1("check_hidden_class_loader: FAIL: JVMTI GetClassLoaderClasses returned hidden class: %s\n", sig);
186     failed = true;
187     return;
188   }
189   LOG0("check_hidden_class_loader: not found hidden class in its loader classes as expected\n");
190 }
191 
192 /* Test the hidden class implements expected interface. */
193 static void
194 check_hidden_class_impl_interf(jvmtiEnv* jvmti, JNIEnv* jni, jclass klass) {
195   char* sig = nullptr;
196   jint count = 0;
197   jclass* interfaces = nullptr;
198   jvmtiError err;
199 
200   // check that hidden class implements just one interface (or two if IdentityObject has been injected)
201   err = jvmti->GetImplementedInterfaces(klass, &count, &interfaces);
202   CHECK_JVMTI_ERROR(jni, err, "check_hidden_class_impl_interf: Error in JVMTI GetImplementedInterfaces");
203   if (count != 1 && count != 2) {
204     LOG1("check_hidden_class_impl_interf: FAIL: implemented interfaces count: %d, expected to be in [1-2] range\n", count);
205     failed = true;
206     return;
207   }
208   bool found = false;
209   for (int i = 0; i < count; i++) {
210     // get interface signature
211     err = jvmti->GetClassSignature(interfaces[i], &sig, nullptr);
212     CHECK_JVMTI_ERROR(jni, err, "check_hidden_class_impl_interf: Error in JVMTI GetClassSignature for implemented interface");
213     // check the interface signature is matching the expected
214     if (strcmp(sig, EXP_INTERF_SIG) == 0) {
215       found = true;
216     }
217   }
218 
219   if (!found) {
220     LOG2("check_hidden_class_impl_interf: FAIL: implemented interface signature: %s, expected to be: %s\n",
221            sig, EXP_INTERF_SIG);
222     failed = true;
223   }
224 }
225 
226 /* Test hidden class. */
227 static void
228 check_hidden_class(jvmtiEnv* jvmti, JNIEnv* jni, jclass klass, const char* exp_sig) {
229   char* source_file_name = nullptr;
230 
231   LOG1("\n### Native agent: check_hidden_class started: class: %s\n", exp_sig);
232 
233   check_class_signature(jvmti, jni, klass, true /* not hidden */,  exp_sig);
234   if (failed) return;
235 
236   check_hidden_class_flags(jvmti, jni, klass);
237   if (failed) return;
238 
239   check_hidden_class_loader(jvmti, jni, klass);
240   if (failed) return;
241 
242   check_hidden_class_impl_interf(jvmti, jni, klass);
243   if (failed) return;
244 
245   LOG0("### Native agent: check_hidden_class finished\n");
246 }
247 
248 /* Test hidden class array. */
249 static void
250 check_hidden_class_array(jvmtiEnv* jvmti, JNIEnv* jni, jclass klass_array, const char* exp_sig) {
251   char* source_file_name = nullptr;
252 
253   LOG1("\n### Native agent: check_hidden_class_array started: array: %s\n", exp_sig);
254 
255   check_class_signature(jvmti, jni, klass_array, false /* is hidden */, exp_sig);
256   if (failed) return;
257 
258   LOG0("### Native agent: check_hidden_class_array finished\n");
259 }
260 
261 /* Process a CLASS_LOAD or a ClassPrepare event. */
262 static void process_class_event(jvmtiEnv* jvmti, JNIEnv* jni, jclass klass,
263                                 jint* event_count_ptr, const char* event_name) {
264   char* sig = nullptr;
265   char* gsig = nullptr;
266   jvmtiError err;
267 
268   RawMonitorLocker locker(jvmti, jni, event_mon);
269   if (is_vm_dead) {
270     return;
271   }
272 
273   // get class signature
274   err = jvmti->GetClassSignature(klass, &sig, &gsig);
275   CHECK_JVMTI_ERROR(jni, err, "ClassLoad/ClassPrepare event: Error in JVMTI GetClassSignature");
276 
277   // check if this is an expected class event for hidden class
278   if (strlen(sig) > strlen(SIG_START) &&
279       strncmp(sig, SIG_START, SIG_START_LEN) == 0 &&
280       is_hidden(jni, klass)) {
281     (*event_count_ptr)++;
282     if (gsig == nullptr) {
283       LOG1("%s event: FAIL: GetClassSignature returned null generic signature for hidden class\n", event_name);
284       failed = true;
285     }
286     LOG2("%s event: hidden class with sig: %s\n", event_name, sig);
287     LOG2("%s event: hidden class with gsig: %s\n", event_name, gsig);
288   }
289 }
290 
291 /* Check CLASS_LOAD event is generated for the given hidden class. */
292 static void JNICALL
293 ClassLoad(jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jclass klass) {
294   process_class_event(jvmti, jni, klass, &class_load_count, "ClassLoad");
295 }
296 
297 /* Check CLASS_PREPARE event is generated for the given hidden class. */
298 static void JNICALL
299 ClassPrepare(jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jclass klass) {
300   process_class_event(jvmti, jni, klass, &class_prep_count, "ClassPrepare");
301 }
302 
303 /* Enable CLASS_LOAD event notification mode. */
304 static void JNICALL
305 VMInit(jvmtiEnv* jvmti, JNIEnv* jni, jthread thread) {
306   jvmtiError err;
307 
308   printf("VMInit event: SIG_START: %s, SIG_START_LEN: %d\n", SIG_START, (int)SIG_START_LEN);
309   fflush(stdout);
310 
311   // enable ClassLoad event notification mode
312   err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_CLASS_LOAD, nullptr);
313   CHECK_JVMTI_ERROR(jni, err, "VMInit event: Error in enabling ClassLoad events notification");
314 
315   // enable ClassPrepare event notification mode
316   err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_CLASS_PREPARE, nullptr);
317   CHECK_JVMTI_ERROR(jni, err, "VMInit event: Error in enabling ClassPrepare events notification");
318 }
319 
320 static void JNICALL
321 VMDeath(jvmtiEnv *jvmti, JNIEnv* jni) {
322   RawMonitorLocker locker(jvmti, jni, event_mon);
323 
324   LOG0("VMDeath\n");
325   is_vm_dead = true;
326 }
327 
328 JNIEXPORT jint JNICALL
329 Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
330   jvmtiEventCallbacks callbacks;
331   jvmtiError err;
332 
333   LOG0("Agent_OnLoad: started\n");
334   if (jvm->GetEnv((void **) (&jvmti), JVMTI_VERSION) != JNI_OK) {
335     LOG0("Agent_OnLoad: Error in GetEnv in obtaining jvmtiEnv*\n");
336     failed = true;
337     return JNI_ERR;
338   }
339 
340   err = jvmti->CreateRawMonitor("Event Monitor", &event_mon);
341   if (err != JVMTI_ERROR_NONE) {
342     LOG1("Agent_OnLoad: CreateRawMonitor failed: %d\n", err);
343     failed = true;
344     return JNI_ERR;
345   }
346 
347   // set required event callbacks
348   memset(&callbacks, 0, sizeof(callbacks));
349   callbacks.ClassLoad = &ClassLoad;
350   callbacks.ClassPrepare = &ClassPrepare;
351   callbacks.VMInit = &VMInit;
352   callbacks.VMDeath = &VMDeath;
353 
354   err = jvmti->SetEventCallbacks(&callbacks, sizeof(jvmtiEventCallbacks));
355   if (err != JVMTI_ERROR_NONE) {
356     LOG1("Agent_OnLoad: Error in JVMTI SetEventCallbacks: %d\n", err);
357     failed = true;
358     return JNI_ERR;
359   }
360 
361   // enable VM_INIT event notification mode
362   err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, nullptr);
363   if (err != JVMTI_ERROR_NONE) {
364     LOG1("Agent_OnLoad: Error in JVMTI SetEventNotificationMode: %d\n", err);
365     failed = true;
366     return JNI_ERR;
367   }
368 
369   LOG0("Agent_OnLoad: finished\n");
370   return JNI_OK;
371 }
372 
373 /* Native method: checkHiddenClass(). */
374 JNIEXPORT void JNICALL
375 Java_P_Q_HiddenClassSigTest_checkHiddenClass(JNIEnv *jni, jclass klass, jclass hidden_klass, jstring exp_sig_str) {
376   const char* exp_sig = jni->GetStringUTFChars(exp_sig_str, nullptr);
377 
378   if (exp_sig == nullptr) {
379     jni->FatalError("check_hidden_class: Error: JNI GetStringChars returned null for jstring\n");
380     return;
381   }
382   check_hidden_class(jvmti, jni, hidden_klass, exp_sig);
383 
384   jni->ReleaseStringUTFChars(exp_sig_str, exp_sig);
385 }
386 
387 /* Native method: checkHiddenClassArray(). */
388 JNIEXPORT void JNICALL
389 Java_P_Q_HiddenClassSigTest_checkHiddenClassArray(JNIEnv *jni, jclass klass, jclass hidden_klass_array, jstring exp_sig_str) {
390   const char* exp_sig = jni->GetStringUTFChars(exp_sig_str, nullptr);
391 
392   if (exp_sig == nullptr) {
393     jni->FatalError("check_hidden_class_array: Error: JNI GetStringChars returned null for jstring\n");
394     return;
395   }
396   check_hidden_class_array(jvmti, jni, hidden_klass_array, exp_sig);
397 
398   jni->ReleaseStringUTFChars(exp_sig_str, exp_sig);
399 }
400 
401 /* Native method: checkFailed(). */
402 JNIEXPORT jboolean JNICALL
403 Java_P_Q_HiddenClassSigTest_checkFailed(JNIEnv *jni, jclass klass) {
404   if (class_load_count == 0) {
405     // expected ClassLoad event was not generated for hidden class
406     LOG0("Native Agent: FAIL: missed ClassLoad event for hidden class\n");
407     failed = true;
408   }
409   if (class_prep_count == 0) {
410     // expected ClassPrepare event was not generated for hidden class
411     LOG0("Native Agent: FAIL: missed ClassPrepare event for hidden class\n");
412     failed = true;
413   }
414   return failed;
415 }
416 
417 } // extern "C"