diff options
author | 2019-10-31 14:59:26 +0000 | |
---|---|---|
committer | 2019-11-07 15:23:32 +0000 | |
commit | 267366ca19e7b71a63d3c4a02976cc56a6e58adc (patch) | |
tree | 063ef118f770096ac667f5b4c7d22b75693896c0 | |
parent | fa2b2d35255515accd0aa69193aa5e72b009e38e (diff) |
Only allow access to @TestApi signatures in instrumented processes.
Note that the check is for "pure" @TestApi signatures, i.e. those that are on blacklist. If the signature is also annotated with @SystemApi or @UnsupportedApiUsage then it would not be on blacklist.
Bug: 133832325
Test: manual
Change-Id: I546fb42495331efd638d9def924ef33da0c80182
-rw-r--r-- | libartbase/base/hiddenapi_flags.h | 10 | ||||
-rw-r--r-- | runtime/hidden_api.cc | 21 | ||||
-rw-r--r-- | runtime/hidden_api_test.cc | 38 |
3 files changed, 62 insertions, 7 deletions
diff --git a/libartbase/base/hiddenapi_flags.h b/libartbase/base/hiddenapi_flags.h index cd0bc7578c..a9a903b71f 100644 --- a/libartbase/base/hiddenapi_flags.h +++ b/libartbase/base/hiddenapi_flags.h @@ -290,6 +290,16 @@ class ApiList { // Returns true when no ApiList is specified and no domain_api flags either. bool IsEmpty() const { return (GetValue() == Value::kInvalid) && (GetDomainApis() == 0); } + // Returns true if the ApiList is on blacklist. + bool IsBlacklisted() const { + return GetValue() == Value::kBlacklist; + } + + // Returns true if the ApiList is a test API. + bool IsTestApi() const { + return helper::MatchesBitMask(helper::ToBit(DomainApi::kTestApi), dex_flags_); + } + // Returns the maximum target SDK version allowed to access this ApiList. SdkVersion GetMaxAllowedSdkVersion() const { return kMaxSdkVersions[GetIntValue()]; } diff --git a/runtime/hidden_api.cc b/runtime/hidden_api.cc index 98774bdf2d..6a9bdf6c79 100644 --- a/runtime/hidden_api.cc +++ b/runtime/hidden_api.cc @@ -435,15 +435,10 @@ bool ShouldDenyAccessToMemberImpl(T* member, ApiList api_list, AccessMethod acce DCHECK(member != nullptr); Runtime* runtime = Runtime::Current(); - EnforcementPolicy policy = runtime->GetHiddenApiEnforcementPolicy(); - DCHECK(policy != EnforcementPolicy::kDisabled) + EnforcementPolicy hiddenApiPolicy = runtime->GetHiddenApiEnforcementPolicy(); + DCHECK(hiddenApiPolicy != EnforcementPolicy::kDisabled) << "Should never enter this function when access checks are completely disabled"; - const bool deny_access = - (policy == EnforcementPolicy::kEnabled) && - IsSdkVersionSetAndMoreThan(runtime->GetTargetSdkVersion(), - api_list.GetMaxAllowedSdkVersion()); - MemberSignature member_signature(member); // Check for an exemption first. Exempted APIs are treated as white list. @@ -455,6 +450,18 @@ bool ShouldDenyAccessToMemberImpl(T* member, ApiList api_list, AccessMethod acce return false; } + EnforcementPolicy testApiPolicy = runtime->GetTestApiEnforcementPolicy(); + + bool deny_access = false; + if (hiddenApiPolicy == EnforcementPolicy::kEnabled) { + if (testApiPolicy == EnforcementPolicy::kDisabled && api_list.IsTestApi()) { + deny_access = false; + } else { + deny_access = IsSdkVersionSetAndMoreThan(runtime->GetTargetSdkVersion(), + api_list.GetMaxAllowedSdkVersion()); + } + } + if (access_method != AccessMethod::kNone) { // Print a log message with information about this class member access. // We do this if we're about to deny access, or the app is debuggable. diff --git a/runtime/hidden_api_test.cc b/runtime/hidden_api_test.cc index d5c03c3850..145bb07676 100644 --- a/runtime/hidden_api_test.cc +++ b/runtime/hidden_api_test.cc @@ -155,6 +155,44 @@ TEST_F(HiddenApiTest, CheckGetActionFromRuntimeFlags) { ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::Blacklist()), true); } +TEST_F(HiddenApiTest, CheckTestApiEnforcement) { + ScopedObjectAccess soa(self_); + + runtime_->SetHiddenApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kEnabled); + runtime_->SetTargetSdkVersion( + static_cast<uint32_t>(hiddenapi::ApiList::GreylistMaxQ().GetMaxAllowedSdkVersion()) + 1); + + // Default case where all TestApis are treated like non-TestApi. + runtime_->SetTestApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kEnabled); + ASSERT_EQ( + ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::Whitelist()), false); + ASSERT_EQ( + ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::Greylist()), false); + ASSERT_EQ( + ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::GreylistMaxQ()), true); + ASSERT_EQ( + ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::GreylistMaxP()), true); + ASSERT_EQ( + ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::GreylistMaxO()), true); + ASSERT_EQ( + ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::Blacklist()), true); + + // A case where we want to allow access to TestApis. + runtime_->SetTestApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kDisabled); + ASSERT_EQ( + ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::Whitelist()), false); + ASSERT_EQ( + ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::Greylist()), false); + ASSERT_EQ( + ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::GreylistMaxQ()), false); + ASSERT_EQ( + ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::GreylistMaxP()), false); + ASSERT_EQ( + ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::GreylistMaxO()), false); + ASSERT_EQ( + ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::Blacklist()), false); +} + TEST_F(HiddenApiTest, CheckMembersRead) { ASSERT_NE(nullptr, class1_field1_); ASSERT_NE(nullptr, class1_field12_); |