• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <dlfcn.h>
18 
19 #include "base/sdk_version.h"
20 #include "dex/art_dex_file_loader.h"
21 #include "hidden_api.h"
22 #include "jni.h"
23 #include "runtime.h"
24 #include "ti-agent/scoped_utf_chars.h"
25 
26 #ifdef ART_TARGET_ANDROID
27 #include "nativeloader/dlext_namespaces.h"
28 #endif
29 
30 namespace art {
31 namespace Test674HiddenApi {
32 
33 // Should be the same as dalvik.system.VMRuntime.PREVENT_META_REFLECTION_BLOCKLIST_ACCESS
34 static constexpr uint64_t kPreventMetaReflectionBlocklistAccess = 142365358;
35 
36 std::vector<std::vector<std::unique_ptr<const DexFile>>> opened_dex_files;
37 
38 // The JNI entrypoints below end up in libarttest(d).so, while the test makes
39 // copies of libarttest(d)_external.so and loads them instead. Those libs depend
40 // on libarttest(d).so, so its exported symbols become visible directly in them.
41 // Hence we don't need to create wrappers for the JNI methods in
42 // libarttest(d)_external.so.
43 
44 extern "C" JNIEXPORT void JNICALL
Java_Main_addDefaultNamespaceLibsLinkToSystemLinkerNamespace(JNIEnv *,jclass)45 Java_Main_addDefaultNamespaceLibsLinkToSystemLinkerNamespace(JNIEnv*, jclass) {
46 #ifdef ART_TARGET_ANDROID
47   const char* links = getenv("NATIVELOADER_DEFAULT_NAMESPACE_LIBS");
48   if (links == nullptr || *links == 0) {
49     LOG(FATAL) << "Expected NATIVELOADER_DEFAULT_NAMESPACE_LIBS to be set";
50   }
51   struct android_namespace_t* system_ns = android_get_exported_namespace("system");
52   if (system_ns == nullptr) {
53     LOG(FATAL) << "Failed to retrieve system namespace";
54   }
55   if (!android_link_namespaces(system_ns, nullptr, links)) {
56     LOG(FATAL) << "Error adding linker namespace link from system to default for " << links << ": "
57                << dlerror();
58   }
59 #endif
60 }
61 
Java_Main_init(JNIEnv *,jclass)62 extern "C" JNIEXPORT void JNICALL Java_Main_init(JNIEnv*, jclass) {
63   Runtime* runtime = Runtime::Current();
64   runtime->SetHiddenApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kEnabled);
65   runtime->SetCorePlatformApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kEnabled);
66   runtime->SetTargetSdkVersion(
67       static_cast<uint32_t>(hiddenapi::ApiList::MaxTargetO().GetMaxAllowedSdkVersion()));
68   runtime->SetDedupeHiddenApiWarnings(false);
69 }
70 
Java_Main_setDexDomain(JNIEnv *,jclass,jint int_index,jboolean is_core_platform)71 extern "C" JNIEXPORT void JNICALL Java_Main_setDexDomain(
72     JNIEnv*, jclass, jint int_index, jboolean is_core_platform) {
73   size_t index = static_cast<size_t>(int_index);
74   CHECK_LT(index, opened_dex_files.size());
75   for (std::unique_ptr<const DexFile>& dex_file : opened_dex_files[index]) {
76     const_cast<DexFile*>(dex_file.get())->SetHiddenapiDomain(
77         (is_core_platform == JNI_FALSE) ? hiddenapi::Domain::kPlatform
78                                         : hiddenapi::Domain::kCorePlatform);
79   }
80 }
81 
Java_Main_appendToBootClassLoader(JNIEnv * env,jclass klass,jstring jpath,jboolean is_core_platform)82 extern "C" JNIEXPORT jint JNICALL Java_Main_appendToBootClassLoader(
83     JNIEnv* env, jclass klass, jstring jpath, jboolean is_core_platform) {
84   ScopedUtfChars utf(env, jpath);
85   const char* path = utf.c_str();
86   CHECK(path != nullptr);
87 
88   const size_t index = opened_dex_files.size();
89   const jint int_index = static_cast<jint>(index);
90   opened_dex_files.push_back(std::vector<std::unique_ptr<const DexFile>>());
91 
92   DexFileLoader dex_loader(path);
93   std::string error_msg;
94 
95   if (!dex_loader.Open(/* verify */ false,
96                        /* verify_checksum */ true,
97                        &error_msg,
98                        &opened_dex_files[index])) {
99     LOG(FATAL) << "Could not open " << path << " for boot classpath extension: " << error_msg;
100     UNREACHABLE();
101   }
102 
103   Java_Main_setDexDomain(env, klass, int_index, is_core_platform);
104 
105   Runtime::Current()->AppendToBootClassPath(path, path, opened_dex_files[index]);
106 
107   return int_index;
108 }
109 
Java_Main_setSdkAll(JNIEnv *,jclass,jboolean value)110 extern "C" JNIEXPORT void JNICALL Java_Main_setSdkAll(JNIEnv*, jclass, jboolean value) {
111   std::vector<std::string> exemptions;
112   if (value != JNI_FALSE) {
113     exemptions.push_back("L");
114   }
115   Runtime::Current()->SetHiddenApiExemptions(exemptions);
116 }
117 
NewInstance(JNIEnv * env,jclass klass)118 static jobject NewInstance(JNIEnv* env, jclass klass) {
119   jmethodID constructor = env->GetMethodID(klass, "<init>", "()V");
120   if (constructor == nullptr) {
121     return nullptr;
122   }
123   return env->NewObject(klass, constructor);
124 }
125 
Java_JNI_canDiscoverField(JNIEnv * env,jclass,jclass klass,jstring name,jboolean is_static)126 extern "C" JNIEXPORT jboolean JNICALL Java_JNI_canDiscoverField(
127     JNIEnv* env, jclass, jclass klass, jstring name, jboolean is_static) {
128   ScopedUtfChars utf_name(env, name);
129   jfieldID field = is_static ? env->GetStaticFieldID(klass, utf_name.c_str(), "I")
130                              : env->GetFieldID(klass, utf_name.c_str(), "I");
131   if (field == nullptr) {
132     env->ExceptionClear();
133     return JNI_FALSE;
134   }
135 
136   return JNI_TRUE;
137 }
138 
Java_JNI_canGetField(JNIEnv * env,jclass,jclass klass,jstring name,jboolean is_static)139 extern "C" JNIEXPORT jboolean JNICALL Java_JNI_canGetField(
140     JNIEnv* env, jclass, jclass klass, jstring name, jboolean is_static) {
141   ScopedUtfChars utf_name(env, name);
142   jfieldID field = is_static ? env->GetStaticFieldID(klass, utf_name.c_str(), "I")
143                              : env->GetFieldID(klass, utf_name.c_str(), "I");
144   if (field == nullptr) {
145     env->ExceptionClear();
146     return JNI_FALSE;
147   }
148   if (is_static) {
149     env->GetStaticIntField(klass, field);
150   } else {
151     jobject obj = NewInstance(env, klass);
152     if (obj == nullptr) {
153       env->ExceptionDescribe();
154       env->ExceptionClear();
155       return JNI_FALSE;
156     }
157     env->GetIntField(obj, field);
158   }
159 
160   if (env->ExceptionOccurred()) {
161     env->ExceptionDescribe();
162     env->ExceptionClear();
163     return JNI_FALSE;
164   }
165 
166   return JNI_TRUE;
167 }
168 
Java_JNI_canSetField(JNIEnv * env,jclass,jclass klass,jstring name,jboolean is_static)169 extern "C" JNIEXPORT jboolean JNICALL Java_JNI_canSetField(
170     JNIEnv* env, jclass, jclass klass, jstring name, jboolean is_static) {
171   ScopedUtfChars utf_name(env, name);
172   jfieldID field = is_static ? env->GetStaticFieldID(klass, utf_name.c_str(), "I")
173                              : env->GetFieldID(klass, utf_name.c_str(), "I");
174   if (field == nullptr) {
175     env->ExceptionClear();
176     return JNI_FALSE;
177   }
178   if (is_static) {
179     env->SetStaticIntField(klass, field, 42);
180   } else {
181     jobject obj = NewInstance(env, klass);
182     if (obj == nullptr) {
183       env->ExceptionDescribe();
184       env->ExceptionClear();
185       return JNI_FALSE;
186     }
187     env->SetIntField(obj, field, 42);
188   }
189 
190   if (env->ExceptionOccurred()) {
191     env->ExceptionDescribe();
192     env->ExceptionClear();
193     return JNI_FALSE;
194   }
195 
196   return JNI_TRUE;
197 }
198 
Java_JNI_canDiscoverMethod(JNIEnv * env,jclass,jclass klass,jstring name,jboolean is_static)199 extern "C" JNIEXPORT jboolean JNICALL Java_JNI_canDiscoverMethod(
200     JNIEnv* env, jclass, jclass klass, jstring name, jboolean is_static) {
201   ScopedUtfChars utf_name(env, name);
202   jmethodID method = is_static ? env->GetStaticMethodID(klass, utf_name.c_str(), "()I")
203                                : env->GetMethodID(klass, utf_name.c_str(), "()I");
204   if (method == nullptr) {
205     env->ExceptionClear();
206     return JNI_FALSE;
207   }
208 
209   return JNI_TRUE;
210 }
211 
Java_JNI_canInvokeMethodA(JNIEnv * env,jclass,jclass klass,jstring name,jboolean is_static)212 extern "C" JNIEXPORT jboolean JNICALL Java_JNI_canInvokeMethodA(
213     JNIEnv* env, jclass, jclass klass, jstring name, jboolean is_static) {
214   ScopedUtfChars utf_name(env, name);
215   jmethodID method = is_static ? env->GetStaticMethodID(klass, utf_name.c_str(), "()I")
216                                : env->GetMethodID(klass, utf_name.c_str(), "()I");
217   if (method == nullptr) {
218     env->ExceptionClear();
219     return JNI_FALSE;
220   }
221 
222   if (is_static) {
223     env->CallStaticIntMethodA(klass, method, nullptr);
224   } else {
225     jobject obj = NewInstance(env, klass);
226     if (obj == nullptr) {
227       env->ExceptionDescribe();
228       env->ExceptionClear();
229       return JNI_FALSE;
230     }
231     env->CallIntMethodA(obj, method, nullptr);
232   }
233 
234   if (env->ExceptionOccurred()) {
235     env->ExceptionDescribe();
236     env->ExceptionClear();
237     return JNI_FALSE;
238   }
239 
240   return JNI_TRUE;
241 }
242 
Java_JNI_canInvokeMethodV(JNIEnv * env,jclass,jclass klass,jstring name,jboolean is_static)243 extern "C" JNIEXPORT jboolean JNICALL Java_JNI_canInvokeMethodV(
244     JNIEnv* env, jclass, jclass klass, jstring name, jboolean is_static) {
245   ScopedUtfChars utf_name(env, name);
246   jmethodID method = is_static ? env->GetStaticMethodID(klass, utf_name.c_str(), "()I")
247                                : env->GetMethodID(klass, utf_name.c_str(), "()I");
248   if (method == nullptr) {
249     env->ExceptionClear();
250     return JNI_FALSE;
251   }
252 
253   if (is_static) {
254     env->CallStaticIntMethod(klass, method);
255   } else {
256     jobject obj = NewInstance(env, klass);
257     if (obj == nullptr) {
258       env->ExceptionDescribe();
259       env->ExceptionClear();
260       return JNI_FALSE;
261     }
262     env->CallIntMethod(obj, method);
263   }
264 
265   if (env->ExceptionOccurred()) {
266     env->ExceptionDescribe();
267     env->ExceptionClear();
268     return JNI_FALSE;
269   }
270 
271   return JNI_TRUE;
272 }
273 
274 static constexpr size_t kConstructorSignatureLength = 5;  // e.g. (IZ)V
275 static constexpr size_t kNumConstructorArgs = kConstructorSignatureLength - 3;
276 
Java_JNI_canDiscoverConstructor(JNIEnv * env,jclass,jclass klass,jstring args)277 extern "C" JNIEXPORT jboolean JNICALL Java_JNI_canDiscoverConstructor(
278     JNIEnv* env, jclass, jclass klass, jstring args) {
279   ScopedUtfChars utf_args(env, args);
280   jmethodID constructor = env->GetMethodID(klass, "<init>", utf_args.c_str());
281   if (constructor == nullptr) {
282     env->ExceptionClear();
283     return JNI_FALSE;
284   }
285 
286   return JNI_TRUE;
287 }
288 
Java_JNI_canInvokeConstructorA(JNIEnv * env,jclass,jclass klass,jstring args)289 extern "C" JNIEXPORT jboolean JNICALL Java_JNI_canInvokeConstructorA(
290     JNIEnv* env, jclass, jclass klass, jstring args) {
291   ScopedUtfChars utf_args(env, args);
292   jmethodID constructor = env->GetMethodID(klass, "<init>", utf_args.c_str());
293   if (constructor == nullptr) {
294     env->ExceptionClear();
295     return JNI_FALSE;
296   }
297 
298   // CheckJNI won't allow out-of-range values, so just zero everything.
299   CHECK_EQ(strlen(utf_args.c_str()), kConstructorSignatureLength);
300   size_t initargs_size = sizeof(jvalue) * kNumConstructorArgs;
301   jvalue *initargs = reinterpret_cast<jvalue*>(alloca(initargs_size));
302   memset(initargs, 0, initargs_size);
303 
304   env->NewObjectA(klass, constructor, initargs);
305   if (env->ExceptionOccurred()) {
306     env->ExceptionDescribe();
307     env->ExceptionClear();
308     return JNI_FALSE;
309   }
310 
311   return JNI_TRUE;
312 }
313 
Java_JNI_canInvokeConstructorV(JNIEnv * env,jclass,jclass klass,jstring args)314 extern "C" JNIEXPORT jboolean JNICALL Java_JNI_canInvokeConstructorV(
315     JNIEnv* env, jclass, jclass klass, jstring args) {
316   ScopedUtfChars utf_args(env, args);
317   jmethodID constructor = env->GetMethodID(klass, "<init>", utf_args.c_str());
318   if (constructor == nullptr) {
319     env->ExceptionClear();
320     return JNI_FALSE;
321   }
322 
323   // CheckJNI won't allow out-of-range values, so just zero everything.
324   CHECK_EQ(strlen(utf_args.c_str()), kConstructorSignatureLength);
325   size_t initargs_size = sizeof(jvalue) * kNumConstructorArgs;
326   jvalue *initargs = reinterpret_cast<jvalue*>(alloca(initargs_size));
327   memset(initargs, 0, initargs_size);
328 
329   static_assert(kNumConstructorArgs == 2, "Change the varargs below if you change the constant");
330   env->NewObject(klass, constructor, initargs[0], initargs[1]);
331   if (env->ExceptionOccurred()) {
332     env->ExceptionDescribe();
333     env->ExceptionClear();
334     return JNI_FALSE;
335   }
336 
337   return JNI_TRUE;
338 }
339 
Java_Reflection_getHiddenApiAccessFlags(JNIEnv *,jclass)340 extern "C" JNIEXPORT jint JNICALL Java_Reflection_getHiddenApiAccessFlags(JNIEnv*, jclass) {
341   return static_cast<jint>(kAccHiddenapiBits);
342 }
343 
Java_Reflection_setHiddenApiCheckHardening(JNIEnv *,jclass,jboolean value)344 extern "C" JNIEXPORT void JNICALL Java_Reflection_setHiddenApiCheckHardening(JNIEnv*, jclass,
345     jboolean value) {
346   CompatFramework& compat_framework = Runtime::Current()->GetCompatFramework();
347   std::set<uint64_t> disabled_changes = compat_framework.GetDisabledCompatChanges();
348   if (value == JNI_TRUE) {
349     // If hidden api check hardening is enabled, remove it from the set of disabled changes.
350     disabled_changes.erase(kPreventMetaReflectionBlocklistAccess);
351   } else {
352     // If hidden api check hardening is disabled, add it to the set of disabled changes.
353     disabled_changes.insert(kPreventMetaReflectionBlocklistAccess);
354   }
355   compat_framework.SetDisabledCompatChanges(disabled_changes);
356 }
357 
358 }  // namespace Test674HiddenApi
359 }  // namespace art
360