diff options
Diffstat (limited to 'runtime/hidden_api.cc')
-rw-r--r-- | runtime/hidden_api.cc | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/runtime/hidden_api.cc b/runtime/hidden_api.cc index f42ed49140..9e2ad9291b 100644 --- a/runtime/hidden_api.cc +++ b/runtime/hidden_api.cc @@ -590,5 +590,121 @@ template bool ShouldDenyAccessToMemberImpl<ArtMethod>(ArtMethod* member, AccessMethod access_method); } // namespace detail +template<typename T> +bool ShouldDenyAccessToMember(T* member, + const std::function<AccessContext()>& fn_get_access_context, + AccessMethod access_method) { + DCHECK(member != nullptr); + + // First check if we have an explicit sdk checker installed that should be used to + // verify access. If so, make the decision based on it. + // + // This is used during off-device AOT compilation which may want to generate verification + // metadata only for a specific list of public SDKs. Note that the check here is made + // based on descriptor equality and it's aim to further restrict a symbol that would + // otherwise be resolved. + // + // The check only applies to boot classpaths dex files. + Runtime* runtime = Runtime::Current(); + if (UNLIKELY(runtime->IsAotCompiler())) { + if (member->GetDeclaringClass()->GetClassLoader() == nullptr && + runtime->GetClassLinker()->DenyAccessBasedOnPublicSdk(member)) { + return true; + } + } + + // Get the runtime flags encoded in member's access flags. + // Note: this works for proxy methods because they inherit access flags from their + // respective interface methods. + const uint32_t runtime_flags = GetRuntimeFlags(member); + + // Exit early if member is public API. This flag is also set for non-boot class + // path fields/methods. + if ((runtime_flags & kAccPublicApi) != 0) { + return false; + } + + // Determine which domain the caller and callee belong to. + // This can be *very* expensive. This is why ShouldDenyAccessToMember + // should not be called on every individual access. + const AccessContext caller_context = fn_get_access_context(); + const AccessContext callee_context(member->GetDeclaringClass()); + + // Non-boot classpath callers should have exited early. + DCHECK(!callee_context.IsApplicationDomain()); + + // Check if the caller is always allowed to access members in the callee context. + if (caller_context.CanAlwaysAccess(callee_context)) { + return false; + } + + // Check if this is platform accessing core platform. We may warn if `member` is + // not part of core platform API. + switch (caller_context.GetDomain()) { + case Domain::kApplication: { + DCHECK(!callee_context.IsApplicationDomain()); + + // Exit early if access checks are completely disabled. + EnforcementPolicy policy = runtime->GetHiddenApiEnforcementPolicy(); + if (policy == EnforcementPolicy::kDisabled) { + return false; + } + + // If this is a proxy method, look at the interface method instead. + member = detail::GetInterfaceMemberIfProxy(member); + + // Decode hidden API access flags from the dex file. + // This is an O(N) operation scaling with the number of fields/methods + // in the class. Only do this on slow path and only do it once. + ApiList api_list(detail::GetDexFlags(member)); + DCHECK(api_list.IsValid()); + + // Member is hidden and caller is not exempted. Enter slow path. + return detail::ShouldDenyAccessToMemberImpl(member, api_list, access_method); + } + + case Domain::kPlatform: { + DCHECK(callee_context.GetDomain() == Domain::kCorePlatform); + + // Member is part of core platform API. Accessing it is allowed. + if ((runtime_flags & kAccCorePlatformApi) != 0) { + return false; + } + + // Allow access if access checks are disabled. + EnforcementPolicy policy = Runtime::Current()->GetCorePlatformApiEnforcementPolicy(); + if (policy == EnforcementPolicy::kDisabled) { + return false; + } + + // If this is a proxy method, look at the interface method instead. + member = detail::GetInterfaceMemberIfProxy(member); + + // Access checks are not disabled, report the violation. + // This may also add kAccCorePlatformApi to the access flags of `member` + // so as to not warn again on next access. + return detail::HandleCorePlatformApiViolation(member, + caller_context, + access_method, + policy); + } + + case Domain::kCorePlatform: { + LOG(FATAL) << "CorePlatform domain should be allowed to access all domains"; + UNREACHABLE(); + } + } +} + +// Need to instantiate these. +template bool ShouldDenyAccessToMember<ArtField>( + ArtField* member, + const std::function<AccessContext()>& fn_get_access_context, + AccessMethod access_method); +template bool ShouldDenyAccessToMember<ArtMethod>( + ArtMethod* member, + const std::function<AccessContext()>& fn_get_access_context, + AccessMethod access_method); + } // namespace hiddenapi } // namespace art |