1 /* 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 #include <metricslogger/metrics_logger.h> 18 19 #include "hidden_api.h" 20 21 #include <nativehelper/scoped_local_ref.h> 22 23 #include "base/dumpable.h" 24 #include "thread-current-inl.h" 25 #include "well_known_classes.h" 26 27 using android::metricslogger::ComplexEventLogger; 28 using android::metricslogger::ACTION_HIDDEN_API_ACCESSED; 29 using android::metricslogger::FIELD_HIDDEN_API_ACCESS_METHOD; 30 using android::metricslogger::FIELD_HIDDEN_API_ACCESS_DENIED; 31 using android::metricslogger::FIELD_HIDDEN_API_SIGNATURE; 32 33 namespace art { 34 namespace hiddenapi { 35 36 // Set to true if we should always print a warning in logcat for all hidden API accesses, not just 37 // dark grey and black. This can be set to true for developer preview / beta builds, but should be 38 // false for public release builds. 39 // Note that when flipping this flag, you must also update the expectations of test 674-hiddenapi 40 // as it affects whether or not we warn for light grey APIs that have been added to the exemptions 41 // list. 42 static constexpr bool kLogAllAccesses = false; 43 44 static inline std::ostream& operator<<(std::ostream& os, AccessMethod value) { 45 switch (value) { 46 case kNone: 47 LOG(FATAL) << "Internal access to hidden API should not be logged"; 48 UNREACHABLE(); 49 case kReflection: 50 os << "reflection"; 51 break; 52 case kJNI: 53 os << "JNI"; 54 break; 55 case kLinking: 56 os << "linking"; 57 break; 58 } 59 return os; 60 } 61 62 static constexpr bool EnumsEqual(EnforcementPolicy policy, HiddenApiAccessFlags::ApiList apiList) { 63 return static_cast<int>(policy) == static_cast<int>(apiList); 64 } 65 66 // GetMemberAction-related static_asserts. 67 static_assert( 68 EnumsEqual(EnforcementPolicy::kDarkGreyAndBlackList, HiddenApiAccessFlags::kDarkGreylist) && 69 EnumsEqual(EnforcementPolicy::kBlacklistOnly, HiddenApiAccessFlags::kBlacklist), 70 "Mismatch between EnforcementPolicy and ApiList enums"); 71 static_assert( 72 EnforcementPolicy::kJustWarn < EnforcementPolicy::kDarkGreyAndBlackList && 73 EnforcementPolicy::kDarkGreyAndBlackList < EnforcementPolicy::kBlacklistOnly, 74 "EnforcementPolicy values ordering not correct"); 75 76 namespace detail { 77 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 } 119 120 bool MemberSignature::IsExempted(const std::vector<std::string>& exemptions) { 121 for (const std::string& exemption : exemptions) { 122 if (DoesPrefixMatch(exemption)) { 123 return true; 124 } 125 } 126 return false; 127 } 128 129 void MemberSignature::Dump(std::ostream& os) const { 130 for (const char* part : GetSignatureParts()) { 131 os << part; 132 } 133 } 134 135 void MemberSignature::WarnAboutAccess(AccessMethod access_method, 136 HiddenApiAccessFlags::ApiList list) { 137 LOG(WARNING) << "Accessing hidden " << (type_ == kField ? "field " : "method ") 138 << Dumpable<MemberSignature>(*this) << " (" << list << ", " << access_method << ")"; 139 } 140 // Convert an AccessMethod enum to a value for logging from the proto enum. 141 // This method may look odd (the enum values are current the same), but it 142 // prevents coupling the internal enum to the proto enum (which should never 143 // be changed) so that we are free to change the internal one if necessary in 144 // future. 145 inline static int32_t GetEnumValueForLog(AccessMethod access_method) { 146 switch (access_method) { 147 case kNone: 148 return android::metricslogger::ACCESS_METHOD_NONE; 149 case kReflection: 150 return android::metricslogger::ACCESS_METHOD_REFLECTION; 151 case kJNI: 152 return android::metricslogger::ACCESS_METHOD_JNI; 153 case kLinking: 154 return android::metricslogger::ACCESS_METHOD_LINKING; 155 default: 156 DCHECK(false); 157 } 158 } 159 160 void MemberSignature::LogAccessToEventLog(AccessMethod access_method, Action action_taken) { 161 if (access_method == kLinking || access_method == kNone) { 162 // Linking warnings come from static analysis/compilation of the bytecode 163 // and can contain false positives (i.e. code that is never run). We choose 164 // not to log these in the event log. 165 // None does not correspond to actual access, so should also be ignored. 166 return; 167 } 168 ComplexEventLogger log_maker(ACTION_HIDDEN_API_ACCESSED); 169 log_maker.AddTaggedData(FIELD_HIDDEN_API_ACCESS_METHOD, GetEnumValueForLog(access_method)); 170 if (action_taken == kDeny) { 171 log_maker.AddTaggedData(FIELD_HIDDEN_API_ACCESS_DENIED, 1); 172 } 173 const std::string& package_name = Runtime::Current()->GetProcessPackageName(); 174 if (!package_name.empty()) { 175 log_maker.SetPackageName(package_name); 176 } 177 std::ostringstream signature_str; 178 Dump(signature_str); 179 log_maker.AddTaggedData(FIELD_HIDDEN_API_SIGNATURE, signature_str.str()); 180 log_maker.Record(); 181 } 182 183 static ALWAYS_INLINE bool CanUpdateMemberAccessFlags(ArtField*) { 184 return true; 185 } 186 187 static ALWAYS_INLINE bool CanUpdateMemberAccessFlags(ArtMethod* method) { 188 return !method->IsIntrinsic(); 189 } 190 191 template<typename T> 192 static ALWAYS_INLINE void MaybeWhitelistMember(Runtime* runtime, T* member) 193 REQUIRES_SHARED(Locks::mutator_lock_) { 194 if (CanUpdateMemberAccessFlags(member) && runtime->ShouldDedupeHiddenApiWarnings()) { 195 member->SetAccessFlags(HiddenApiAccessFlags::EncodeForRuntime( 196 member->GetAccessFlags(), HiddenApiAccessFlags::kWhitelist)); 197 } 198 } 199 200 template<typename T> 201 Action GetMemberActionImpl(T* member, 202 HiddenApiAccessFlags::ApiList api_list, 203 Action action, 204 AccessMethod access_method) { 205 DCHECK_NE(action, kAllow); 206 207 // Get the signature, we need it later. 208 MemberSignature member_signature(member); 209 210 Runtime* runtime = Runtime::Current(); 211 212 // Check for an exemption first. Exempted APIs are treated as white list. 213 // We only do this if we're about to deny, or if the app is debuggable. This is because: 214 // - we only print a warning for light greylist violations for debuggable apps 215 // - for non-debuggable apps, there is no distinction between light grey & whitelisted APIs. 216 // - we want to avoid the overhead of checking for exemptions for light greylisted APIs whenever 217 // possible. 218 const bool shouldWarn = kLogAllAccesses || runtime->IsJavaDebuggable(); 219 if (shouldWarn || action == kDeny) { 220 if (member_signature.IsExempted(runtime->GetHiddenApiExemptions())) { 221 action = kAllow; 222 // Avoid re-examining the exemption list next time. 223 // Note this results in no warning for the member, which seems like what one would expect. 224 // Exemptions effectively adds new members to the whitelist. 225 MaybeWhitelistMember(runtime, member); 226 return kAllow; 227 } 228 229 if (access_method != kNone) { 230 // Print a log message with information about this class member access. 231 // We do this if we're about to block access, or the app is debuggable. 232 member_signature.WarnAboutAccess(access_method, api_list); 233 } 234 } 235 236 if (kIsTargetBuild) { 237 uint32_t eventLogSampleRate = runtime->GetHiddenApiEventLogSampleRate(); 238 // Assert that RAND_MAX is big enough, to ensure sampling below works as expected. 239 static_assert(RAND_MAX >= 0xffff, "RAND_MAX too small"); 240 if (eventLogSampleRate != 0 && 241 (static_cast<uint32_t>(std::rand()) & 0xffff) < eventLogSampleRate) { 242 member_signature.LogAccessToEventLog(access_method, action); 243 } 244 } 245 246 if (action == kDeny) { 247 // Block access 248 return action; 249 } 250 251 // Allow access to this member but print a warning. 252 DCHECK(action == kAllowButWarn || action == kAllowButWarnAndToast); 253 254 if (access_method != kNone) { 255 // Depending on a runtime flag, we might move the member into whitelist and 256 // skip the warning the next time the member is accessed. 257 MaybeWhitelistMember(runtime, member); 258 259 // If this action requires a UI warning, set the appropriate flag. 260 if (shouldWarn && 261 (action == kAllowButWarnAndToast || runtime->ShouldAlwaysSetHiddenApiWarningFlag())) { 262 runtime->SetPendingHiddenApiWarning(true); 263 } 264 } 265 266 return action; 267 } 268 269 // Need to instantiate this. 270 template Action GetMemberActionImpl<ArtField>(ArtField* member, 271 HiddenApiAccessFlags::ApiList api_list, 272 Action action, 273 AccessMethod access_method); 274 template Action GetMemberActionImpl<ArtMethod>(ArtMethod* member, 275 HiddenApiAccessFlags::ApiList api_list, 276 Action action, 277 AccessMethod access_method); 278 } // namespace detail 279 280 template<typename T> 281 void NotifyHiddenApiListener(T* member) { 282 Runtime* runtime = Runtime::Current(); 283 if (!runtime->IsAotCompiler()) { 284 ScopedObjectAccessUnchecked soa(Thread::Current()); 285 286 ScopedLocalRef<jobject> consumer_object(soa.Env(), 287 soa.Env()->GetStaticObjectField( 288 WellKnownClasses::dalvik_system_VMRuntime, 289 WellKnownClasses::dalvik_system_VMRuntime_nonSdkApiUsageConsumer)); 290 // If the consumer is non-null, we call back to it to let it know that we 291 // have encountered an API that's in one of our lists. 292 if (consumer_object != nullptr) { 293 detail::MemberSignature member_signature(member); 294 std::ostringstream member_signature_str; 295 member_signature.Dump(member_signature_str); 296 297 ScopedLocalRef<jobject> signature_str( 298 soa.Env(), 299 soa.Env()->NewStringUTF(member_signature_str.str().c_str())); 300 301 // Call through to Consumer.accept(String memberSignature); 302 soa.Env()->CallVoidMethod(consumer_object.get(), 303 WellKnownClasses::java_util_function_Consumer_accept, 304 signature_str.get()); 305 } 306 } 307 } 308 309 template void NotifyHiddenApiListener<ArtMethod>(ArtMethod* member); 310 template void NotifyHiddenApiListener<ArtField>(ArtField* member); 311 312 } // namespace hiddenapi 313 } // namespace art 314