1 /*
2 * Copyright (C) 2018 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 #ifndef ART_RUNTIME_HIDDEN_API_H_
18 #define ART_RUNTIME_HIDDEN_API_H_
19
20 #include "art_field.h"
21 #include "art_method.h"
22 #include "base/hiddenapi_flags.h"
23 #include "base/locks.h"
24 #include "intrinsics_enum.h"
25 #include "mirror/class-inl.h"
26 #include "reflection.h"
27 #include "runtime.h"
28
29 namespace art {
30 namespace hiddenapi {
31
32 // Hidden API enforcement policy
33 // This must be kept in sync with ApplicationInfo.ApiEnforcementPolicy in
34 // frameworks/base/core/java/android/content/pm/ApplicationInfo.java
35 enum class EnforcementPolicy {
36 kDisabled = 0,
37 kJustWarn = 1, // keep checks enabled, but allow everything (enables logging)
38 kEnabled = 2, // ban dark grey & blacklist
39 kMax = kEnabled,
40 };
41
EnforcementPolicyFromInt(int api_policy_int)42 inline EnforcementPolicy EnforcementPolicyFromInt(int api_policy_int) {
43 DCHECK_GE(api_policy_int, 0);
44 DCHECK_LE(api_policy_int, static_cast<int>(EnforcementPolicy::kMax));
45 return static_cast<EnforcementPolicy>(api_policy_int);
46 }
47
48 // Hidden API access method
49 // Thist must be kept in sync with VMRuntime.HiddenApiUsageLogger.ACCESS_METHOD_*
50 enum class AccessMethod {
51 kNone = 0, // internal test that does not correspond to an actual access by app
52 kReflection = 1,
53 kJNI = 2,
54 kLinking = 3,
55 };
56
57 // Represents the API domain of a caller/callee.
58 class AccessContext {
59 public:
60 // Initialize to either the fully-trusted or fully-untrusted domain.
AccessContext(bool is_trusted)61 explicit AccessContext(bool is_trusted)
62 : klass_(nullptr),
63 dex_file_(nullptr),
64 domain_(ComputeDomain(is_trusted)) {}
65
66 // Initialize from class loader and dex file (via dex cache).
AccessContext(ObjPtr<mirror::ClassLoader> class_loader,ObjPtr<mirror::DexCache> dex_cache)67 AccessContext(ObjPtr<mirror::ClassLoader> class_loader, ObjPtr<mirror::DexCache> dex_cache)
68 REQUIRES_SHARED(Locks::mutator_lock_)
69 : klass_(nullptr),
70 dex_file_(GetDexFileFromDexCache(dex_cache)),
71 domain_(ComputeDomain(class_loader, dex_file_)) {}
72
73 // Initialize from class loader and dex file (only used by tests).
AccessContext(ObjPtr<mirror::ClassLoader> class_loader,const DexFile * dex_file)74 AccessContext(ObjPtr<mirror::ClassLoader> class_loader, const DexFile* dex_file)
75 : klass_(nullptr),
76 dex_file_(dex_file),
77 domain_(ComputeDomain(class_loader, dex_file_)) {}
78
79 // Initialize from Class.
AccessContext(ObjPtr<mirror::Class> klass)80 explicit AccessContext(ObjPtr<mirror::Class> klass)
81 REQUIRES_SHARED(Locks::mutator_lock_)
82 : klass_(klass),
83 dex_file_(GetDexFileFromDexCache(klass->GetDexCache())),
84 domain_(ComputeDomain(klass, dex_file_)) {}
85
GetClass()86 ObjPtr<mirror::Class> GetClass() const { return klass_; }
GetDexFile()87 const DexFile* GetDexFile() const { return dex_file_; }
GetDomain()88 Domain GetDomain() const { return domain_; }
IsApplicationDomain()89 bool IsApplicationDomain() const { return domain_ == Domain::kApplication; }
90
91 // Returns true if this domain is always allowed to access the domain of `callee`.
CanAlwaysAccess(const AccessContext & callee)92 bool CanAlwaysAccess(const AccessContext& callee) const {
93 return IsDomainMoreTrustedThan(domain_, callee.domain_);
94 }
95
96 private:
GetDexFileFromDexCache(ObjPtr<mirror::DexCache> dex_cache)97 static const DexFile* GetDexFileFromDexCache(ObjPtr<mirror::DexCache> dex_cache)
98 REQUIRES_SHARED(Locks::mutator_lock_) {
99 return dex_cache.IsNull() ? nullptr : dex_cache->GetDexFile();
100 }
101
ComputeDomain(bool is_trusted)102 static Domain ComputeDomain(bool is_trusted) {
103 return is_trusted ? Domain::kCorePlatform : Domain::kApplication;
104 }
105
ComputeDomain(ObjPtr<mirror::ClassLoader> class_loader,const DexFile * dex_file)106 static Domain ComputeDomain(ObjPtr<mirror::ClassLoader> class_loader, const DexFile* dex_file) {
107 if (dex_file == nullptr) {
108 return ComputeDomain(/* is_trusted= */ class_loader.IsNull());
109 }
110
111 return dex_file->GetHiddenapiDomain();
112 }
113
ComputeDomain(ObjPtr<mirror::Class> klass,const DexFile * dex_file)114 static Domain ComputeDomain(ObjPtr<mirror::Class> klass, const DexFile* dex_file)
115 REQUIRES_SHARED(Locks::mutator_lock_) {
116 // Check other aspects of the context.
117 Domain domain = ComputeDomain(klass->GetClassLoader(), dex_file);
118
119 if (domain == Domain::kApplication &&
120 klass->ShouldSkipHiddenApiChecks() &&
121 Runtime::Current()->IsJavaDebuggable()) {
122 // Class is known, it is marked trusted and we are in debuggable mode.
123 domain = ComputeDomain(/* is_trusted= */ true);
124 }
125
126 return domain;
127 }
128
129 // Pointer to declaring class of the caller/callee (null if not provided).
130 // This is not safe across GC but we're only using this class for passing
131 // information about the caller to the access check logic and never retain
132 // the AccessContext instance beyond that.
133 const ObjPtr<mirror::Class> klass_;
134
135 // DexFile of the caller/callee (null if not provided).
136 const DexFile* const dex_file_;
137
138 // Computed domain of the caller/callee.
139 const Domain domain_;
140 };
141
142 class ScopedHiddenApiEnforcementPolicySetting {
143 public:
ScopedHiddenApiEnforcementPolicySetting(EnforcementPolicy new_policy)144 explicit ScopedHiddenApiEnforcementPolicySetting(EnforcementPolicy new_policy)
145 : initial_policy_(Runtime::Current()->GetHiddenApiEnforcementPolicy()) {
146 Runtime::Current()->SetHiddenApiEnforcementPolicy(new_policy);
147 }
148
~ScopedHiddenApiEnforcementPolicySetting()149 ~ScopedHiddenApiEnforcementPolicySetting() {
150 Runtime::Current()->SetHiddenApiEnforcementPolicy(initial_policy_);
151 }
152
153 private:
154 const EnforcementPolicy initial_policy_;
155 DISALLOW_COPY_AND_ASSIGN(ScopedHiddenApiEnforcementPolicySetting);
156 };
157
158 // Implementation details. DO NOT ACCESS DIRECTLY.
159 namespace detail {
160
161 // Class to encapsulate the signature of a member (ArtField or ArtMethod). This
162 // is used as a helper when matching prefixes, and when logging the signature.
163 class MemberSignature {
164 private:
165 enum MemberType {
166 kField,
167 kMethod,
168 };
169
170 std::string class_name_;
171 std::string member_name_;
172 std::string type_signature_;
173 std::string tmp_;
174 MemberType type_;
175
176 inline std::vector<const char*> GetSignatureParts() const;
177
178 public:
179 explicit MemberSignature(ArtField* field) REQUIRES_SHARED(Locks::mutator_lock_);
180 explicit MemberSignature(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_);
181 explicit MemberSignature(const ClassAccessor::Field& field);
182 explicit MemberSignature(const ClassAccessor::Method& method);
183
184 void Dump(std::ostream& os) const;
185
186 bool Equals(const MemberSignature& other);
187 bool MemberNameAndTypeMatch(const MemberSignature& other);
188
189 // Performs prefix match on this member. Since the full member signature is
190 // composed of several parts, we match each part in turn (rather than
191 // building the entire thing in memory and performing a simple prefix match)
192 bool DoesPrefixMatch(const std::string& prefix) const;
193
194 bool IsExempted(const std::vector<std::string>& exemptions);
195
196 void WarnAboutAccess(AccessMethod access_method, ApiList list, bool access_denied);
197
198 void LogAccessToEventLog(uint32_t sampled_value, AccessMethod access_method, bool access_denied);
199
200 // Calls back into managed code to notify VMRuntime.nonSdkApiUsageConsumer that
201 // |member| was accessed. This is usually called when an API is on the black,
202 // dark grey or light grey lists. Given that the callback can execute arbitrary
203 // code, a call to this method can result in thread suspension.
204 void NotifyHiddenApiListener(AccessMethod access_method);
205 };
206
207 // Locates hiddenapi flags for `field` in the corresponding dex file.
208 // NB: This is an O(N) operation, linear with the number of members in the class def.
209 template<typename T>
210 uint32_t GetDexFlags(T* member) REQUIRES_SHARED(Locks::mutator_lock_);
211
212 // Handler of detected core platform API violations. Returns true if access to
213 // `member` should be denied.
214 template<typename T>
215 bool HandleCorePlatformApiViolation(T* member,
216 const AccessContext& caller_context,
217 AccessMethod access_method,
218 EnforcementPolicy policy)
219 REQUIRES_SHARED(Locks::mutator_lock_);
220
221 template<typename T>
222 bool ShouldDenyAccessToMemberImpl(T* member, ApiList api_list, AccessMethod access_method)
223 REQUIRES_SHARED(Locks::mutator_lock_);
224
GetInterfaceMemberIfProxy(ArtField * field)225 inline ArtField* GetInterfaceMemberIfProxy(ArtField* field) { return field; }
226
GetInterfaceMemberIfProxy(ArtMethod * method)227 inline ArtMethod* GetInterfaceMemberIfProxy(ArtMethod* method)
228 REQUIRES_SHARED(Locks::mutator_lock_) {
229 return method->GetInterfaceMethodIfProxy(kRuntimePointerSize);
230 }
231
232 // Returns access flags for the runtime representation of a class member (ArtField/ArtMember).
CreateRuntimeFlags_Impl(uint32_t dex_flags)233 ALWAYS_INLINE inline uint32_t CreateRuntimeFlags_Impl(uint32_t dex_flags) {
234 uint32_t runtime_flags = 0u;
235
236 ApiList api_list(dex_flags);
237 DCHECK(api_list.IsValid());
238
239 if (api_list.Contains(ApiList::Whitelist())) {
240 runtime_flags |= kAccPublicApi;
241 } else {
242 // Only add domain-specific flags for non-public API members.
243 // This simplifies hardcoded values for intrinsics.
244 if (api_list.Contains(ApiList::CorePlatformApi())) {
245 runtime_flags |= kAccCorePlatformApi;
246 }
247 }
248
249 DCHECK_EQ(runtime_flags & kAccHiddenapiBits, runtime_flags)
250 << "Runtime flags not in reserved access flags bits";
251 return runtime_flags;
252 }
253
254 } // namespace detail
255
256 // Returns access flags for the runtime representation of a class member (ArtField/ArtMember).
CreateRuntimeFlags(const ClassAccessor::BaseItem & member)257 ALWAYS_INLINE inline uint32_t CreateRuntimeFlags(const ClassAccessor::BaseItem& member) {
258 return detail::CreateRuntimeFlags_Impl(member.GetHiddenapiFlags());
259 }
260
261 // Returns access flags for the runtime representation of a class member (ArtField/ArtMember).
262 template<typename T>
CreateRuntimeFlags(T * member)263 ALWAYS_INLINE inline uint32_t CreateRuntimeFlags(T* member) REQUIRES_SHARED(Locks::mutator_lock_) {
264 return detail::CreateRuntimeFlags_Impl(detail::GetDexFlags(member));
265 }
266
267 // Extracts hiddenapi runtime flags from access flags of ArtField.
GetRuntimeFlags(ArtField * field)268 ALWAYS_INLINE inline uint32_t GetRuntimeFlags(ArtField* field)
269 REQUIRES_SHARED(Locks::mutator_lock_) {
270 return field->GetAccessFlags() & kAccHiddenapiBits;
271 }
272
273 // Extracts hiddenapi runtime flags from access flags of ArtMethod.
274 // Uses hardcoded values for intrinsics.
GetRuntimeFlags(ArtMethod * method)275 ALWAYS_INLINE inline uint32_t GetRuntimeFlags(ArtMethod* method)
276 REQUIRES_SHARED(Locks::mutator_lock_) {
277 if (UNLIKELY(method->IsIntrinsic())) {
278 switch (static_cast<Intrinsics>(method->GetIntrinsic())) {
279 case Intrinsics::kSystemArrayCopyChar:
280 case Intrinsics::kStringGetCharsNoCheck:
281 case Intrinsics::kReferenceGetReferent:
282 case Intrinsics::kMemoryPeekByte:
283 case Intrinsics::kMemoryPokeByte:
284 case Intrinsics::kUnsafeCASInt:
285 case Intrinsics::kUnsafeCASLong:
286 case Intrinsics::kUnsafeCASObject:
287 case Intrinsics::kUnsafeGet:
288 case Intrinsics::kUnsafeGetAndAddInt:
289 case Intrinsics::kUnsafeGetAndAddLong:
290 case Intrinsics::kUnsafeGetAndSetInt:
291 case Intrinsics::kUnsafeGetAndSetLong:
292 case Intrinsics::kUnsafeGetAndSetObject:
293 case Intrinsics::kUnsafeGetLongVolatile:
294 case Intrinsics::kUnsafeGetObject:
295 case Intrinsics::kUnsafeGetObjectVolatile:
296 case Intrinsics::kUnsafeGetVolatile:
297 case Intrinsics::kUnsafePut:
298 case Intrinsics::kUnsafePutLong:
299 case Intrinsics::kUnsafePutLongOrdered:
300 case Intrinsics::kUnsafePutLongVolatile:
301 case Intrinsics::kUnsafePutObject:
302 case Intrinsics::kUnsafePutObjectOrdered:
303 case Intrinsics::kUnsafePutObjectVolatile:
304 case Intrinsics::kUnsafePutOrdered:
305 case Intrinsics::kUnsafePutVolatile:
306 case Intrinsics::kUnsafeLoadFence:
307 case Intrinsics::kUnsafeStoreFence:
308 case Intrinsics::kUnsafeFullFence:
309 case Intrinsics::kCRC32Update:
310 case Intrinsics::kCRC32UpdateBytes:
311 case Intrinsics::kCRC32UpdateByteBuffer:
312 case Intrinsics::kStringNewStringFromBytes:
313 case Intrinsics::kStringNewStringFromChars:
314 case Intrinsics::kStringNewStringFromString:
315 case Intrinsics::kMemoryPeekIntNative:
316 case Intrinsics::kMemoryPeekLongNative:
317 case Intrinsics::kMemoryPeekShortNative:
318 case Intrinsics::kMemoryPokeIntNative:
319 case Intrinsics::kMemoryPokeLongNative:
320 case Intrinsics::kMemoryPokeShortNative:
321 case Intrinsics::kVarHandleFullFence:
322 case Intrinsics::kVarHandleAcquireFence:
323 case Intrinsics::kVarHandleReleaseFence:
324 case Intrinsics::kVarHandleLoadLoadFence:
325 case Intrinsics::kVarHandleStoreStoreFence:
326 case Intrinsics::kVarHandleCompareAndExchange:
327 case Intrinsics::kVarHandleCompareAndExchangeAcquire:
328 case Intrinsics::kVarHandleCompareAndExchangeRelease:
329 case Intrinsics::kVarHandleCompareAndSet:
330 case Intrinsics::kVarHandleGet:
331 case Intrinsics::kVarHandleGetAcquire:
332 case Intrinsics::kVarHandleGetAndAdd:
333 case Intrinsics::kVarHandleGetAndAddAcquire:
334 case Intrinsics::kVarHandleGetAndAddRelease:
335 case Intrinsics::kVarHandleGetAndBitwiseAnd:
336 case Intrinsics::kVarHandleGetAndBitwiseAndAcquire:
337 case Intrinsics::kVarHandleGetAndBitwiseAndRelease:
338 case Intrinsics::kVarHandleGetAndBitwiseOr:
339 case Intrinsics::kVarHandleGetAndBitwiseOrAcquire:
340 case Intrinsics::kVarHandleGetAndBitwiseOrRelease:
341 case Intrinsics::kVarHandleGetAndBitwiseXor:
342 case Intrinsics::kVarHandleGetAndBitwiseXorAcquire:
343 case Intrinsics::kVarHandleGetAndBitwiseXorRelease:
344 case Intrinsics::kVarHandleGetAndSet:
345 case Intrinsics::kVarHandleGetAndSetAcquire:
346 case Intrinsics::kVarHandleGetAndSetRelease:
347 case Intrinsics::kVarHandleGetOpaque:
348 case Intrinsics::kVarHandleGetVolatile:
349 case Intrinsics::kVarHandleSet:
350 case Intrinsics::kVarHandleSetOpaque:
351 case Intrinsics::kVarHandleSetRelease:
352 case Intrinsics::kVarHandleSetVolatile:
353 case Intrinsics::kVarHandleWeakCompareAndSet:
354 case Intrinsics::kVarHandleWeakCompareAndSetAcquire:
355 case Intrinsics::kVarHandleWeakCompareAndSetPlain:
356 case Intrinsics::kVarHandleWeakCompareAndSetRelease:
357 return 0u;
358 case Intrinsics::kUnsafeGetLong:
359 return kAccCorePlatformApi;
360 default:
361 // Remaining intrinsics are public API. We DCHECK that in SetIntrinsic().
362 return kAccPublicApi;
363 }
364 } else {
365 return method->GetAccessFlags() & kAccHiddenapiBits;
366 }
367 }
368
369 // Called by class linker when a new dex file has been registered. Assigns
370 // the AccessContext domain to the newly-registered dex file based on its
371 // location and class loader.
372 void InitializeDexFileDomain(const DexFile& dex_file, ObjPtr<mirror::ClassLoader> class_loader);
373
374 // Returns true if access to `member` should be denied in the given context.
375 // The decision is based on whether the caller is in a trusted context or not.
376 // Because determining the access context can be expensive, a lambda function
377 // "fn_get_access_context" is lazily invoked after other criteria have been
378 // considered.
379 // This function might print warnings into the log if the member is hidden.
380 template<typename T>
ShouldDenyAccessToMember(T * member,const std::function<AccessContext ()> & fn_get_access_context,AccessMethod access_method)381 inline bool ShouldDenyAccessToMember(T* member,
382 const std::function<AccessContext()>& fn_get_access_context,
383 AccessMethod access_method)
384 REQUIRES_SHARED(Locks::mutator_lock_) {
385 DCHECK(member != nullptr);
386
387 // Get the runtime flags encoded in member's access flags.
388 // Note: this works for proxy methods because they inherit access flags from their
389 // respective interface methods.
390 const uint32_t runtime_flags = GetRuntimeFlags(member);
391
392 // Exit early if member is public API. This flag is also set for non-boot class
393 // path fields/methods.
394 if ((runtime_flags & kAccPublicApi) != 0) {
395 return false;
396 }
397
398 // Determine which domain the caller and callee belong to.
399 // This can be *very* expensive. This is why ShouldDenyAccessToMember
400 // should not be called on every individual access.
401 const AccessContext caller_context = fn_get_access_context();
402 const AccessContext callee_context(member->GetDeclaringClass());
403
404 // Non-boot classpath callers should have exited early.
405 DCHECK(!callee_context.IsApplicationDomain());
406
407 // Check if the caller is always allowed to access members in the callee context.
408 if (caller_context.CanAlwaysAccess(callee_context)) {
409 return false;
410 }
411
412 // Check if this is platform accessing core platform. We may warn if `member` is
413 // not part of core platform API.
414 switch (caller_context.GetDomain()) {
415 case Domain::kApplication: {
416 DCHECK(!callee_context.IsApplicationDomain());
417
418 // Exit early if access checks are completely disabled.
419 EnforcementPolicy policy = Runtime::Current()->GetHiddenApiEnforcementPolicy();
420 if (policy == EnforcementPolicy::kDisabled) {
421 return false;
422 }
423
424 // If this is a proxy method, look at the interface method instead.
425 member = detail::GetInterfaceMemberIfProxy(member);
426
427 // Decode hidden API access flags from the dex file.
428 // This is an O(N) operation scaling with the number of fields/methods
429 // in the class. Only do this on slow path and only do it once.
430 ApiList api_list(detail::GetDexFlags(member));
431 DCHECK(api_list.IsValid());
432
433 // Member is hidden and caller is not exempted. Enter slow path.
434 return detail::ShouldDenyAccessToMemberImpl(member, api_list, access_method);
435 }
436
437 case Domain::kPlatform: {
438 DCHECK(callee_context.GetDomain() == Domain::kCorePlatform);
439
440 // Member is part of core platform API. Accessing it is allowed.
441 if ((runtime_flags & kAccCorePlatformApi) != 0) {
442 return false;
443 }
444
445 // Allow access if access checks are disabled.
446 EnforcementPolicy policy = Runtime::Current()->GetCorePlatformApiEnforcementPolicy();
447 if (policy == EnforcementPolicy::kDisabled) {
448 return false;
449 }
450
451 // If this is a proxy method, look at the interface method instead.
452 member = detail::GetInterfaceMemberIfProxy(member);
453
454 // Access checks are not disabled, report the violation.
455 // This may also add kAccCorePlatformApi to the access flags of `member`
456 // so as to not warn again on next access.
457 return detail::HandleCorePlatformApiViolation(member,
458 caller_context,
459 access_method,
460 policy);
461 }
462
463 case Domain::kCorePlatform: {
464 LOG(FATAL) << "CorePlatform domain should be allowed to access all domains";
465 UNREACHABLE();
466 }
467 }
468 }
469
470 // Helper method for callers where access context can be determined beforehand.
471 // Wraps AccessContext in a lambda and passes it to the real ShouldDenyAccessToMember.
472 template<typename T>
ShouldDenyAccessToMember(T * member,const AccessContext & access_context,AccessMethod access_method)473 inline bool ShouldDenyAccessToMember(T* member,
474 const AccessContext& access_context,
475 AccessMethod access_method)
476 REQUIRES_SHARED(Locks::mutator_lock_) {
477 return ShouldDenyAccessToMember(member, [&]() { return access_context; }, access_method);
478 }
479
480 } // namespace hiddenapi
481 } // namespace art
482
483 #endif // ART_RUNTIME_HIDDEN_API_H_
484