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 "hidden_api.h" 18 19 #include <nativehelper/scoped_local_ref.h> 20 21 #include "art_field-inl.h" 22 #include "art_method-inl.h" 23 #include "base/dumpable.h" 24 #include "base/file_utils.h" 25 #include "class_root.h" 26 #include "dex/class_accessor-inl.h" 27 #include "dex/dex_file_loader.h" 28 #include "mirror/class_ext.h" 29 #include "oat_file.h" 30 #include "scoped_thread_state_change.h" 31 #include "thread-inl.h" 32 #include "well_known_classes.h" 33 34 namespace art { 35 namespace hiddenapi { 36 37 // Set to true if we should always print a warning in logcat for all hidden API accesses, not just 38 // dark grey and black. This can be set to true for developer preview / beta builds, but should be 39 // false for public release builds. 40 // Note that when flipping this flag, you must also update the expectations of test 674-hiddenapi 41 // as it affects whether or not we warn for light grey APIs that have been added to the exemptions 42 // list. 43 static constexpr bool kLogAllAccesses = false; 44 45 static inline std::ostream& operator<<(std::ostream& os, AccessMethod value) { 46 switch (value) { 47 case AccessMethod::kNone: 48 LOG(FATAL) << "Internal access to hidden API should not be logged"; 49 UNREACHABLE(); 50 case AccessMethod::kReflection: 51 os << "reflection"; 52 break; 53 case AccessMethod::kJNI: 54 os << "JNI"; 55 break; 56 case AccessMethod::kLinking: 57 os << "linking"; 58 break; 59 } 60 return os; 61 } 62 63 static inline std::ostream& operator<<(std::ostream& os, const AccessContext& value) 64 REQUIRES_SHARED(Locks::mutator_lock_) { 65 if (!value.GetClass().IsNull()) { 66 std::string tmp; 67 os << value.GetClass()->GetDescriptor(&tmp); 68 } else if (value.GetDexFile() != nullptr) { 69 os << value.GetDexFile()->GetLocation(); 70 } else { 71 os << "<unknown_caller>"; 72 } 73 return os; 74 } 75 76 static Domain DetermineDomainFromLocation(const std::string& dex_location, 77 ObjPtr<mirror::ClassLoader> class_loader) { 78 // If running with APEX, check `path` against known APEX locations. 79 // These checks will be skipped on target buildbots where ANDROID_RUNTIME_ROOT 80 // is set to "/system". 81 if (RuntimeModuleRootDistinctFromAndroidRoot()) { 82 if (LocationIsOnRuntimeModule(dex_location.c_str()) || 83 LocationIsOnConscryptModule(dex_location.c_str())) { 84 return Domain::kCorePlatform; 85 } 86 87 if (LocationIsOnApex(dex_location.c_str())) { 88 return Domain::kPlatform; 89 } 90 } 91 92 if (LocationIsOnSystemFramework(dex_location.c_str())) { 93 return Domain::kPlatform; 94 } 95 96 if (class_loader.IsNull()) { 97 LOG(WARNING) << "DexFile " << dex_location 98 << " is in boot class path but is not in a known location"; 99 return Domain::kPlatform; 100 } 101 102 return Domain::kApplication; 103 } 104 105 void InitializeDexFileDomain(const DexFile& dex_file, ObjPtr<mirror::ClassLoader> class_loader) { 106 Domain dex_domain = DetermineDomainFromLocation(dex_file.GetLocation(), class_loader); 107 108 // Assign the domain unless a more permissive domain has already been assigned. 109 // This may happen when DexFile is initialized as trusted. 110 if (IsDomainMoreTrustedThan(dex_domain, dex_file.GetHiddenapiDomain())) { 111 dex_file.SetHiddenapiDomain(dex_domain); 112 } 113 } 114 115 namespace detail { 116 117 // Do not change the values of items in this enum, as they are written to the 118 // event log for offline analysis. Any changes will interfere with that analysis. 119 enum AccessContextFlags { 120 // Accessed member is a field if this bit is set, else a method 121 kMemberIsField = 1 << 0, 122 // Indicates if access was denied to the member, instead of just printing a warning. 123 kAccessDenied = 1 << 1, 124 }; 125 126 MemberSignature::MemberSignature(ArtField* field) { 127 class_name_ = field->GetDeclaringClass()->GetDescriptor(&tmp_); 128 member_name_ = field->GetName(); 129 type_signature_ = field->GetTypeDescriptor(); 130 type_ = kField; 131 } 132 133 MemberSignature::MemberSignature(ArtMethod* method) { 134 DCHECK(method == method->GetInterfaceMethodIfProxy(kRuntimePointerSize)) 135 << "Caller should have replaced proxy method with interface method"; 136 class_name_ = method->GetDeclaringClass()->GetDescriptor(&tmp_); 137 member_name_ = method->GetName(); 138 type_signature_ = method->GetSignature().ToString(); 139 type_ = kMethod; 140 } 141 142 MemberSignature::MemberSignature(const ClassAccessor::Field& field) { 143 const DexFile& dex_file = field.GetDexFile(); 144 const dex::FieldId& field_id = dex_file.GetFieldId(field.GetIndex()); 145 class_name_ = dex_file.GetFieldDeclaringClassDescriptor(field_id); 146 member_name_ = dex_file.GetFieldName(field_id); 147 type_signature_ = dex_file.GetFieldTypeDescriptor(field_id); 148 type_ = kField; 149 } 150 151 MemberSignature::MemberSignature(const ClassAccessor::Method& method) { 152 const DexFile& dex_file = method.GetDexFile(); 153 const dex::MethodId& method_id = dex_file.GetMethodId(method.GetIndex()); 154 class_name_ = dex_file.GetMethodDeclaringClassDescriptor(method_id); 155 member_name_ = dex_file.GetMethodName(method_id); 156 type_signature_ = dex_file.GetMethodSignature(method_id).ToString(); 157 type_ = kMethod; 158 } 159 160 inline std::vector<const char*> MemberSignature::GetSignatureParts() const { 161 if (type_ == kField) { 162 return { class_name_.c_str(), "->", member_name_.c_str(), ":", type_signature_.c_str() }; 163 } else { 164 DCHECK_EQ(type_, kMethod); 165 return { class_name_.c_str(), "->", member_name_.c_str(), type_signature_.c_str() }; 166 } 167 } 168 169 bool MemberSignature::DoesPrefixMatch(const std::string& prefix) const { 170 size_t pos = 0; 171 for (const char* part : GetSignatureParts()) { 172 size_t count = std::min(prefix.length() - pos, strlen(part)); 173 if (prefix.compare(pos, count, part, 0, count) == 0) { 174 pos += count; 175 } else { 176 return false; 177 } 178 } 179 // We have a complete match if all parts match (we exit the loop without 180 // returning) AND we've matched the whole prefix. 181 return pos == prefix.length(); 182 } 183 184 bool MemberSignature::IsExempted(const std::vector<std::string>& exemptions) { 185 for (const std::string& exemption : exemptions) { 186 if (DoesPrefixMatch(exemption)) { 187 return true; 188 } 189 } 190 return false; 191 } 192 193 void MemberSignature::Dump(std::ostream& os) const { 194 for (const char* part : GetSignatureParts()) { 195 os << part; 196 } 197 } 198 199 void MemberSignature::WarnAboutAccess(AccessMethod access_method, 200 hiddenapi::ApiList list, 201 bool access_denied) { 202 LOG(WARNING) << "Accessing hidden " << (type_ == kField ? "field " : "method ") 203 << Dumpable<MemberSignature>(*this) << " (" << list << ", " << access_method 204 << (access_denied ? ", denied)" : ", allowed)"); 205 } 206 207 bool MemberSignature::Equals(const MemberSignature& other) { 208 return type_ == other.type_ && 209 class_name_ == other.class_name_ && 210 member_name_ == other.member_name_ && 211 type_signature_ == other.type_signature_; 212 } 213 214 bool MemberSignature::MemberNameAndTypeMatch(const MemberSignature& other) { 215 return member_name_ == other.member_name_ && type_signature_ == other.type_signature_; 216 } 217 218 void MemberSignature::LogAccessToEventLog(uint32_t sampled_value, 219 AccessMethod access_method, 220 bool access_denied) { 221 #ifdef ART_TARGET_ANDROID 222 if (access_method == AccessMethod::kLinking || access_method == AccessMethod::kNone) { 223 // Linking warnings come from static analysis/compilation of the bytecode 224 // and can contain false positives (i.e. code that is never run). We choose 225 // not to log these in the event log. 226 // None does not correspond to actual access, so should also be ignored. 227 return; 228 } 229 Runtime* runtime = Runtime::Current(); 230 if (runtime->IsAotCompiler()) { 231 return; 232 } 233 JNIEnvExt* env = Thread::Current()->GetJniEnv(); 234 const std::string& package_name = Runtime::Current()->GetProcessPackageName(); 235 ScopedLocalRef<jstring> package_str(env, env->NewStringUTF(package_name.c_str())); 236 if (env->ExceptionCheck()) { 237 env->ExceptionClear(); 238 LOG(ERROR) << "Unable to allocate string for package name which called hidden api"; 239 } 240 std::ostringstream signature_str; 241 Dump(signature_str); 242 ScopedLocalRef<jstring> signature_jstr(env, 243 env->NewStringUTF(signature_str.str().c_str())); 244 if (env->ExceptionCheck()) { 245 env->ExceptionClear(); 246 LOG(ERROR) << "Unable to allocate string for hidden api method signature"; 247 } 248 env->CallStaticVoidMethod(WellKnownClasses::dalvik_system_VMRuntime, 249 WellKnownClasses::dalvik_system_VMRuntime_hiddenApiUsed, 250 sampled_value, 251 package_str.get(), 252 signature_jstr.get(), 253 static_cast<jint>(access_method), 254 access_denied); 255 if (env->ExceptionCheck()) { 256 env->ExceptionClear(); 257 LOG(ERROR) << "Unable to report hidden api usage"; 258 } 259 #else 260 UNUSED(sampled_value); 261 UNUSED(access_method); 262 UNUSED(access_denied); 263 #endif 264 } 265 266 void MemberSignature::NotifyHiddenApiListener(AccessMethod access_method) { 267 if (access_method != AccessMethod::kReflection && access_method != AccessMethod::kJNI) { 268 // We can only up-call into Java during reflection and JNI down-calls. 269 return; 270 } 271 272 Runtime* runtime = Runtime::Current(); 273 if (!runtime->IsAotCompiler()) { 274 ScopedObjectAccessUnchecked soa(Thread::Current()); 275 276 ScopedLocalRef<jobject> consumer_object(soa.Env(), 277 soa.Env()->GetStaticObjectField( 278 WellKnownClasses::dalvik_system_VMRuntime, 279 WellKnownClasses::dalvik_system_VMRuntime_nonSdkApiUsageConsumer)); 280 // If the consumer is non-null, we call back to it to let it know that we 281 // have encountered an API that's in one of our lists. 282 if (consumer_object != nullptr) { 283 std::ostringstream member_signature_str; 284 Dump(member_signature_str); 285 286 ScopedLocalRef<jobject> signature_str( 287 soa.Env(), 288 soa.Env()->NewStringUTF(member_signature_str.str().c_str())); 289 290 // Call through to Consumer.accept(String memberSignature); 291 soa.Env()->CallVoidMethod(consumer_object.get(), 292 WellKnownClasses::java_util_function_Consumer_accept, 293 signature_str.get()); 294 } 295 } 296 } 297 298 static ALWAYS_INLINE bool CanUpdateRuntimeFlags(ArtField*) { 299 return true; 300 } 301 302 static ALWAYS_INLINE bool CanUpdateRuntimeFlags(ArtMethod* method) { 303 return !method->IsIntrinsic(); 304 } 305 306 template<typename T> 307 static ALWAYS_INLINE void MaybeUpdateAccessFlags(Runtime* runtime, T* member, uint32_t flag) 308 REQUIRES_SHARED(Locks::mutator_lock_) { 309 // Update the access flags unless: 310 // (a) `member` is an intrinsic 311 // (b) this is AOT compiler, as we do not want the updated access flags in the boot/app image 312 // (c) deduping warnings has been explicitly switched off. 313 if (CanUpdateRuntimeFlags(member) && 314 !runtime->IsAotCompiler() && 315 runtime->ShouldDedupeHiddenApiWarnings()) { 316 member->SetAccessFlags(member->GetAccessFlags() | flag); 317 } 318 } 319 320 static ALWAYS_INLINE uint32_t GetMemberDexIndex(ArtField* field) { 321 return field->GetDexFieldIndex(); 322 } 323 324 static ALWAYS_INLINE uint32_t GetMemberDexIndex(ArtMethod* method) 325 REQUIRES_SHARED(Locks::mutator_lock_) { 326 // Use the non-obsolete method to avoid DexFile mismatch between 327 // the method index and the declaring class. 328 return method->GetNonObsoleteMethod()->GetDexMethodIndex(); 329 } 330 331 static void VisitMembers(const DexFile& dex_file, 332 const dex::ClassDef& class_def, 333 const std::function<void(const ClassAccessor::Field&)>& fn_visit) { 334 ClassAccessor accessor(dex_file, class_def, /* parse_hiddenapi_class_data= */ true); 335 accessor.VisitFields(fn_visit, fn_visit); 336 } 337 338 static void VisitMembers(const DexFile& dex_file, 339 const dex::ClassDef& class_def, 340 const std::function<void(const ClassAccessor::Method&)>& fn_visit) { 341 ClassAccessor accessor(dex_file, class_def, /* parse_hiddenapi_class_data= */ true); 342 accessor.VisitMethods(fn_visit, fn_visit); 343 } 344 345 template<typename T> 346 uint32_t GetDexFlags(T* member) REQUIRES_SHARED(Locks::mutator_lock_) { 347 static_assert(std::is_same<T, ArtField>::value || std::is_same<T, ArtMethod>::value); 348 constexpr bool kMemberIsField = std::is_same<T, ArtField>::value; 349 using AccessorType = typename std::conditional<std::is_same<T, ArtField>::value, 350 ClassAccessor::Field, ClassAccessor::Method>::type; 351 352 ObjPtr<mirror::Class> declaring_class = member->GetDeclaringClass(); 353 DCHECK(!declaring_class.IsNull()) << "Attempting to access a runtime method"; 354 355 ApiList flags; 356 DCHECK(!flags.IsValid()); 357 358 // Check if the declaring class has ClassExt allocated. If it does, check if 359 // the pre-JVMTI redefine dex file has been set to determine if the declaring 360 // class has been JVMTI-redefined. 361 ObjPtr<mirror::ClassExt> ext(declaring_class->GetExtData()); 362 const DexFile* original_dex = ext.IsNull() ? nullptr : ext->GetPreRedefineDexFile(); 363 if (LIKELY(original_dex == nullptr)) { 364 // Class is not redefined. Find the class def, iterate over its members and 365 // find the entry corresponding to this `member`. 366 const dex::ClassDef* class_def = declaring_class->GetClassDef(); 367 if (class_def == nullptr) { 368 // ClassDef is not set for proxy classes. Only their fields can ever be inspected. 369 DCHECK(declaring_class->IsProxyClass()) 370 << "Only proxy classes are expected not to have a class def"; 371 DCHECK(kMemberIsField) 372 << "Interface methods should be inspected instead of proxy class methods"; 373 flags = ApiList::Greylist(); 374 } else { 375 uint32_t member_index = GetMemberDexIndex(member); 376 auto fn_visit = [&](const AccessorType& dex_member) { 377 if (dex_member.GetIndex() == member_index) { 378 flags = ApiList(dex_member.GetHiddenapiFlags()); 379 } 380 }; 381 VisitMembers(declaring_class->GetDexFile(), *class_def, fn_visit); 382 } 383 } else { 384 // Class was redefined using JVMTI. We have a pointer to the original dex file 385 // and the class def index of this class in that dex file, but the field/method 386 // indices are lost. Iterate over all members of the class def and find the one 387 // corresponding to this `member` by name and type string comparison. 388 // This is obviously very slow, but it is only used when non-exempt code tries 389 // to access a hidden member of a JVMTI-redefined class. 390 uint16_t class_def_idx = ext->GetPreRedefineClassDefIndex(); 391 DCHECK_NE(class_def_idx, DexFile::kDexNoIndex16); 392 const dex::ClassDef& original_class_def = original_dex->GetClassDef(class_def_idx); 393 MemberSignature member_signature(member); 394 auto fn_visit = [&](const AccessorType& dex_member) { 395 MemberSignature cur_signature(dex_member); 396 if (member_signature.MemberNameAndTypeMatch(cur_signature)) { 397 DCHECK(member_signature.Equals(cur_signature)); 398 flags = ApiList(dex_member.GetHiddenapiFlags()); 399 } 400 }; 401 VisitMembers(*original_dex, original_class_def, fn_visit); 402 } 403 404 CHECK(flags.IsValid()) << "Could not find hiddenapi flags for " 405 << Dumpable<MemberSignature>(MemberSignature(member)); 406 return flags.GetDexFlags(); 407 } 408 409 template<typename T> 410 bool HandleCorePlatformApiViolation(T* member, 411 const AccessContext& caller_context, 412 AccessMethod access_method, 413 EnforcementPolicy policy) { 414 DCHECK(policy != EnforcementPolicy::kDisabled) 415 << "Should never enter this function when access checks are completely disabled"; 416 417 if (access_method != AccessMethod::kNone) { 418 LOG(WARNING) << "Core platform API violation: " 419 << Dumpable<MemberSignature>(MemberSignature(member)) 420 << " from " << caller_context << " using " << access_method; 421 422 // If policy is set to just warn, add kAccCorePlatformApi to access flags of 423 // `member` to avoid reporting the violation again next time. 424 if (policy == EnforcementPolicy::kJustWarn) { 425 MaybeUpdateAccessFlags(Runtime::Current(), member, kAccCorePlatformApi); 426 } 427 } 428 429 // Deny access if enforcement is enabled. 430 return policy == EnforcementPolicy::kEnabled; 431 } 432 433 template<typename T> 434 bool ShouldDenyAccessToMemberImpl(T* member, ApiList api_list, AccessMethod access_method) { 435 DCHECK(member != nullptr); 436 Runtime* runtime = Runtime::Current(); 437 438 EnforcementPolicy policy = runtime->GetHiddenApiEnforcementPolicy(); 439 DCHECK(policy != EnforcementPolicy::kDisabled) 440 << "Should never enter this function when access checks are completely disabled"; 441 442 const bool deny_access = 443 (policy == EnforcementPolicy::kEnabled) && 444 IsSdkVersionSetAndMoreThan(runtime->GetTargetSdkVersion(), 445 api_list.GetMaxAllowedSdkVersion()); 446 447 MemberSignature member_signature(member); 448 449 // Check for an exemption first. Exempted APIs are treated as white list. 450 if (member_signature.IsExempted(runtime->GetHiddenApiExemptions())) { 451 // Avoid re-examining the exemption list next time. 452 // Note this results in no warning for the member, which seems like what one would expect. 453 // Exemptions effectively adds new members to the whitelist. 454 MaybeUpdateAccessFlags(runtime, member, kAccPublicApi); 455 return false; 456 } 457 458 if (access_method != AccessMethod::kNone) { 459 // Print a log message with information about this class member access. 460 // We do this if we're about to deny access, or the app is debuggable. 461 if (kLogAllAccesses || deny_access || runtime->IsJavaDebuggable()) { 462 member_signature.WarnAboutAccess(access_method, api_list, deny_access); 463 } 464 465 // If there is a StrictMode listener, notify it about this violation. 466 member_signature.NotifyHiddenApiListener(access_method); 467 468 // If event log sampling is enabled, report this violation. 469 if (kIsTargetBuild && !kIsTargetLinux) { 470 uint32_t eventLogSampleRate = runtime->GetHiddenApiEventLogSampleRate(); 471 // Assert that RAND_MAX is big enough, to ensure sampling below works as expected. 472 static_assert(RAND_MAX >= 0xffff, "RAND_MAX too small"); 473 if (eventLogSampleRate != 0) { 474 const uint32_t sampled_value = static_cast<uint32_t>(std::rand()) & 0xffff; 475 if (sampled_value < eventLogSampleRate) { 476 member_signature.LogAccessToEventLog(sampled_value, access_method, deny_access); 477 } 478 } 479 } 480 481 // If this access was not denied, move the member into whitelist and skip 482 // the warning the next time the member is accessed. 483 if (!deny_access) { 484 MaybeUpdateAccessFlags(runtime, member, kAccPublicApi); 485 } 486 } 487 488 return deny_access; 489 } 490 491 // Need to instantiate these. 492 template uint32_t GetDexFlags<ArtField>(ArtField* member); 493 template uint32_t GetDexFlags<ArtMethod>(ArtMethod* member); 494 template bool HandleCorePlatformApiViolation(ArtField* member, 495 const AccessContext& caller_context, 496 AccessMethod access_method, 497 EnforcementPolicy policy); 498 template bool HandleCorePlatformApiViolation(ArtMethod* member, 499 const AccessContext& caller_context, 500 AccessMethod access_method, 501 EnforcementPolicy policy); 502 template bool ShouldDenyAccessToMemberImpl<ArtField>(ArtField* member, 503 ApiList api_list, 504 AccessMethod access_method); 505 template bool ShouldDenyAccessToMemberImpl<ArtMethod>(ArtMethod* member, 506 ApiList api_list, 507 AccessMethod access_method); 508 } // namespace detail 509 510 } // namespace hiddenapi 511 } // namespace art 512