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 "dex/art_dex_file_loader.h"
19 #include "hidden_api.h"
20 #include "jni.h"
21 #include "runtime.h"
22 #include "ti-agent/scoped_utf_chars.h"
23
24 namespace art {
25 namespace Test674HiddenApi {
26
27 // Should be the same as dalvik.system.VMRuntime.PREVENT_META_REFLECTION_BLOCKLIST_ACCESS
28 static constexpr uint64_t kPreventMetaReflectionBlocklistAccess = 142365358;
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::MaxTargetO().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 DexFileLoader dex_loader(path);
63 std::string error_msg;
64
65 if (!dex_loader.Open(/* verify */ false,
66 /* verify_checksum */ true,
67 &error_msg,
68 &opened_dex_files[index])) {
69 LOG(FATAL) << "Could not open " << path << " for boot classpath extension: " << error_msg;
70 UNREACHABLE();
71 }
72
73 Java_Main_setDexDomain(env, klass, int_index, is_core_platform);
74
75 Runtime::Current()->AppendToBootClassPath(path, path, opened_dex_files[index]);
76
77 return int_index;
78 }
79
Java_Main_setSdkAll(JNIEnv *,jclass,jboolean value)80 extern "C" JNIEXPORT void JNICALL Java_Main_setSdkAll(JNIEnv*, jclass, jboolean value) {
81 std::vector<std::string> exemptions;
82 if (value != JNI_FALSE) {
83 exemptions.push_back("L");
84 }
85 Runtime::Current()->SetHiddenApiExemptions(exemptions);
86 }
87
NewInstance(JNIEnv * env,jclass klass)88 static jobject NewInstance(JNIEnv* env, jclass klass) {
89 jmethodID constructor = env->GetMethodID(klass, "<init>", "()V");
90 if (constructor == nullptr) {
91 return nullptr;
92 }
93 return env->NewObject(klass, constructor);
94 }
95
Java_JNI_canDiscoverField(JNIEnv * env,jclass,jclass klass,jstring name,jboolean is_static)96 extern "C" JNIEXPORT jboolean JNICALL Java_JNI_canDiscoverField(
97 JNIEnv* env, jclass, jclass klass, jstring name, jboolean is_static) {
98 ScopedUtfChars utf_name(env, name);
99 jfieldID field = is_static ? env->GetStaticFieldID(klass, utf_name.c_str(), "I")
100 : env->GetFieldID(klass, utf_name.c_str(), "I");
101 if (field == nullptr) {
102 env->ExceptionClear();
103 return JNI_FALSE;
104 }
105
106 return JNI_TRUE;
107 }
108
Java_JNI_canGetField(JNIEnv * env,jclass,jclass klass,jstring name,jboolean is_static)109 extern "C" JNIEXPORT jboolean JNICALL Java_JNI_canGetField(
110 JNIEnv* env, jclass, jclass klass, jstring name, jboolean is_static) {
111 ScopedUtfChars utf_name(env, name);
112 jfieldID field = is_static ? env->GetStaticFieldID(klass, utf_name.c_str(), "I")
113 : env->GetFieldID(klass, utf_name.c_str(), "I");
114 if (field == nullptr) {
115 env->ExceptionClear();
116 return JNI_FALSE;
117 }
118 if (is_static) {
119 env->GetStaticIntField(klass, field);
120 } else {
121 jobject obj = NewInstance(env, klass);
122 if (obj == nullptr) {
123 env->ExceptionDescribe();
124 env->ExceptionClear();
125 return JNI_FALSE;
126 }
127 env->GetIntField(obj, field);
128 }
129
130 if (env->ExceptionOccurred()) {
131 env->ExceptionDescribe();
132 env->ExceptionClear();
133 return JNI_FALSE;
134 }
135
136 return JNI_TRUE;
137 }
138
Java_JNI_canSetField(JNIEnv * env,jclass,jclass klass,jstring name,jboolean is_static)139 extern "C" JNIEXPORT jboolean JNICALL Java_JNI_canSetField(
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->SetStaticIntField(klass, field, 42);
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->SetIntField(obj, field, 42);
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_canDiscoverMethod(JNIEnv * env,jclass,jclass klass,jstring name,jboolean is_static)169 extern "C" JNIEXPORT jboolean JNICALL Java_JNI_canDiscoverMethod(
170 JNIEnv* env, jclass, jclass klass, jstring name, jboolean is_static) {
171 ScopedUtfChars utf_name(env, name);
172 jmethodID method = is_static ? env->GetStaticMethodID(klass, utf_name.c_str(), "()I")
173 : env->GetMethodID(klass, utf_name.c_str(), "()I");
174 if (method == nullptr) {
175 env->ExceptionClear();
176 return JNI_FALSE;
177 }
178
179 return JNI_TRUE;
180 }
181
Java_JNI_canInvokeMethodA(JNIEnv * env,jclass,jclass klass,jstring name,jboolean is_static)182 extern "C" JNIEXPORT jboolean JNICALL Java_JNI_canInvokeMethodA(
183 JNIEnv* env, jclass, jclass klass, jstring name, jboolean is_static) {
184 ScopedUtfChars utf_name(env, name);
185 jmethodID method = is_static ? env->GetStaticMethodID(klass, utf_name.c_str(), "()I")
186 : env->GetMethodID(klass, utf_name.c_str(), "()I");
187 if (method == nullptr) {
188 env->ExceptionClear();
189 return JNI_FALSE;
190 }
191
192 if (is_static) {
193 env->CallStaticIntMethodA(klass, method, nullptr);
194 } else {
195 jobject obj = NewInstance(env, klass);
196 if (obj == nullptr) {
197 env->ExceptionDescribe();
198 env->ExceptionClear();
199 return JNI_FALSE;
200 }
201 env->CallIntMethodA(obj, method, nullptr);
202 }
203
204 if (env->ExceptionOccurred()) {
205 env->ExceptionDescribe();
206 env->ExceptionClear();
207 return JNI_FALSE;
208 }
209
210 return JNI_TRUE;
211 }
212
Java_JNI_canInvokeMethodV(JNIEnv * env,jclass,jclass klass,jstring name,jboolean is_static)213 extern "C" JNIEXPORT jboolean JNICALL Java_JNI_canInvokeMethodV(
214 JNIEnv* env, jclass, jclass klass, jstring name, jboolean is_static) {
215 ScopedUtfChars utf_name(env, name);
216 jmethodID method = is_static ? env->GetStaticMethodID(klass, utf_name.c_str(), "()I")
217 : env->GetMethodID(klass, utf_name.c_str(), "()I");
218 if (method == nullptr) {
219 env->ExceptionClear();
220 return JNI_FALSE;
221 }
222
223 if (is_static) {
224 env->CallStaticIntMethod(klass, method);
225 } else {
226 jobject obj = NewInstance(env, klass);
227 if (obj == nullptr) {
228 env->ExceptionDescribe();
229 env->ExceptionClear();
230 return JNI_FALSE;
231 }
232 env->CallIntMethod(obj, method);
233 }
234
235 if (env->ExceptionOccurred()) {
236 env->ExceptionDescribe();
237 env->ExceptionClear();
238 return JNI_FALSE;
239 }
240
241 return JNI_TRUE;
242 }
243
244 static constexpr size_t kConstructorSignatureLength = 5; // e.g. (IZ)V
245 static constexpr size_t kNumConstructorArgs = kConstructorSignatureLength - 3;
246
Java_JNI_canDiscoverConstructor(JNIEnv * env,jclass,jclass klass,jstring args)247 extern "C" JNIEXPORT jboolean JNICALL Java_JNI_canDiscoverConstructor(
248 JNIEnv* env, jclass, jclass klass, jstring args) {
249 ScopedUtfChars utf_args(env, args);
250 jmethodID constructor = env->GetMethodID(klass, "<init>", utf_args.c_str());
251 if (constructor == nullptr) {
252 env->ExceptionClear();
253 return JNI_FALSE;
254 }
255
256 return JNI_TRUE;
257 }
258
Java_JNI_canInvokeConstructorA(JNIEnv * env,jclass,jclass klass,jstring args)259 extern "C" JNIEXPORT jboolean JNICALL Java_JNI_canInvokeConstructorA(
260 JNIEnv* env, jclass, jclass klass, jstring args) {
261 ScopedUtfChars utf_args(env, args);
262 jmethodID constructor = env->GetMethodID(klass, "<init>", utf_args.c_str());
263 if (constructor == nullptr) {
264 env->ExceptionClear();
265 return JNI_FALSE;
266 }
267
268 // CheckJNI won't allow out-of-range values, so just zero everything.
269 CHECK_EQ(strlen(utf_args.c_str()), kConstructorSignatureLength);
270 size_t initargs_size = sizeof(jvalue) * kNumConstructorArgs;
271 jvalue *initargs = reinterpret_cast<jvalue*>(alloca(initargs_size));
272 memset(initargs, 0, initargs_size);
273
274 env->NewObjectA(klass, constructor, initargs);
275 if (env->ExceptionOccurred()) {
276 env->ExceptionDescribe();
277 env->ExceptionClear();
278 return JNI_FALSE;
279 }
280
281 return JNI_TRUE;
282 }
283
Java_JNI_canInvokeConstructorV(JNIEnv * env,jclass,jclass klass,jstring args)284 extern "C" JNIEXPORT jboolean JNICALL Java_JNI_canInvokeConstructorV(
285 JNIEnv* env, jclass, jclass klass, jstring args) {
286 ScopedUtfChars utf_args(env, args);
287 jmethodID constructor = env->GetMethodID(klass, "<init>", utf_args.c_str());
288 if (constructor == nullptr) {
289 env->ExceptionClear();
290 return JNI_FALSE;
291 }
292
293 // CheckJNI won't allow out-of-range values, so just zero everything.
294 CHECK_EQ(strlen(utf_args.c_str()), kConstructorSignatureLength);
295 size_t initargs_size = sizeof(jvalue) * kNumConstructorArgs;
296 jvalue *initargs = reinterpret_cast<jvalue*>(alloca(initargs_size));
297 memset(initargs, 0, initargs_size);
298
299 static_assert(kNumConstructorArgs == 2, "Change the varargs below if you change the constant");
300 env->NewObject(klass, constructor, initargs[0], initargs[1]);
301 if (env->ExceptionOccurred()) {
302 env->ExceptionDescribe();
303 env->ExceptionClear();
304 return JNI_FALSE;
305 }
306
307 return JNI_TRUE;
308 }
309
Java_Reflection_getHiddenApiAccessFlags(JNIEnv *,jclass)310 extern "C" JNIEXPORT jint JNICALL Java_Reflection_getHiddenApiAccessFlags(JNIEnv*, jclass) {
311 return static_cast<jint>(kAccHiddenapiBits);
312 }
313
Java_Reflection_setHiddenApiCheckHardening(JNIEnv *,jclass,jboolean value)314 extern "C" JNIEXPORT void JNICALL Java_Reflection_setHiddenApiCheckHardening(JNIEnv*, jclass,
315 jboolean value) {
316 CompatFramework& compat_framework = Runtime::Current()->GetCompatFramework();
317 std::set<uint64_t> disabled_changes = compat_framework.GetDisabledCompatChanges();
318 if (value == JNI_TRUE) {
319 // If hidden api check hardening is enabled, remove it from the set of disabled changes.
320 disabled_changes.erase(kPreventMetaReflectionBlocklistAccess);
321 } else {
322 // If hidden api check hardening is disabled, add it to the set of disabled changes.
323 disabled_changes.insert(kPreventMetaReflectionBlocklistAccess);
324 }
325 compat_framework.SetDisabledCompatChanges(disabled_changes);
326 }
327
328 } // namespace Test674HiddenApi
329 } // namespace art
330