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_domain.h"
23 #include "base/hiddenapi_flags.h"
24 #include "base/locks.h"
25 #include "base/macros.h"
26 #include "dex/class_accessor.h"
27 #include "intrinsics_enum.h"
28 #include "jni/jni_internal.h"
29 #include "mirror/class.h"
30 #include "mirror/class_loader.h"
31 #include "reflection.h"
32 #include "runtime.h"
33
34 namespace art HIDDEN {
35 namespace hiddenapi {
36
37 // Hidden API enforcement policy
38 // This must be kept in sync with ApplicationInfo.ApiEnforcementPolicy in
39 // frameworks/base/core/java/android/content/pm/ApplicationInfo.java
40 enum class EnforcementPolicy {
41 kDisabled = 0,
42 kJustWarn = 1, // keep checks enabled, but allow everything (enables logging)
43 kEnabled = 2, // ban conditionally blocked & blocklist
44 kMax = kEnabled,
45 };
46
EnforcementPolicyFromInt(int api_policy_int)47 inline EnforcementPolicy EnforcementPolicyFromInt(int api_policy_int) {
48 DCHECK_GE(api_policy_int, 0);
49 DCHECK_LE(api_policy_int, static_cast<int>(EnforcementPolicy::kMax));
50 return static_cast<EnforcementPolicy>(api_policy_int);
51 }
52
53 // Hidden API access method
54 // Thist must be kept in sync with VMRuntime.HiddenApiUsageLogger.ACCESS_METHOD_*
55 enum class AccessMethod {
56 kNone = 0, // internal test that does not correspond to an actual access by app
57 kReflection = 1,
58 kJNI = 2,
59 kLinking = 3,
60 };
61
62 // Represents the API domain of a caller/callee.
63 class AccessContext {
64 public:
65 // Initialize to either the fully-trusted or fully-untrusted domain.
AccessContext(bool is_trusted)66 explicit AccessContext(bool is_trusted)
67 : klass_(nullptr),
68 dex_file_(nullptr),
69 domain_(ComputeDomain(is_trusted)) {}
70
71 // Initialize from class loader and dex file (via dex cache).
AccessContext(ObjPtr<mirror::ClassLoader> class_loader,ObjPtr<mirror::DexCache> dex_cache)72 AccessContext(ObjPtr<mirror::ClassLoader> class_loader, ObjPtr<mirror::DexCache> dex_cache)
73 REQUIRES_SHARED(Locks::mutator_lock_)
74 : klass_(nullptr),
75 dex_file_(GetDexFileFromDexCache(dex_cache)),
76 domain_(ComputeDomain(class_loader, dex_file_)) {}
77
78 // Initialize from class loader and dex file (only used by tests).
AccessContext(ObjPtr<mirror::ClassLoader> class_loader,const DexFile * dex_file)79 AccessContext(ObjPtr<mirror::ClassLoader> class_loader, const DexFile* dex_file)
80 : klass_(nullptr),
81 dex_file_(dex_file),
82 domain_(ComputeDomain(class_loader, dex_file_)) {}
83
84 // Initialize from Class.
AccessContext(ObjPtr<mirror::Class> klass)85 explicit AccessContext(ObjPtr<mirror::Class> klass)
86 REQUIRES_SHARED(Locks::mutator_lock_)
87 : klass_(klass),
88 dex_file_(GetDexFileFromDexCache(klass->GetDexCache())),
89 domain_(ComputeDomain(klass, dex_file_)) {}
90
GetClass()91 ObjPtr<mirror::Class> GetClass() const { return klass_; }
GetDexFile()92 const DexFile* GetDexFile() const { return dex_file_; }
GetDomain()93 Domain GetDomain() const { return domain_; }
IsApplicationDomain()94 bool IsApplicationDomain() const { return domain_ == Domain::kApplication; }
95
96 // Returns true if this domain is always allowed to access the domain of `callee`.
CanAlwaysAccess(const AccessContext & callee)97 bool CanAlwaysAccess(const AccessContext& callee) const {
98 return IsDomainMoreTrustedThan(domain_, callee.domain_);
99 }
100
101 private:
GetDexFileFromDexCache(ObjPtr<mirror::DexCache> dex_cache)102 static const DexFile* GetDexFileFromDexCache(ObjPtr<mirror::DexCache> dex_cache)
103 REQUIRES_SHARED(Locks::mutator_lock_) {
104 return dex_cache.IsNull() ? nullptr : dex_cache->GetDexFile();
105 }
106
ComputeDomain(bool is_trusted)107 static Domain ComputeDomain(bool is_trusted) {
108 return is_trusted ? Domain::kCorePlatform : Domain::kApplication;
109 }
110
ComputeDomain(ObjPtr<mirror::ClassLoader> class_loader,const DexFile * dex_file)111 static Domain ComputeDomain(ObjPtr<mirror::ClassLoader> class_loader, const DexFile* dex_file) {
112 if (dex_file == nullptr) {
113 return ComputeDomain(/* is_trusted= */ class_loader.IsNull());
114 }
115
116 return dex_file->GetHiddenapiDomain();
117 }
118
ComputeDomain(ObjPtr<mirror::Class> klass,const DexFile * dex_file)119 static Domain ComputeDomain(ObjPtr<mirror::Class> klass, const DexFile* dex_file)
120 REQUIRES_SHARED(Locks::mutator_lock_) {
121 // Check other aspects of the context.
122 Domain domain = ComputeDomain(klass->GetClassLoader(), dex_file);
123
124 if (domain == Domain::kApplication &&
125 klass->ShouldSkipHiddenApiChecks() &&
126 Runtime::Current()->IsJavaDebuggableAtInit()) {
127 // Class is known, it is marked trusted and we are in debuggable mode.
128 domain = ComputeDomain(/* is_trusted= */ true);
129 }
130
131 return domain;
132 }
133
134 // Pointer to declaring class of the caller/callee (null if not provided).
135 // This is not safe across GC but we're only using this class for passing
136 // information about the caller to the access check logic and never retain
137 // the AccessContext instance beyond that.
138 const ObjPtr<mirror::Class> klass_;
139
140 // DexFile of the caller/callee (null if not provided).
141 const DexFile* const dex_file_;
142
143 // Computed domain of the caller/callee.
144 const Domain domain_;
145 };
146
147 class ScopedHiddenApiEnforcementPolicySetting {
148 public:
ScopedHiddenApiEnforcementPolicySetting(EnforcementPolicy new_policy)149 explicit ScopedHiddenApiEnforcementPolicySetting(EnforcementPolicy new_policy)
150 : initial_policy_(Runtime::Current()->GetHiddenApiEnforcementPolicy()) {
151 Runtime::Current()->SetHiddenApiEnforcementPolicy(new_policy);
152 }
153
~ScopedHiddenApiEnforcementPolicySetting()154 ~ScopedHiddenApiEnforcementPolicySetting() {
155 Runtime::Current()->SetHiddenApiEnforcementPolicy(initial_policy_);
156 }
157
158 private:
159 const EnforcementPolicy initial_policy_;
160 DISALLOW_COPY_AND_ASSIGN(ScopedHiddenApiEnforcementPolicySetting);
161 };
162
163 void InitializeCorePlatformApiPrivateFields() REQUIRES(!Locks::mutator_lock_);
164
165 // Walks the stack, finds the caller of this reflective call and returns
166 // a hiddenapi AccessContext formed from its declaring class.
167 AccessContext GetReflectionCallerAccessContext(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_);
168
169 // Implementation details. DO NOT ACCESS DIRECTLY.
170 namespace detail {
171
172 // Class to encapsulate the signature of a member (ArtField or ArtMethod). This
173 // is used as a helper when matching prefixes, and when logging the signature.
174 class MemberSignature {
175 private:
176 enum MemberType {
177 kField,
178 kMethod,
179 };
180
181 std::string class_name_;
182 std::string member_name_;
183 std::string type_signature_;
184 std::string tmp_;
185 MemberType type_;
186
187 inline std::vector<const char*> GetSignatureParts() const;
188
189 public:
190 explicit MemberSignature(ArtField* field) REQUIRES_SHARED(Locks::mutator_lock_);
191 explicit MemberSignature(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_);
192 explicit MemberSignature(const ClassAccessor::Field& field);
193 explicit MemberSignature(const ClassAccessor::Method& method);
194
195 void Dump(std::ostream& os) const;
196
197 bool Equals(const MemberSignature& other);
198 bool MemberNameAndTypeMatch(const MemberSignature& other);
199
200 // Performs prefix match on this member. Since the full member signature is
201 // composed of several parts, we match each part in turn (rather than
202 // building the entire thing in memory and performing a simple prefix match)
203 bool DoesPrefixMatch(const std::string& prefix) const;
204
205 bool DoesPrefixMatchAny(const std::vector<std::string>& exemptions);
206
207 void WarnAboutAccess(AccessMethod access_method, ApiList list, bool access_denied);
208
209 void LogAccessToEventLog(uint32_t sampled_value, AccessMethod access_method, bool access_denied);
210
211 // Calls back into managed code to notify VMRuntime.nonSdkApiUsageConsumer that
212 // |member| was accessed. This is usually called when an API is unsupported,
213 // conditionally or unconditionally blocked. Given that the callback can execute arbitrary
214 // code, a call to this method can result in thread suspension.
215 void NotifyHiddenApiListener(AccessMethod access_method);
216 };
217
218 // Locates hiddenapi flags for `member` in the corresponding dex file.
219 // NB: This is an O(N) operation, linear with the number of members in the class def.
220 template<typename T>
221 uint32_t GetDexFlags(T* member) REQUIRES_SHARED(Locks::mutator_lock_);
222
223 // Handler of detected core platform API violations. Returns true if access to
224 // `member` should be denied.
225 template<typename T>
226 bool HandleCorePlatformApiViolation(T* member,
227 const AccessContext& caller_context,
228 AccessMethod access_method,
229 EnforcementPolicy policy)
230 REQUIRES_SHARED(Locks::mutator_lock_);
231
232 template<typename T>
233 bool ShouldDenyAccessToMemberImpl(T* member, ApiList api_list, AccessMethod access_method)
234 REQUIRES_SHARED(Locks::mutator_lock_);
235
GetInterfaceMemberIfProxy(ArtField * field)236 inline ArtField* GetInterfaceMemberIfProxy(ArtField* field) { return field; }
237
GetInterfaceMemberIfProxy(ArtMethod * method)238 inline ArtMethod* GetInterfaceMemberIfProxy(ArtMethod* method)
239 REQUIRES_SHARED(Locks::mutator_lock_) {
240 return method->GetInterfaceMethodIfProxy(kRuntimePointerSize);
241 }
242
243 // Returns access flags for the runtime representation of a class member (ArtField/ArtMember).
CreateRuntimeFlags_Impl(uint32_t dex_flags)244 ALWAYS_INLINE inline uint32_t CreateRuntimeFlags_Impl(uint32_t dex_flags) {
245 uint32_t runtime_flags = 0u;
246
247 ApiList api_list(dex_flags);
248 DCHECK(api_list.IsValid());
249
250 if (api_list.Contains(ApiList::Sdk())) {
251 runtime_flags |= kAccPublicApi;
252 } else {
253 // Only add domain-specific flags for non-public API members.
254 // This simplifies hardcoded values for intrinsics.
255 if (api_list.Contains(ApiList::CorePlatformApi())) {
256 runtime_flags |= kAccCorePlatformApi;
257 }
258 }
259
260 DCHECK_EQ(runtime_flags & kAccHiddenapiBits, runtime_flags)
261 << "Runtime flags not in reserved access flags bits";
262 return runtime_flags;
263 }
264
265 } // namespace detail
266
267 // Returns access flags for the runtime representation of a class member (ArtField/ArtMember).
CreateRuntimeFlags(const ClassAccessor::BaseItem & member)268 ALWAYS_INLINE inline uint32_t CreateRuntimeFlags(const ClassAccessor::BaseItem& member) {
269 return detail::CreateRuntimeFlags_Impl(member.GetHiddenapiFlags());
270 }
271
272 // Returns access flags for the runtime representation of a class member (ArtField/ArtMember).
273 template<typename T>
CreateRuntimeFlags(T * member)274 ALWAYS_INLINE inline uint32_t CreateRuntimeFlags(T* member) REQUIRES_SHARED(Locks::mutator_lock_) {
275 return detail::CreateRuntimeFlags_Impl(detail::GetDexFlags(member));
276 }
277
278 // Extracts hiddenapi runtime flags from access flags of ArtField.
GetRuntimeFlags(ArtField * field)279 ALWAYS_INLINE inline uint32_t GetRuntimeFlags(ArtField* field)
280 REQUIRES_SHARED(Locks::mutator_lock_) {
281 return field->GetAccessFlags() & kAccHiddenapiBits;
282 }
283
284 // Extracts hiddenapi runtime flags from access flags of ArtMethod.
285 // Uses hardcoded values for intrinsics.
GetRuntimeFlags(ArtMethod * method)286 ALWAYS_INLINE inline uint32_t GetRuntimeFlags(ArtMethod* method)
287 REQUIRES_SHARED(Locks::mutator_lock_) {
288 if (UNLIKELY(method->IsIntrinsic())) {
289 switch (static_cast<Intrinsics>(method->GetIntrinsic())) {
290 case Intrinsics::kSystemArrayCopyChar:
291 case Intrinsics::kSystemArrayCopyByte:
292 case Intrinsics::kSystemArrayCopyInt:
293 case Intrinsics::kStringGetCharsNoCheck:
294 case Intrinsics::kReferenceGetReferent:
295 case Intrinsics::kReferenceRefersTo:
296 case Intrinsics::kMemoryPeekByte:
297 case Intrinsics::kMemoryPokeByte:
298 case Intrinsics::kCRC32Update:
299 case Intrinsics::kCRC32UpdateBytes:
300 case Intrinsics::kCRC32UpdateByteBuffer:
301 case Intrinsics::kStringNewStringFromBytes:
302 case Intrinsics::kStringNewStringFromChars:
303 case Intrinsics::kStringNewStringFromString:
304 case Intrinsics::kMemoryPeekIntNative:
305 case Intrinsics::kMemoryPeekLongNative:
306 case Intrinsics::kMemoryPeekShortNative:
307 case Intrinsics::kMemoryPokeIntNative:
308 case Intrinsics::kMemoryPokeLongNative:
309 case Intrinsics::kMemoryPokeShortNative:
310 case Intrinsics::kUnsafeCASInt:
311 case Intrinsics::kUnsafeCASLong:
312 case Intrinsics::kUnsafeCASObject:
313 case Intrinsics::kUnsafeGetAndAddInt:
314 case Intrinsics::kUnsafeGetAndAddLong:
315 case Intrinsics::kUnsafeGetAndSetInt:
316 case Intrinsics::kUnsafeGetAndSetLong:
317 case Intrinsics::kUnsafeGetAndSetObject:
318 case Intrinsics::kUnsafeGetLongVolatile:
319 case Intrinsics::kUnsafeGetObjectVolatile:
320 case Intrinsics::kUnsafeGetVolatile:
321 case Intrinsics::kUnsafePutLongOrdered:
322 case Intrinsics::kUnsafePutLongVolatile:
323 case Intrinsics::kUnsafePutObjectOrdered:
324 case Intrinsics::kUnsafePutObjectVolatile:
325 case Intrinsics::kUnsafePutOrdered:
326 case Intrinsics::kUnsafePutVolatile:
327 case Intrinsics::kUnsafeLoadFence:
328 case Intrinsics::kUnsafeStoreFence:
329 case Intrinsics::kUnsafeFullFence:
330 case Intrinsics::kJdkUnsafeCASInt:
331 case Intrinsics::kJdkUnsafeCASLong:
332 case Intrinsics::kJdkUnsafeCASObject:
333 case Intrinsics::kJdkUnsafeCompareAndSetInt:
334 case Intrinsics::kJdkUnsafeCompareAndSetLong:
335 case Intrinsics::kJdkUnsafeCompareAndSetReference:
336 case Intrinsics::kJdkUnsafeGetAndAddInt:
337 case Intrinsics::kJdkUnsafeGetAndAddLong:
338 case Intrinsics::kJdkUnsafeGetAndSetInt:
339 case Intrinsics::kJdkUnsafeGetAndSetLong:
340 case Intrinsics::kJdkUnsafeGetAndSetReference:
341 case Intrinsics::kJdkUnsafeGetLongVolatile:
342 case Intrinsics::kJdkUnsafeGetLongAcquire:
343 case Intrinsics::kJdkUnsafeGetReferenceVolatile:
344 case Intrinsics::kJdkUnsafeGetReferenceAcquire:
345 case Intrinsics::kJdkUnsafeGetVolatile:
346 case Intrinsics::kJdkUnsafeGetAcquire:
347 case Intrinsics::kJdkUnsafePutLongOrdered:
348 case Intrinsics::kJdkUnsafePutLongVolatile:
349 case Intrinsics::kJdkUnsafePutLongRelease:
350 case Intrinsics::kJdkUnsafePutObjectOrdered:
351 case Intrinsics::kJdkUnsafePutReferenceVolatile:
352 case Intrinsics::kJdkUnsafePutReferenceRelease:
353 case Intrinsics::kJdkUnsafePutOrdered:
354 case Intrinsics::kJdkUnsafePutVolatile:
355 case Intrinsics::kJdkUnsafePutRelease:
356 case Intrinsics::kJdkUnsafeLoadFence:
357 case Intrinsics::kJdkUnsafeStoreFence:
358 case Intrinsics::kJdkUnsafeFullFence:
359 case Intrinsics::kJdkUnsafeGet:
360 case Intrinsics::kJdkUnsafeGetLong:
361 case Intrinsics::kJdkUnsafeGetByte:
362 case Intrinsics::kJdkUnsafeGetReference:
363 case Intrinsics::kJdkUnsafePutLong:
364 case Intrinsics::kJdkUnsafePut:
365 case Intrinsics::kJdkUnsafePutReference:
366 case Intrinsics::kJdkUnsafePutByte:
367 return 0u;
368 case Intrinsics::kFP16Ceil:
369 case Intrinsics::kFP16Compare:
370 case Intrinsics::kFP16Floor:
371 case Intrinsics::kFP16Greater:
372 case Intrinsics::kFP16GreaterEquals:
373 case Intrinsics::kFP16Less:
374 case Intrinsics::kFP16LessEquals:
375 case Intrinsics::kFP16Min:
376 case Intrinsics::kFP16Max:
377 case Intrinsics::kFP16ToFloat:
378 case Intrinsics::kFP16ToHalf:
379 case Intrinsics::kFP16Rint:
380 case Intrinsics::kUnsafeGet:
381 case Intrinsics::kUnsafeGetLong:
382 case Intrinsics::kUnsafeGetByte:
383 case Intrinsics::kUnsafeGetObject:
384 case Intrinsics::kUnsafePutLong:
385 case Intrinsics::kUnsafePut:
386 case Intrinsics::kUnsafePutObject:
387 case Intrinsics::kUnsafePutByte:
388 return kAccCorePlatformApi;
389 default:
390 // Remaining intrinsics are public API. We DCHECK that in SetIntrinsic().
391 return kAccPublicApi;
392 }
393 } else {
394 return method->GetAccessFlags() & kAccHiddenapiBits;
395 }
396 }
397
398 // Called by class linker when a new dex file has been registered. Assigns
399 // the AccessContext domain to the newly-registered dex file based on its
400 // location and class loader.
401 void InitializeDexFileDomain(const DexFile& dex_file, ObjPtr<mirror::ClassLoader> class_loader);
402
403 // Returns true if access to `member` should be denied in the given context.
404 // The decision is based on whether the caller is in a trusted context or not.
405 // Because determining the access context can be expensive, a lambda function
406 // "fn_get_access_context" is lazily invoked after other criteria have been
407 // considered.
408 // This function might print warnings into the log if the member is hidden.
409 template<typename T>
410 bool ShouldDenyAccessToMember(T* member,
411 const std::function<AccessContext()>& fn_get_access_context,
412 AccessMethod access_method)
413 REQUIRES_SHARED(Locks::mutator_lock_);
414
415 // Helper method for callers where access context can be determined beforehand.
416 // Wraps AccessContext in a lambda and passes it to the real ShouldDenyAccessToMember.
417 template<typename T>
ShouldDenyAccessToMember(T * member,const AccessContext & access_context,AccessMethod access_method)418 inline bool ShouldDenyAccessToMember(T* member,
419 const AccessContext& access_context,
420 AccessMethod access_method)
421 REQUIRES_SHARED(Locks::mutator_lock_) {
422 return ShouldDenyAccessToMember(member, [&]() { return access_context; }, access_method);
423 }
424
425 } // namespace hiddenapi
426 } // namespace art
427
428 #endif // ART_RUNTIME_HIDDEN_API_H_
429