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