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 "base/sdk_version.h"
18 #include "class_linker.h"
19 #include "dex/art_dex_file_loader.h"
20 #include "hidden_api.h"
21 #include "jni.h"
22 #include "runtime.h"
23 #include "scoped_thread_state_change-inl.h"
24 #include "thread.h"
25 #include "ti-agent/scoped_utf_chars.h"
26 
27 namespace art {
28 namespace Test674HiddenApi {
29 
30 std::vector<std::vector<std::unique_ptr<const DexFile>>> opened_dex_files;
31 
Java_Main_init(JNIEnv *,jclass)32 extern "C" JNIEXPORT void JNICALL Java_Main_init(JNIEnv*, jclass) {
33   Runtime* runtime = Runtime::Current();
34   runtime->SetHiddenApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kEnabled);
35   runtime->SetCorePlatformApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kEnabled);
36   runtime->SetTargetSdkVersion(
37       static_cast<uint32_t>(hiddenapi::ApiList::GreylistMaxO().GetMaxAllowedSdkVersion()));
38   runtime->SetDedupeHiddenApiWarnings(false);
39 }
40 
Java_Main_setDexDomain(JNIEnv *,jclass,jint int_index,jboolean is_core_platform)41 extern "C" JNIEXPORT void JNICALL Java_Main_setDexDomain(
42     JNIEnv*, jclass, jint int_index, jboolean is_core_platform) {
43   size_t index = static_cast<size_t>(int_index);
44   CHECK_LT(index, opened_dex_files.size());
45   for (std::unique_ptr<const DexFile>& dex_file : opened_dex_files[index]) {
46     const_cast<DexFile*>(dex_file.get())->SetHiddenapiDomain(
47         (is_core_platform == JNI_FALSE) ? hiddenapi::Domain::kPlatform
48                                         : hiddenapi::Domain::kCorePlatform);
49   }
50 }
51 
Java_Main_appendToBootClassLoader(JNIEnv * env,jclass klass,jstring jpath,jboolean is_core_platform)52 extern "C" JNIEXPORT jint JNICALL Java_Main_appendToBootClassLoader(
53     JNIEnv* env, jclass klass, jstring jpath, jboolean is_core_platform) {
54   ScopedUtfChars utf(env, jpath);
55   const char* path = utf.c_str();
56   CHECK(path != nullptr);
57 
58   const size_t index = opened_dex_files.size();
59   const jint int_index = static_cast<jint>(index);
60   opened_dex_files.push_back(std::vector<std::unique_ptr<const DexFile>>());
61 
62   ArtDexFileLoader dex_loader;
63   std::string error_msg;
64 
65   if (!dex_loader.Open(path,
66                        path,
67                        /* verify */ false,
68                        /* verify_checksum */ true,
69                        &error_msg,
70                        &opened_dex_files[index])) {
71     LOG(FATAL) << "Could not open " << path << " for boot classpath extension: " << error_msg;
72     UNREACHABLE();
73   }
74 
75   Java_Main_setDexDomain(env, klass, int_index, is_core_platform);
76 
77   ScopedObjectAccess soa(Thread::Current());
78   for (std::unique_ptr<const DexFile>& dex_file : opened_dex_files[index]) {
79     Runtime::Current()->GetClassLinker()->AppendToBootClassPath(Thread::Current(), *dex_file.get());
80   }
81 
82   return int_index;
83 }
84 
Java_Main_setWhitelistAll(JNIEnv *,jclass,jboolean value)85 extern "C" JNIEXPORT void JNICALL Java_Main_setWhitelistAll(JNIEnv*, jclass, jboolean value) {
86   std::vector<std::string> exemptions;
87   if (value != JNI_FALSE) {
88     exemptions.push_back("L");
89   }
90   Runtime::Current()->SetHiddenApiExemptions(exemptions);
91 }
92 
NewInstance(JNIEnv * env,jclass klass)93 static jobject NewInstance(JNIEnv* env, jclass klass) {
94   jmethodID constructor = env->GetMethodID(klass, "<init>", "()V");
95   if (constructor == nullptr) {
96     return nullptr;
97   }
98   return env->NewObject(klass, constructor);
99 }
100 
Java_JNI_canDiscoverField(JNIEnv * env,jclass,jclass klass,jstring name,jboolean is_static)101 extern "C" JNIEXPORT jboolean JNICALL Java_JNI_canDiscoverField(
102     JNIEnv* env, jclass, jclass klass, jstring name, jboolean is_static) {
103   ScopedUtfChars utf_name(env, name);
104   jfieldID field = is_static ? env->GetStaticFieldID(klass, utf_name.c_str(), "I")
105                              : env->GetFieldID(klass, utf_name.c_str(), "I");
106   if (field == nullptr) {
107     env->ExceptionClear();
108     return JNI_FALSE;
109   }
110 
111   return JNI_TRUE;
112 }
113 
Java_JNI_canGetField(JNIEnv * env,jclass,jclass klass,jstring name,jboolean is_static)114 extern "C" JNIEXPORT jboolean JNICALL Java_JNI_canGetField(
115     JNIEnv* env, jclass, jclass klass, jstring name, jboolean is_static) {
116   ScopedUtfChars utf_name(env, name);
117   jfieldID field = is_static ? env->GetStaticFieldID(klass, utf_name.c_str(), "I")
118                              : env->GetFieldID(klass, utf_name.c_str(), "I");
119   if (field == nullptr) {
120     env->ExceptionClear();
121     return JNI_FALSE;
122   }
123   if (is_static) {
124     env->GetStaticIntField(klass, field);
125   } else {
126     jobject obj = NewInstance(env, klass);
127     if (obj == nullptr) {
128       env->ExceptionDescribe();
129       env->ExceptionClear();
130       return JNI_FALSE;
131     }
132     env->GetIntField(obj, field);
133   }
134 
135   if (env->ExceptionOccurred()) {
136     env->ExceptionDescribe();
137     env->ExceptionClear();
138     return JNI_FALSE;
139   }
140 
141   return JNI_TRUE;
142 }
143 
Java_JNI_canSetField(JNIEnv * env,jclass,jclass klass,jstring name,jboolean is_static)144 extern "C" JNIEXPORT jboolean JNICALL Java_JNI_canSetField(
145     JNIEnv* env, jclass, jclass klass, jstring name, jboolean is_static) {
146   ScopedUtfChars utf_name(env, name);
147   jfieldID field = is_static ? env->GetStaticFieldID(klass, utf_name.c_str(), "I")
148                              : env->GetFieldID(klass, utf_name.c_str(), "I");
149   if (field == nullptr) {
150     env->ExceptionClear();
151     return JNI_FALSE;
152   }
153   if (is_static) {
154     env->SetStaticIntField(klass, field, 42);
155   } else {
156     jobject obj = NewInstance(env, klass);
157     if (obj == nullptr) {
158       env->ExceptionDescribe();
159       env->ExceptionClear();
160       return JNI_FALSE;
161     }
162     env->SetIntField(obj, field, 42);
163   }
164 
165   if (env->ExceptionOccurred()) {
166     env->ExceptionDescribe();
167     env->ExceptionClear();
168     return JNI_FALSE;
169   }
170 
171   return JNI_TRUE;
172 }
173 
Java_JNI_canDiscoverMethod(JNIEnv * env,jclass,jclass klass,jstring name,jboolean is_static)174 extern "C" JNIEXPORT jboolean JNICALL Java_JNI_canDiscoverMethod(
175     JNIEnv* env, jclass, jclass klass, jstring name, jboolean is_static) {
176   ScopedUtfChars utf_name(env, name);
177   jmethodID method = is_static ? env->GetStaticMethodID(klass, utf_name.c_str(), "()I")
178                                : env->GetMethodID(klass, utf_name.c_str(), "()I");
179   if (method == nullptr) {
180     env->ExceptionClear();
181     return JNI_FALSE;
182   }
183 
184   return JNI_TRUE;
185 }
186 
Java_JNI_canInvokeMethodA(JNIEnv * env,jclass,jclass klass,jstring name,jboolean is_static)187 extern "C" JNIEXPORT jboolean JNICALL Java_JNI_canInvokeMethodA(
188     JNIEnv* env, jclass, jclass klass, jstring name, jboolean is_static) {
189   ScopedUtfChars utf_name(env, name);
190   jmethodID method = is_static ? env->GetStaticMethodID(klass, utf_name.c_str(), "()I")
191                                : env->GetMethodID(klass, utf_name.c_str(), "()I");
192   if (method == nullptr) {
193     env->ExceptionClear();
194     return JNI_FALSE;
195   }
196 
197   if (is_static) {
198     env->CallStaticIntMethodA(klass, method, nullptr);
199   } else {
200     jobject obj = NewInstance(env, klass);
201     if (obj == nullptr) {
202       env->ExceptionDescribe();
203       env->ExceptionClear();
204       return JNI_FALSE;
205     }
206     env->CallIntMethodA(obj, method, nullptr);
207   }
208 
209   if (env->ExceptionOccurred()) {
210     env->ExceptionDescribe();
211     env->ExceptionClear();
212     return JNI_FALSE;
213   }
214 
215   return JNI_TRUE;
216 }
217 
Java_JNI_canInvokeMethodV(JNIEnv * env,jclass,jclass klass,jstring name,jboolean is_static)218 extern "C" JNIEXPORT jboolean JNICALL Java_JNI_canInvokeMethodV(
219     JNIEnv* env, jclass, jclass klass, jstring name, jboolean is_static) {
220   ScopedUtfChars utf_name(env, name);
221   jmethodID method = is_static ? env->GetStaticMethodID(klass, utf_name.c_str(), "()I")
222                                : env->GetMethodID(klass, utf_name.c_str(), "()I");
223   if (method == nullptr) {
224     env->ExceptionClear();
225     return JNI_FALSE;
226   }
227 
228   if (is_static) {
229     env->CallStaticIntMethod(klass, method);
230   } else {
231     jobject obj = NewInstance(env, klass);
232     if (obj == nullptr) {
233       env->ExceptionDescribe();
234       env->ExceptionClear();
235       return JNI_FALSE;
236     }
237     env->CallIntMethod(obj, method);
238   }
239 
240   if (env->ExceptionOccurred()) {
241     env->ExceptionDescribe();
242     env->ExceptionClear();
243     return JNI_FALSE;
244   }
245 
246   return JNI_TRUE;
247 }
248 
249 static constexpr size_t kConstructorSignatureLength = 5;  // e.g. (IZ)V
250 static constexpr size_t kNumConstructorArgs = kConstructorSignatureLength - 3;
251 
Java_JNI_canDiscoverConstructor(JNIEnv * env,jclass,jclass klass,jstring args)252 extern "C" JNIEXPORT jboolean JNICALL Java_JNI_canDiscoverConstructor(
253     JNIEnv* env, jclass, jclass klass, jstring args) {
254   ScopedUtfChars utf_args(env, args);
255   jmethodID constructor = env->GetMethodID(klass, "<init>", utf_args.c_str());
256   if (constructor == nullptr) {
257     env->ExceptionClear();
258     return JNI_FALSE;
259   }
260 
261   return JNI_TRUE;
262 }
263 
Java_JNI_canInvokeConstructorA(JNIEnv * env,jclass,jclass klass,jstring args)264 extern "C" JNIEXPORT jboolean JNICALL Java_JNI_canInvokeConstructorA(
265     JNIEnv* env, jclass, jclass klass, jstring args) {
266   ScopedUtfChars utf_args(env, args);
267   jmethodID constructor = env->GetMethodID(klass, "<init>", utf_args.c_str());
268   if (constructor == nullptr) {
269     env->ExceptionClear();
270     return JNI_FALSE;
271   }
272 
273   // CheckJNI won't allow out-of-range values, so just zero everything.
274   CHECK_EQ(strlen(utf_args.c_str()), kConstructorSignatureLength);
275   size_t initargs_size = sizeof(jvalue) * kNumConstructorArgs;
276   jvalue *initargs = reinterpret_cast<jvalue*>(alloca(initargs_size));
277   memset(initargs, 0, initargs_size);
278 
279   env->NewObjectA(klass, constructor, initargs);
280   if (env->ExceptionOccurred()) {
281     env->ExceptionDescribe();
282     env->ExceptionClear();
283     return JNI_FALSE;
284   }
285 
286   return JNI_TRUE;
287 }
288 
Java_JNI_canInvokeConstructorV(JNIEnv * env,jclass,jclass klass,jstring args)289 extern "C" JNIEXPORT jboolean JNICALL Java_JNI_canInvokeConstructorV(
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   static_assert(kNumConstructorArgs == 2, "Change the varargs below if you change the constant");
305   env->NewObject(klass, constructor, initargs[0], initargs[1]);
306   if (env->ExceptionOccurred()) {
307     env->ExceptionDescribe();
308     env->ExceptionClear();
309     return JNI_FALSE;
310   }
311 
312   return JNI_TRUE;
313 }
314 
Java_Reflection_getHiddenApiAccessFlags(JNIEnv *,jclass)315 extern "C" JNIEXPORT jint JNICALL Java_Reflection_getHiddenApiAccessFlags(JNIEnv*, jclass) {
316   return static_cast<jint>(kAccHiddenapiBits);
317 }
318 
319 }  // namespace Test674HiddenApi
320 }  // namespace art
321