art/runtime/native/java_lang_Class.cc
static jobject Class_getDeclaredMethodInternal(JNIEnv* env, jobject javaThis,
jstring name, jobjectArray args) {
ScopedFastNativeObjectAccess soa(env);
StackHandleScope<1> hs(soa.Self());
DCHECK_EQ(Runtime::Current()->GetClassLinker()->GetImagePointerSize(), kRuntimePointerSize);
DCHECK(!Runtime::Current()->IsActiveTransaction());
Handle<mirror::Method> result = hs.NewHandle(
mirror::Class::GetDeclaredMethodInternal<kRuntimePointerSize, false>(
soa.Self(),
DecodeClass(soa, javaThis),
soa.Decode<mirror::String>(name),
soa.Decode<mirror::ObjectArray<mirror::Class>>(args),
GetHiddenapiAccessContextFunction(soa.Self())));
if (result == nullptr || ShouldDenyAccessToMember(result->GetArtMethod(), soa.Self())) {
return nullptr;
}
return soa.AddLocalReference<jobject>(result.Get());
}
xref: /art/libdexfile/dex/hidden_api_access_flags.h
16
17 #ifndef ART_LIBDEXFILE_DEX_HIDDEN_API_ACCESS_FLAGS_H_
18 #define ART_LIBDEXFILE_DEX_HIDDEN_API_ACCESS_FLAGS_H_
19
20 #include "base/bit_utils.h"
21 #include "base/macros.h"
22 #include "dex/modifiers.h"
23
24 namespace art {
25
26 /* This class is used for encoding and decoding access flags of class members
27 * from the boot class path. These access flags might contain additional two bits
28 * of information on whether the given class member should be hidden from apps
29 * and under what circumstances.
30 *
31 * The encoding is different inside DexFile, where we are concerned with size,
32 * and at runtime where we want to optimize for speed of access. The class
33 * provides helper functions to decode/encode both of them.
34 *
35 * Encoding in DexFile
36 * ===================
37 *
38 * First bit is encoded as inversion of visibility flags (public/private/protected).
39 * At most one can be set for any given class member. If two or three are set,
40 * this is interpreted as the first bit being set and actual visibility flags
41 * being the complement of the encoded flags.
42 *
43 * Second bit is either encoded as bit 5 for fields and non-native methods, where
44 * it carries no other meaning. If a method is native (bit 8 set), bit 9 is used.
45 *
46 * Bits were selected so that they never increase the length of unsigned LEB-128
47 * encoding of the access flags.
48 *
49 * Encoding at runtime
50 * ===================
51 *
52 * Two bits are set aside in the uint32_t access flags in the intrinsics ordinal
53 * space (thus intrinsics need to be special-cased). These are two consecutive
54 * bits and they are directly used to store the integer value of the ApiList
55 * enum values.
56 *
57 */
58 class HiddenApiAccessFlags {
59 public:
60 enum ApiList {
61 kWhitelist = 0,
62 kLightGreylist,
63 kDarkGreylist,
64 kBlacklist,
65 };
66
67 static ALWAYS_INLINE ApiList DecodeFromDex(uint32_t dex_access_flags) {
68 DexHiddenAccessFlags flags(dex_access_flags);
69 uint32_t int_value = (flags.IsFirstBitSet() ? 1 : 0) + (flags.IsSecondBitSet() ? 2 : 0);
70 return static_cast<ApiList>(int_value);
71 }
72
73 static ALWAYS_INLINE uint32_t RemoveFromDex(uint32_t dex_access_flags) {
74 DexHiddenAccessFlags flags(dex_access_flags);
75 flags.SetFirstBit(false);
76 flags.SetSecondBit(false);
77 return flags.GetEncoding();
78 }
79
80 static ALWAYS_INLINE uint32_t EncodeForDex(uint32_t dex_access_flags, ApiList value) {
81 DexHiddenAccessFlags flags(RemoveFromDex(dex_access_flags));
82 uint32_t int_value = static_cast<uint32_t>(value);
83 flags.SetFirstBit((int_value & 1) != 0);
84 flags.SetSecondBit((int_value & 2) != 0);
85 return flags.GetEncoding();
86 }
87
88 static ALWAYS_INLINE ApiList DecodeFromRuntime(uint32_t runtime_access_flags) {
89 // This is used in the fast path, only DCHECK here.
90 DCHECK_EQ(runtime_access_flags & kAccIntrinsic, 0u);
91 uint32_t int_value = (runtime_access_flags & kAccHiddenApiBits) >> kAccFlagsShift;
92 return static_cast<ApiList>(int_value);
93 }
94
95 static ALWAYS_INLINE uint32_t EncodeForRuntime(uint32_t runtime_access_flags, ApiList value) {
96 CHECK_EQ(runtime_access_flags & kAccIntrinsic, 0u);
97
98 uint32_t hidden_api_flags = static_cast<uint32_t>(value) << kAccFlagsShift;
99 CHECK_EQ(hidden_api_flags & ~kAccHiddenApiBits, 0u);
100
101 runtime_access_flags &= ~kAccHiddenApiBits;
102 return runtime_access_flags | hidden_api_flags;
103 }
104
105 private:
106 static const int kAccFlagsShift = CTZ(kAccHiddenApiBits);
107 static_assert(IsPowerOfTwo((kAccHiddenApiBits >> kAccFlagsShift) + 1),
108 "kAccHiddenApiBits are not continuous");
109
110 struct DexHiddenAccessFlags {
111 explicit DexHiddenAccessFlags(uint32_t access_flags) : access_flags_(access_flags) {}
112
113 ALWAYS_INLINE uint32_t GetSecondFlag() {
114 return ((access_flags_ & kAccNative) != 0) ? kAccDexHiddenBitNative : kAccDexHiddenBit;
115 }
116
117 ALWAYS_INLINE bool IsFirstBitSet() {
118 static_assert(IsPowerOfTwo(0u), "Following statement checks if *at most* one bit is set");
119 return !IsPowerOfTwo(access_flags_ & kAccVisibilityFlags);
120 }
121
122 ALWAYS_INLINE void SetFirstBit(bool value) {
123 if (IsFirstBitSet() != value) {
124 access_flags_ ^= kAccVisibilityFlags;
125 }
126 }
127
128 ALWAYS_INLINE bool IsSecondBitSet() {
129 return (access_flags_ & GetSecondFlag()) != 0;
130 }
131
132 ALWAYS_INLINE void SetSecondBit(bool value) {
133 if (value) {
134 access_flags_ |= GetSecondFlag();
135 } else {
136 access_flags_ &= ~GetSecondFlag();
137 }
138 }
139
140 ALWAYS_INLINE uint32_t GetEncoding() const {
141 return access_flags_;
142 }
143
144 uint32_t access_flags_;
145 };
146 };
147
148 inline std::ostream& operator<<(std::ostream& os, HiddenApiAccessFlags::ApiList value) {
149 switch (value) {
150 case HiddenApiAccessFlags::kWhitelist:
151 os << "whitelist";
152 break;
153 case HiddenApiAccessFlags::kLightGreylist:
154 os << "light greylist";
155 break;
156 case HiddenApiAccessFlags::kDarkGreylist:
157 os << "dark greylist";
158 break;
159 case HiddenApiAccessFlags::kBlacklist:
160 os << "blacklist";
161 break;
162 }
163 return os;
164 }
165
166 } // namespace art
167
168
169 #endif // ART_LIBDEXFILE_DEX_HIDDEN_API_ACCESS_FLAGS_H_
170
art/runtime/hidden_api.h
template<typename T>
inline bool ShouldDenyAccessToMember(T* member,
const std::function<AccessContext()>& fn_get_access_context,
AccessMethod access_method)
REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK(member != nullptr);
// 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::Current()->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();
}
}
}
/art/runtime/hidden_api.cc
template<typename T>
bool ShouldDenyAccessToMemberImpl(T* member, ApiList api_list, AccessMethod access_method) {
DCHECK(member != nullptr);
Runtime* runtime = Runtime::Current();
EnforcementPolicy policy = runtime->GetHiddenApiEnforcementPolicy();
DCHECK(policy != 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.
if (member_signature.IsExempted(runtime->GetHiddenApiExemptions())) {
// Avoid re-examining the exemption list next time.
// Note this results in no warning for the member, which seems like what one would expect.
// Exemptions effectively adds new members to the whitelist.
MaybeUpdateAccessFlags(runtime, member, kAccPublicApi);
return false;
}
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.
if (kLogAllAccesses || deny_access || runtime->IsJavaDebuggable()) {
member_signature.WarnAboutAccess(access_method, api_list, deny_access);
}
// If there is a StrictMode listener, notify it about this violation.
member_signature.NotifyHiddenApiListener(access_method);
// If event log sampling is enabled, report this violation.
if (kIsTargetBuild && !kIsTargetLinux) {
uint32_t eventLogSampleRate = runtime->GetHiddenApiEventLogSampleRate();
// Assert that RAND_MAX is big enough, to ensure sampling below works as expected.
static_assert(RAND_MAX >= 0xffff, "RAND_MAX too small");
if (eventLogSampleRate != 0) {
const uint32_t sampled_value = static_cast<uint32_t>(std::rand()) & 0xffff;
if (sampled_value < eventLogSampleRate) {
member_signature.LogAccessToEventLog(sampled_value, access_method, deny_access);
}
}
}
// If this access was not denied, move the member into whitelist and skip
// the warning the next time the member is accessed.
if (!deny_access) {
MaybeUpdateAccessFlags(runtime, member, kAccPublicApi);
}
}
return deny_access;
}
78 MemberSignature::MemberSignature(ArtField* field) {
79 class_name_ = field->GetDeclaringClass()->GetDescriptor(&tmp_);
80 member_name_ = field->GetName();
81 type_signature_ = field->GetTypeDescriptor();
82 type_ = kField;
83 }
84
85 MemberSignature::MemberSignature(ArtMethod* method) {
86 // If this is a proxy method, print the signature of the interface method.
87 method = method->GetInterfaceMethodIfProxy(
88 Runtime::Current()->GetClassLinker()->GetImagePointerSize());
89
90 class_name_ = method->GetDeclaringClass()->GetDescriptor(&tmp_);
91 member_name_ = method->GetName();
92 type_signature_ = method->GetSignature().ToString();
93 type_ = kMethod;
94 }
95
96 inline std::vector<const char*> MemberSignature::GetSignatureParts() const {
97 if (type_ == kField) {
98 return { class_name_.c_str(), "->", member_name_.c_str(), ":", type_signature_.c_str() };
99 } else {
100 DCHECK_EQ(type_, kMethod);
101 return { class_name_.c_str(), "->", member_name_.c_str(), type_signature_.c_str() };
102 }
103 }
104
105 bool MemberSignature::DoesPrefixMatch(const std::string& prefix) const {
106 size_t pos = 0;
107 for (const char* part : GetSignatureParts()) {
108 size_t count = std::min(prefix.length() - pos, strlen(part));
109 if (prefix.compare(pos, count, part, 0, count) == 0) {
110 pos += count;
111 } else {
112 return false;
113 }
114 }
115 // We have a complete match if all parts match (we exit the loop without
116 // returning) AND we've matched the whole prefix.
117 return pos == prefix.length();
118 }
网友评论