summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Mathew Inwood <mathewi@google.com> 2018-03-22 11:36:47 +0000
committer Mathew Inwood <mathewi@google.com> 2018-03-23 11:43:35 +0000
commit597d7f650b0656fcb3985b01f53284717b41e5cc (patch)
tree59ba9853104427b19f2449ce547301764d22756b
parent753ce1bcf458ad6c6fbb41689901943d44e7738e (diff)
More flexible API enforcement policy support.
This CL adds the ability to configure which banned API lists to enforce, defined by new enum hiddenapi::ApiEnforcementPolicy. Currently, the policy can be set at zygote fork time, but not at dex optimization time where blacklist enforcement is still assumed. As such, making the policy more strict will not work as expected yet. This will be improved in a follow up CL. Test: art tests pass Test: Device boots BUG: 73337509 (cherry-picked from commit 159f596eec01adbb5a1c9654402c137cdb943131) Change-Id: I6c319bb8a3000cb1d3c4693b4fb196e749c36d96 Merged-In: I33f9afce628a86727e400052f4d5979d3536da8c
-rw-r--r--runtime/hidden_api.h69
-rw-r--r--runtime/native/dalvik_system_ZygoteHooks.cc49
-rw-r--r--runtime/native/java_lang_Class.cc4
-rw-r--r--runtime/runtime.cc13
-rw-r--r--runtime/runtime.h14
-rw-r--r--runtime/well_known_classes.cc9
-rw-r--r--test/674-hiddenapi/hiddenapi.cc3
7 files changed, 107 insertions, 54 deletions
diff --git a/runtime/hidden_api.h b/runtime/hidden_api.h
index f2ea2fdaaa..321d55d9b7 100644
--- a/runtime/hidden_api.h
+++ b/runtime/hidden_api.h
@@ -27,6 +27,23 @@
namespace art {
namespace hiddenapi {
+// Hidden API enforcement policy
+// This must be kept in sync with ApplicationInfo.ApiEnforcementPolicy in
+// frameworks/base/core/java/android/content/pm/ApplicationInfo.java
+enum class EnforcementPolicy {
+ kNoChecks = 0,
+ kAllLists = 1, // ban anything but whitelist
+ kDarkGreyAndBlackList = 2, // ban dark grey & blacklist
+ kBlacklistOnly = 3, // ban blacklist violations only
+ kMax = kBlacklistOnly,
+};
+
+inline EnforcementPolicy EnforcementPolicyFromInt(int api_policy_int) {
+ DCHECK_GE(api_policy_int, 0);
+ DCHECK_LE(api_policy_int, static_cast<int>(EnforcementPolicy::kMax));
+ return static_cast<EnforcementPolicy>(api_policy_int);
+}
+
enum Action {
kAllow,
kAllowButWarn,
@@ -59,16 +76,38 @@ inline std::ostream& operator<<(std::ostream& os, AccessMethod value) {
return os;
}
+static constexpr bool EnumsEqual(EnforcementPolicy policy, HiddenApiAccessFlags::ApiList apiList) {
+ return static_cast<int>(policy) == static_cast<int>(apiList);
+}
+
inline Action GetMemberAction(uint32_t access_flags) {
- switch (HiddenApiAccessFlags::DecodeFromRuntime(access_flags)) {
- case HiddenApiAccessFlags::kWhitelist:
- return kAllow;
- case HiddenApiAccessFlags::kLightGreylist:
- return kAllowButWarn;
- case HiddenApiAccessFlags::kDarkGreylist:
- return kAllowButWarnAndToast;
- case HiddenApiAccessFlags::kBlacklist:
- return kDeny;
+ EnforcementPolicy policy = Runtime::Current()->GetHiddenApiEnforcementPolicy();
+ if (policy == EnforcementPolicy::kNoChecks) {
+ // Exit early. Nothing to enforce.
+ return kAllow;
+ }
+
+ HiddenApiAccessFlags::ApiList api_list = HiddenApiAccessFlags::DecodeFromRuntime(access_flags);
+ if (api_list == HiddenApiAccessFlags::kWhitelist) {
+ return kAllow;
+ }
+ // The logic below relies on equality of values in the enums EnforcementPolicy and
+ // HiddenApiAccessFlags::ApiList, and their ordering. Assert that this is as expected.
+ static_assert(
+ EnumsEqual(EnforcementPolicy::kAllLists, HiddenApiAccessFlags::kLightGreylist) &&
+ EnumsEqual(EnforcementPolicy::kDarkGreyAndBlackList, HiddenApiAccessFlags::kDarkGreylist) &&
+ EnumsEqual(EnforcementPolicy::kBlacklistOnly, HiddenApiAccessFlags::kBlacklist),
+ "Mismatch between EnforcementPolicy and ApiList enums");
+ static_assert(
+ EnforcementPolicy::kAllLists < EnforcementPolicy::kDarkGreyAndBlackList &&
+ EnforcementPolicy::kDarkGreyAndBlackList < EnforcementPolicy::kBlacklistOnly,
+ "EnforcementPolicy values ordering not correct");
+ if (static_cast<int>(policy) > static_cast<int>(api_list)) {
+ return api_list == HiddenApiAccessFlags::kDarkGreylist
+ ? kAllowButWarnAndToast
+ : kAllowButWarn;
+ } else {
+ return kDeny;
}
}
@@ -107,12 +146,6 @@ inline bool ShouldBlockAccessToMember(T* member,
AccessMethod access_method)
REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK(member != nullptr);
- Runtime* runtime = Runtime::Current();
-
- if (!runtime->AreHiddenApiChecksEnabled()) {
- // Exit early. Nothing to enforce.
- return false;
- }
Action action = GetMemberAction(member->GetAccessFlags());
if (action == kAllow) {
@@ -133,14 +166,16 @@ inline bool ShouldBlockAccessToMember(T* member,
// We do this regardless of whether we block the access or not.
WarnAboutMemberAccess(member, access_method);
- // Block access if on blacklist.
if (action == kDeny) {
+ // Block access
return true;
}
// Allow access to this member but print a warning.
DCHECK(action == kAllowButWarn || action == kAllowButWarnAndToast);
+ Runtime* runtime = Runtime::Current();
+
// Depending on a runtime flag, we might move the member into whitelist and
// skip the warning the next time the member is accessed.
if (runtime->ShouldDedupeHiddenApiWarnings()) {
@@ -150,7 +185,7 @@ inline bool ShouldBlockAccessToMember(T* member,
// If this action requires a UI warning, set the appropriate flag.
if (action == kAllowButWarnAndToast || runtime->ShouldAlwaysSetHiddenApiWarningFlag()) {
- Runtime::Current()->SetPendingHiddenApiWarning(true);
+ runtime->SetPendingHiddenApiWarning(true);
}
return false;
diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc
index 89135698e3..cbc2aeb41f 100644
--- a/runtime/native/dalvik_system_ZygoteHooks.cc
+++ b/runtime/native/dalvik_system_ZygoteHooks.cc
@@ -162,19 +162,24 @@ static void CollectNonDebuggableClasses() REQUIRES(!Locks::mutator_lock_) {
// Must match values in com.android.internal.os.Zygote.
enum {
- DEBUG_ENABLE_JDWP = 1,
- DEBUG_ENABLE_CHECKJNI = 1 << 1,
- DEBUG_ENABLE_ASSERT = 1 << 2,
- DEBUG_ENABLE_SAFEMODE = 1 << 3,
- DEBUG_ENABLE_JNI_LOGGING = 1 << 4,
- DEBUG_GENERATE_DEBUG_INFO = 1 << 5,
- DEBUG_ALWAYS_JIT = 1 << 6,
- DEBUG_NATIVE_DEBUGGABLE = 1 << 7,
- DEBUG_JAVA_DEBUGGABLE = 1 << 8,
- DISABLE_VERIFIER = 1 << 9,
- ONLY_USE_SYSTEM_OAT_FILES = 1 << 10,
- ENABLE_HIDDEN_API_CHECKS = 1 << 11,
- DEBUG_GENERATE_MINI_DEBUG_INFO = 1 << 12,
+ DEBUG_ENABLE_JDWP = 1,
+ DEBUG_ENABLE_CHECKJNI = 1 << 1,
+ DEBUG_ENABLE_ASSERT = 1 << 2,
+ DEBUG_ENABLE_SAFEMODE = 1 << 3,
+ DEBUG_ENABLE_JNI_LOGGING = 1 << 4,
+ DEBUG_GENERATE_DEBUG_INFO = 1 << 5,
+ DEBUG_ALWAYS_JIT = 1 << 6,
+ DEBUG_NATIVE_DEBUGGABLE = 1 << 7,
+ DEBUG_JAVA_DEBUGGABLE = 1 << 8,
+ DISABLE_VERIFIER = 1 << 9,
+ ONLY_USE_SYSTEM_OAT_FILES = 1 << 10,
+ DEBUG_GENERATE_MINI_DEBUG_INFO = 1 << 11,
+ HIDDEN_API_ENFORCEMENT_POLICY_MASK = (1 << 12)
+ | (1 << 13),
+
+ // bits to shift (flags & HIDDEN_API_ENFORCEMENT_POLICY_MASK) by to get a value
+ // corresponding to hiddenapi::EnforcementPolicy
+ API_ENFORCEMENT_POLICY_SHIFT = CTZ(HIDDEN_API_ENFORCEMENT_POLICY_MASK),
};
static uint32_t EnableDebugFeatures(uint32_t runtime_flags) {
@@ -285,7 +290,8 @@ static void ZygoteHooks_nativePostForkChild(JNIEnv* env,
// Our system thread ID, etc, has changed so reset Thread state.
thread->InitAfterFork();
runtime_flags = EnableDebugFeatures(runtime_flags);
- bool do_hidden_api_checks = false;
+ hiddenapi::EnforcementPolicy api_enforcement_policy = hiddenapi::EnforcementPolicy::kNoChecks;
+ bool dedupe_hidden_api_warnings = true;
if ((runtime_flags & DISABLE_VERIFIER) != 0) {
Runtime::Current()->DisableVerifier();
@@ -297,10 +303,9 @@ static void ZygoteHooks_nativePostForkChild(JNIEnv* env,
runtime_flags &= ~ONLY_USE_SYSTEM_OAT_FILES;
}
- if ((runtime_flags & ENABLE_HIDDEN_API_CHECKS) != 0) {
- do_hidden_api_checks = true;
- runtime_flags &= ~ENABLE_HIDDEN_API_CHECKS;
- }
+ api_enforcement_policy = hiddenapi::EnforcementPolicyFromInt(
+ (runtime_flags & HIDDEN_API_ENFORCEMENT_POLICY_MASK) >> API_ENFORCEMENT_POLICY_SHIFT);
+ runtime_flags &= ~HIDDEN_API_ENFORCEMENT_POLICY_MASK;
if (runtime_flags != 0) {
LOG(ERROR) << StringPrintf("Unknown bits set in runtime_flags: %#x", runtime_flags);
@@ -351,11 +356,13 @@ static void ZygoteHooks_nativePostForkChild(JNIEnv* env,
}
}
+ bool do_hidden_api_checks = api_enforcement_policy != hiddenapi::EnforcementPolicy::kNoChecks;
DCHECK(!(is_system_server && do_hidden_api_checks))
- << "SystemServer should be forked with ENABLE_HIDDEN_API_CHECKS";
+ << "SystemServer should be forked with EnforcementPolicy::kDisable";
DCHECK(!(is_zygote && do_hidden_api_checks))
- << "Child zygote processes should be forked with ENABLE_HIDDEN_API_CHECKS";
- Runtime::Current()->SetHiddenApiChecksEnabled(do_hidden_api_checks);
+ << "Child zygote processes should be forked with EnforcementPolicy::kDisable";
+ Runtime::Current()->SetHiddenApiEnforcementPolicy(api_enforcement_policy);
+ Runtime::Current()->SetDedupeHiddenApiWarnings(dedupe_hidden_api_warnings);
// Clear the hidden API warning flag, in case it was set.
Runtime::Current()->SetPendingHiddenApiWarning(false);
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index 25d50376de..fc61c9597e 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -89,8 +89,8 @@ static bool IsCallerInBootClassPath(Thread* self) REQUIRES_SHARED(Locks::mutator
// access hidden APIs. This can be *very* expensive. Never call this in a loop.
ALWAYS_INLINE static bool ShouldEnforceHiddenApi(Thread* self)
REQUIRES_SHARED(Locks::mutator_lock_) {
- return Runtime::Current()->AreHiddenApiChecksEnabled() &&
- !IsCallerInBootClassPath(self);
+ hiddenapi::EnforcementPolicy policy = Runtime::Current()->GetHiddenApiEnforcementPolicy();
+ return policy != hiddenapi::EnforcementPolicy::kNoChecks && !IsCallerInBootClassPath(self);
}
// Returns true if the first non-ClassClass caller up the stack should not be
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 7d9d3426fc..53982ae833 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -267,7 +267,7 @@ Runtime::Runtime()
oat_file_manager_(nullptr),
is_low_memory_mode_(false),
safe_mode_(false),
- do_hidden_api_checks_(false),
+ hidden_api_policy_(hiddenapi::EnforcementPolicy::kNoChecks),
pending_hidden_api_warning_(false),
dedupe_hidden_api_warnings_(true),
always_set_hidden_api_warning_flag_(false),
@@ -1196,9 +1196,14 @@ bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) {
// by default and we only enable them if:
// (a) runtime was started with a flag that enables the checks, or
// (b) Zygote forked a new process that is not exempt (see ZygoteHooks).
- do_hidden_api_checks_ = runtime_options.Exists(Opt::HiddenApiChecks);
- DCHECK(!is_zygote_ || !do_hidden_api_checks_)
- << "Zygote should not be started with hidden API checks";
+ bool do_hidden_api_checks = runtime_options.Exists(Opt::HiddenApiChecks);
+ DCHECK(!is_zygote_ || !do_hidden_api_checks);
+ // TODO pass the actual enforcement policy in, rather than just a single bit.
+ // As is, we're encoding some logic here about which specific policy to use, which would be better
+ // controlled by the framework.
+ hidden_api_policy_ = do_hidden_api_checks
+ ? hiddenapi::EnforcementPolicy::kBlacklistOnly
+ : hiddenapi::EnforcementPolicy::kNoChecks;
no_sig_chain_ = runtime_options.Exists(Opt::NoSigChain);
force_native_bridge_ = runtime_options.Exists(Opt::ForceNativeBridge);
diff --git a/runtime/runtime.h b/runtime/runtime.h
index c7f650ea3f..dba31b2939 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -49,6 +49,10 @@ class AbstractSystemWeakHolder;
class Heap;
} // namespace gc
+namespace hiddenapi {
+enum class EnforcementPolicy;
+} // namespace hiddenapi
+
namespace jit {
class Jit;
class JitOptions;
@@ -520,12 +524,12 @@ class Runtime {
bool IsVerificationEnabled() const;
bool IsVerificationSoftFail() const;
- void SetHiddenApiChecksEnabled(bool value) {
- do_hidden_api_checks_ = value;
+ void SetHiddenApiEnforcementPolicy(hiddenapi::EnforcementPolicy policy) {
+ hidden_api_policy_ = policy;
}
- bool AreHiddenApiChecksEnabled() const {
- return do_hidden_api_checks_;
+ hiddenapi::EnforcementPolicy GetHiddenApiEnforcementPolicy() const {
+ return hidden_api_policy_;
}
void SetPendingHiddenApiWarning(bool value) {
@@ -990,7 +994,7 @@ class Runtime {
bool safe_mode_;
// Whether access checks on hidden API should be performed.
- bool do_hidden_api_checks_;
+ hiddenapi::EnforcementPolicy hidden_api_policy_;
// Whether the application has used an API which is not restricted but we
// should issue a warning about it.
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index 67ea64be74..bf36ccf0fa 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -24,6 +24,7 @@
#include <android-base/stringprintf.h>
#include "entrypoints/quick/quick_entrypoints_enum.h"
+#include "hidden_api.h"
#include "jni_internal.h"
#include "mirror/class.h"
#include "mirror/throwable.h"
@@ -287,17 +288,17 @@ class ScopedHiddenApiExemption {
public:
explicit ScopedHiddenApiExemption(Runtime* runtime)
: runtime_(runtime),
- initially_enabled_(runtime_->AreHiddenApiChecksEnabled()) {
- runtime_->SetHiddenApiChecksEnabled(false);
+ initial_policy_(runtime_->GetHiddenApiEnforcementPolicy()) {
+ runtime_->SetHiddenApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kNoChecks);
}
~ScopedHiddenApiExemption() {
- runtime_->SetHiddenApiChecksEnabled(initially_enabled_);
+ runtime_->SetHiddenApiEnforcementPolicy(initial_policy_);
}
private:
Runtime* runtime_;
- const bool initially_enabled_;
+ const hiddenapi::EnforcementPolicy initial_policy_;
DISALLOW_COPY_AND_ASSIGN(ScopedHiddenApiExemption);
};
diff --git a/test/674-hiddenapi/hiddenapi.cc b/test/674-hiddenapi/hiddenapi.cc
index effa37ade4..04c3fbf03a 100644
--- a/test/674-hiddenapi/hiddenapi.cc
+++ b/test/674-hiddenapi/hiddenapi.cc
@@ -16,6 +16,7 @@
#include "class_linker.h"
#include "dex/art_dex_file_loader.h"
+#include "hidden_api.h"
#include "jni.h"
#include "runtime.h"
#include "scoped_thread_state_change-inl.h"
@@ -27,7 +28,7 @@ namespace Test674HiddenApi {
extern "C" JNIEXPORT void JNICALL Java_Main_init(JNIEnv*, jclass) {
Runtime* runtime = Runtime::Current();
- runtime->SetHiddenApiChecksEnabled(true);
+ runtime->SetHiddenApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kBlacklistOnly);
runtime->SetDedupeHiddenApiWarnings(false);
runtime->AlwaysSetHiddenApiWarningFlag();
}