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