blob: 321d55d9b7987b9df2ab5da365742357e1adbcc8 [file] [log] [blame]
David Brazdil5a61bb72018-01-19 16:59:46 +00001/*
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
David Brazdil8ce3bfa2018-03-12 18:01:18 +000020#include "art_field-inl.h"
21#include "art_method-inl.h"
David Sehr67bf42e2018-02-26 16:43:04 -080022#include "dex/hidden_api_access_flags.h"
David Brazdil8ce3bfa2018-03-12 18:01:18 +000023#include "mirror/class-inl.h"
David Brazdil5a61bb72018-01-19 16:59:46 +000024#include "reflection.h"
25#include "runtime.h"
26
27namespace art {
28namespace hiddenapi {
29
Mathew Inwood597d7f62018-03-22 11:36:47 +000030// Hidden API enforcement policy
31// This must be kept in sync with ApplicationInfo.ApiEnforcementPolicy in
32// frameworks/base/core/java/android/content/pm/ApplicationInfo.java
33enum class EnforcementPolicy {
34 kNoChecks = 0,
35 kAllLists = 1, // ban anything but whitelist
36 kDarkGreyAndBlackList = 2, // ban dark grey & blacklist
37 kBlacklistOnly = 3, // ban blacklist violations only
38 kMax = kBlacklistOnly,
39};
40
41inline EnforcementPolicy EnforcementPolicyFromInt(int api_policy_int) {
42 DCHECK_GE(api_policy_int, 0);
43 DCHECK_LE(api_policy_int, static_cast<int>(EnforcementPolicy::kMax));
44 return static_cast<EnforcementPolicy>(api_policy_int);
45}
46
David Brazdila02cb112018-01-31 11:36:39 +000047enum Action {
48 kAllow,
49 kAllowButWarn,
David Brazdil92265222018-02-02 11:21:40 +000050 kAllowButWarnAndToast,
David Brazdila02cb112018-01-31 11:36:39 +000051 kDeny
52};
David Brazdil5a61bb72018-01-19 16:59:46 +000053
David Brazdil068d68d2018-02-12 13:04:17 -080054enum AccessMethod {
55 kReflection,
David Brazdil8ce3bfa2018-03-12 18:01:18 +000056 kJNI,
57 kLinking,
David Brazdilfc661292018-03-14 13:57:27 +000058 kOverride,
David Brazdil068d68d2018-02-12 13:04:17 -080059};
60
61inline std::ostream& operator<<(std::ostream& os, AccessMethod value) {
62 switch (value) {
63 case kReflection:
64 os << "reflection";
65 break;
66 case kJNI:
67 os << "JNI";
68 break;
David Brazdil8ce3bfa2018-03-12 18:01:18 +000069 case kLinking:
70 os << "linking";
71 break;
David Brazdilfc661292018-03-14 13:57:27 +000072 case kOverride:
73 os << "override";
74 break;
David Brazdil068d68d2018-02-12 13:04:17 -080075 }
76 return os;
77}
78
Mathew Inwood597d7f62018-03-22 11:36:47 +000079static constexpr bool EnumsEqual(EnforcementPolicy policy, HiddenApiAccessFlags::ApiList apiList) {
80 return static_cast<int>(policy) == static_cast<int>(apiList);
81}
82
David Brazdila02cb112018-01-31 11:36:39 +000083inline Action GetMemberAction(uint32_t access_flags) {
Mathew Inwood597d7f62018-03-22 11:36:47 +000084 EnforcementPolicy policy = Runtime::Current()->GetHiddenApiEnforcementPolicy();
85 if (policy == EnforcementPolicy::kNoChecks) {
86 // Exit early. Nothing to enforce.
87 return kAllow;
88 }
89
90 HiddenApiAccessFlags::ApiList api_list = HiddenApiAccessFlags::DecodeFromRuntime(access_flags);
91 if (api_list == HiddenApiAccessFlags::kWhitelist) {
92 return kAllow;
93 }
94 // The logic below relies on equality of values in the enums EnforcementPolicy and
95 // HiddenApiAccessFlags::ApiList, and their ordering. Assert that this is as expected.
96 static_assert(
97 EnumsEqual(EnforcementPolicy::kAllLists, HiddenApiAccessFlags::kLightGreylist) &&
98 EnumsEqual(EnforcementPolicy::kDarkGreyAndBlackList, HiddenApiAccessFlags::kDarkGreylist) &&
99 EnumsEqual(EnforcementPolicy::kBlacklistOnly, HiddenApiAccessFlags::kBlacklist),
100 "Mismatch between EnforcementPolicy and ApiList enums");
101 static_assert(
102 EnforcementPolicy::kAllLists < EnforcementPolicy::kDarkGreyAndBlackList &&
103 EnforcementPolicy::kDarkGreyAndBlackList < EnforcementPolicy::kBlacklistOnly,
104 "EnforcementPolicy values ordering not correct");
105 if (static_cast<int>(policy) > static_cast<int>(api_list)) {
106 return api_list == HiddenApiAccessFlags::kDarkGreylist
107 ? kAllowButWarnAndToast
108 : kAllowButWarn;
109 } else {
110 return kDeny;
David Brazdil5a61bb72018-01-19 16:59:46 +0000111 }
112}
113
David Brazdilee7d2fd2018-01-20 17:25:23 +0000114// Issue a warning about field access.
David Brazdil068d68d2018-02-12 13:04:17 -0800115inline void WarnAboutMemberAccess(ArtField* field, AccessMethod access_method)
116 REQUIRES_SHARED(Locks::mutator_lock_) {
David Brazdil1077bbc2018-01-31 14:33:08 +0000117 std::string tmp;
118 LOG(WARNING) << "Accessing hidden field "
119 << field->GetDeclaringClass()->GetDescriptor(&tmp) << "->"
David Brazdil068d68d2018-02-12 13:04:17 -0800120 << field->GetName() << ":" << field->GetTypeDescriptor()
121 << " (" << HiddenApiAccessFlags::DecodeFromRuntime(field->GetAccessFlags())
122 << ", " << access_method << ")";
David Brazdilee7d2fd2018-01-20 17:25:23 +0000123}
124
125// Issue a warning about method access.
David Brazdil068d68d2018-02-12 13:04:17 -0800126inline void WarnAboutMemberAccess(ArtMethod* method, AccessMethod access_method)
127 REQUIRES_SHARED(Locks::mutator_lock_) {
David Brazdil1077bbc2018-01-31 14:33:08 +0000128 std::string tmp;
129 LOG(WARNING) << "Accessing hidden method "
130 << method->GetDeclaringClass()->GetDescriptor(&tmp) << "->"
David Brazdil068d68d2018-02-12 13:04:17 -0800131 << method->GetName() << method->GetSignature().ToString()
132 << " (" << HiddenApiAccessFlags::DecodeFromRuntime(method->GetAccessFlags())
133 << ", " << access_method << ")";
David Brazdilee7d2fd2018-01-20 17:25:23 +0000134}
135
David Brazdila02cb112018-01-31 11:36:39 +0000136// Returns true if access to `member` should be denied to the caller of the
137// reflective query. The decision is based on whether the caller is in boot
138// class path or not. Because different users of this function determine this
139// in a different way, `fn_caller_in_boot(self)` is called and should return
140// true if the caller is in boot class path.
David Brazdil8ce3bfa2018-03-12 18:01:18 +0000141// This function might print warnings into the log if the member is hidden.
David Brazdilee7d2fd2018-01-20 17:25:23 +0000142template<typename T>
David Brazdila02cb112018-01-31 11:36:39 +0000143inline bool ShouldBlockAccessToMember(T* member,
144 Thread* self,
David Brazdil068d68d2018-02-12 13:04:17 -0800145 std::function<bool(Thread*)> fn_caller_in_boot,
146 AccessMethod access_method)
David Brazdilee7d2fd2018-01-20 17:25:23 +0000147 REQUIRES_SHARED(Locks::mutator_lock_) {
148 DCHECK(member != nullptr);
David Brazdilee7d2fd2018-01-20 17:25:23 +0000149
David Brazdila02cb112018-01-31 11:36:39 +0000150 Action action = GetMemberAction(member->GetAccessFlags());
151 if (action == kAllow) {
152 // Nothing to do.
153 return false;
154 }
155
156 // Member is hidden. Walk the stack to find the caller.
157 // This can be *very* expensive. Save it for last.
158 if (fn_caller_in_boot(self)) {
159 // Caller in boot class path. Exit.
160 return false;
161 }
162
David Brazdil068d68d2018-02-12 13:04:17 -0800163 // Member is hidden and we are not in the boot class path.
164
165 // Print a log message with information about this class member access.
166 // We do this regardless of whether we block the access or not.
167 WarnAboutMemberAccess(member, access_method);
168
David Brazdil92265222018-02-02 11:21:40 +0000169 if (action == kDeny) {
Mathew Inwood597d7f62018-03-22 11:36:47 +0000170 // Block access
David Brazdil92265222018-02-02 11:21:40 +0000171 return true;
David Brazdila02cb112018-01-31 11:36:39 +0000172 }
David Brazdil068d68d2018-02-12 13:04:17 -0800173
174 // Allow access to this member but print a warning.
175 DCHECK(action == kAllowButWarn || action == kAllowButWarnAndToast);
176
Mathew Inwood597d7f62018-03-22 11:36:47 +0000177 Runtime* runtime = Runtime::Current();
178
David Brazdil068d68d2018-02-12 13:04:17 -0800179 // Depending on a runtime flag, we might move the member into whitelist and
180 // skip the warning the next time the member is accessed.
181 if (runtime->ShouldDedupeHiddenApiWarnings()) {
182 member->SetAccessFlags(HiddenApiAccessFlags::EncodeForRuntime(
183 member->GetAccessFlags(), HiddenApiAccessFlags::kWhitelist));
184 }
185
186 // If this action requires a UI warning, set the appropriate flag.
187 if (action == kAllowButWarnAndToast || runtime->ShouldAlwaysSetHiddenApiWarningFlag()) {
Mathew Inwood597d7f62018-03-22 11:36:47 +0000188 runtime->SetPendingHiddenApiWarning(true);
David Brazdil068d68d2018-02-12 13:04:17 -0800189 }
190
191 return false;
David Brazdilee7d2fd2018-01-20 17:25:23 +0000192}
193
David Brazdil8ce3bfa2018-03-12 18:01:18 +0000194// Returns true if access to `member` should be denied to a caller loaded with
195// `caller_class_loader`.
196// This function might print warnings into the log if the member is hidden.
197template<typename T>
198inline bool ShouldBlockAccessToMember(T* member,
199 ObjPtr<mirror::ClassLoader> caller_class_loader,
200 AccessMethod access_method)
David Brazdilee7d2fd2018-01-20 17:25:23 +0000201 REQUIRES_SHARED(Locks::mutator_lock_) {
David Brazdil8ce3bfa2018-03-12 18:01:18 +0000202 bool caller_in_boot = (caller_class_loader.IsNull());
203 return ShouldBlockAccessToMember(member,
204 /* thread */ nullptr,
205 [caller_in_boot] (Thread*) { return caller_in_boot; },
206 access_method);
David Brazdilee7d2fd2018-01-20 17:25:23 +0000207}
208
David Brazdil5a61bb72018-01-19 16:59:46 +0000209} // namespace hiddenapi
210} // namespace art
211
212#endif // ART_RUNTIME_HIDDEN_API_H_