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