|  | /* | 
|  | * Copyright (C) 2020 The Android Open Source Project | 
|  | * | 
|  | * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | * you may not use this file except in compliance with the License. | 
|  | * You may obtain a copy of the License at | 
|  | * | 
|  | *      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | * | 
|  | * Unless required by applicable law or agreed to in writing, software | 
|  | * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | * See the License for the specific language governing permissions and | 
|  | * limitations under the License. | 
|  | */ | 
|  |  | 
|  | #include "sdk_checker.h" | 
|  |  | 
|  | #include "art_method-inl.h" | 
|  | #include "base/utils.h" | 
|  | #include "dex/art_dex_file_loader.h" | 
|  | #include "mirror/class-inl.h" | 
|  |  | 
|  | namespace art { | 
|  |  | 
|  | SdkChecker::SdkChecker() : enabled_(true) {} | 
|  |  | 
|  | SdkChecker* SdkChecker::Create(const std::string& public_sdk, std::string* error_msg) { | 
|  | std::vector<std::string> dex_file_paths; | 
|  | Split(public_sdk, ':', &dex_file_paths); | 
|  |  | 
|  | std::unique_ptr<SdkChecker> sdk_checker(new SdkChecker()); | 
|  | for (const std::string& path : dex_file_paths) { | 
|  | DexFileLoader dex_file_loader(path); | 
|  | if (!dex_file_loader.Open(/*verify=*/true, | 
|  | /*verify_checksum*/ false, | 
|  | error_msg, | 
|  | &sdk_checker->sdk_dex_files_)) { | 
|  | return nullptr; | 
|  | } | 
|  | } | 
|  | return sdk_checker.release(); | 
|  | } | 
|  |  | 
|  | bool SdkChecker::ShouldDenyAccess(ArtMethod* art_method) const { | 
|  | if (!enabled_) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool found = false; | 
|  | for (const std::unique_ptr<const DexFile>& dex_file : sdk_dex_files_) { | 
|  | const dex::TypeId* declaring_type_id = | 
|  | dex_file->FindTypeId(art_method->GetDeclaringClassDescriptor()); | 
|  | if (declaring_type_id == nullptr) { | 
|  | continue; | 
|  | } | 
|  | const dex::StringId* name_id = dex_file->FindStringId(art_method->GetName()); | 
|  | if (name_id == nullptr) { | 
|  | continue; | 
|  | } | 
|  |  | 
|  | dex::TypeIndex return_type_idx; | 
|  | std::vector<dex::TypeIndex> param_type_idxs; | 
|  | if (!dex_file->CreateTypeList( | 
|  | art_method->GetSignature().ToString(), &return_type_idx, ¶m_type_idxs)) { | 
|  | continue; | 
|  | } | 
|  | const dex::ProtoId* proto_id = dex_file->FindProtoId(return_type_idx, param_type_idxs); | 
|  | if (proto_id == nullptr) { | 
|  | continue; | 
|  | } | 
|  |  | 
|  | const dex::MethodId* method_id = | 
|  | dex_file->FindMethodId(*declaring_type_id, *name_id, *proto_id); | 
|  | if (method_id != nullptr) { | 
|  | found = true; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (!found) { | 
|  | VLOG(verifier) << "Deny for " << art_method->PrettyMethod(true); | 
|  | } | 
|  |  | 
|  | // Deny access if we didn't find the descriptor in the public api dex files. | 
|  | return !found; | 
|  | } | 
|  |  | 
|  | bool SdkChecker::ShouldDenyAccess(ArtField* art_field) const { | 
|  | if (!enabled_) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool found = false; | 
|  | for (const std::unique_ptr<const DexFile>& dex_file : sdk_dex_files_) { | 
|  | std::string declaring_class; | 
|  |  | 
|  | const dex::TypeId* declaring_type_id = | 
|  | dex_file->FindTypeId(art_field->GetDeclaringClass()->GetDescriptor(&declaring_class)); | 
|  | if (declaring_type_id == nullptr) { | 
|  | continue; | 
|  | } | 
|  | const dex::StringId* name_id = dex_file->FindStringId(art_field->GetName()); | 
|  | if (name_id == nullptr) { | 
|  | continue; | 
|  | } | 
|  | const dex::TypeId* type_id = dex_file->FindTypeId(art_field->GetTypeDescriptor()); | 
|  | if (type_id == nullptr) { | 
|  | continue; | 
|  | } | 
|  |  | 
|  | const dex::FieldId* field_id = dex_file->FindFieldId(*declaring_type_id, *name_id, *type_id); | 
|  | if (field_id != nullptr) { | 
|  | found = true; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (!found) { | 
|  | VLOG(verifier) << "Deny for " << ArtField::PrettyField(art_field, true); | 
|  | } | 
|  |  | 
|  | // Deny access if we didn't find the descriptor in the public api dex files. | 
|  | return !found; | 
|  | } | 
|  |  | 
|  | bool SdkChecker::ShouldDenyAccess(const char* descriptor) const { | 
|  | if (!enabled_) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool found = false; | 
|  | for (const std::unique_ptr<const DexFile>& dex_file : sdk_dex_files_) { | 
|  | const dex::TypeId* type_id = dex_file->FindTypeId(descriptor); | 
|  | if (type_id != nullptr) { | 
|  | dex::TypeIndex type_idx = dex_file->GetIndexForTypeId(*type_id); | 
|  | if (dex_file->FindClassDef(type_idx) != nullptr) { | 
|  | found = true; | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if (!found) { | 
|  | VLOG(verifier) << "Deny for " << descriptor; | 
|  | } | 
|  |  | 
|  | // Deny access if we didn't find the descriptor in the public api dex files. | 
|  | return !found; | 
|  | } | 
|  |  | 
|  | }  // namespace art |