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 "idmap2d/Idmap2Service.h" 18 19 #include <sys/stat.h> // umask 20 #include <sys/types.h> // umask 21 #include <unistd.h> 22 23 #include <cerrno> 24 #include <cstring> 25 #include <fstream> 26 #include <memory> 27 #include <ostream> 28 #include <string> 29 30 #include "android-base/macros.h" 31 #include "android-base/stringprintf.h" 32 #include "binder/IPCThreadState.h" 33 #include "idmap2/BinaryStreamVisitor.h" 34 #include "idmap2/FileUtils.h" 35 #include "idmap2/Idmap.h" 36 #include "idmap2/Policies.h" 37 #include "idmap2/SysTrace.h" 38 #include "utils/String8.h" 39 40 using android::IPCThreadState; 41 using android::binder::Status; 42 using android::idmap2::BinaryStreamVisitor; 43 using android::idmap2::Idmap; 44 using android::idmap2::IdmapHeader; 45 using android::idmap2::PolicyBitmask; 46 using android::idmap2::utils::kIdmapCacheDir; 47 using android::idmap2::utils::kIdmapFilePermissionMask; 48 using android::idmap2::utils::UidHasWriteAccessToPath; 49 50 namespace { 51 52 Status ok() { 53 return Status::ok(); 54 } 55 56 Status error(const std::string& msg) { 57 LOG(ERROR) << msg; 58 return Status::fromExceptionCode(Status::EX_NONE, msg.c_str()); 59 } 60 61 PolicyBitmask ConvertAidlArgToPolicyBitmask(int32_t arg) { 62 return static_cast<PolicyBitmask>(arg); 63 } 64 65 } // namespace 66 67 namespace android::os { 68 69 Status Idmap2Service::getIdmapPath(const std::string& overlay_apk_path, 70 int32_t user_id ATTRIBUTE_UNUSED, std::string* _aidl_return) { 71 assert(_aidl_return); 72 SYSTRACE << "Idmap2Service::getIdmapPath " << overlay_apk_path; 73 *_aidl_return = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_apk_path); 74 return ok(); 75 } 76 77 Status Idmap2Service::removeIdmap(const std::string& overlay_apk_path, 78 int32_t user_id ATTRIBUTE_UNUSED, bool* _aidl_return) { 79 assert(_aidl_return); 80 SYSTRACE << "Idmap2Service::removeIdmap " << overlay_apk_path; 81 const uid_t uid = IPCThreadState::self()->getCallingUid(); 82 const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_apk_path); 83 if (!UidHasWriteAccessToPath(uid, idmap_path)) { 84 *_aidl_return = false; 85 return error(base::StringPrintf("failed to unlink %s: calling uid %d lacks write access", 86 idmap_path.c_str(), uid)); 87 } 88 if (unlink(idmap_path.c_str()) != 0) { 89 *_aidl_return = false; 90 return error("failed to unlink " + idmap_path + ": " + strerror(errno)); 91 } 92 *_aidl_return = true; 93 return ok(); 94 } 95 96 Status Idmap2Service::verifyIdmap(const std::string& overlay_apk_path, 97 int32_t fulfilled_policies ATTRIBUTE_UNUSED, 98 bool enforce_overlayable ATTRIBUTE_UNUSED, 99 int32_t user_id ATTRIBUTE_UNUSED, bool* _aidl_return) { 100 SYSTRACE << "Idmap2Service::verifyIdmap " << overlay_apk_path; 101 assert(_aidl_return); 102 const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_apk_path); 103 std::ifstream fin(idmap_path); 104 const std::unique_ptr<const IdmapHeader> header = IdmapHeader::FromBinaryStream(fin); 105 fin.close(); 106 *_aidl_return = header && header->IsUpToDate(); 107 108 // TODO(b/119328308): Check that the set of fulfilled policies of the overlay has not changed 109 110 return ok(); 111 } 112 113 Status Idmap2Service::createIdmap(const std::string& target_apk_path, 114 const std::string& overlay_apk_path, int32_t fulfilled_policies, 115 bool enforce_overlayable, int32_t user_id ATTRIBUTE_UNUSED, 116 std::unique_ptr<std::string>* _aidl_return) { 117 assert(_aidl_return); 118 SYSTRACE << "Idmap2Service::createIdmap " << target_apk_path << " " << overlay_apk_path; 119 _aidl_return->reset(nullptr); 120 121 const PolicyBitmask policy_bitmask = ConvertAidlArgToPolicyBitmask(fulfilled_policies); 122 123 const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_apk_path); 124 const uid_t uid = IPCThreadState::self()->getCallingUid(); 125 if (!UidHasWriteAccessToPath(uid, idmap_path)) { 126 return error(base::StringPrintf("will not write to %s: calling uid %d lacks write accesss", 127 idmap_path.c_str(), uid)); 128 } 129 130 const std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path); 131 if (!target_apk) { 132 return error("failed to load apk " + target_apk_path); 133 } 134 135 const std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path); 136 if (!overlay_apk) { 137 return error("failed to load apk " + overlay_apk_path); 138 } 139 140 const auto idmap = Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, 141 *overlay_apk, policy_bitmask, enforce_overlayable); 142 if (!idmap) { 143 return error(idmap.GetErrorMessage()); 144 } 145 146 umask(kIdmapFilePermissionMask); 147 std::ofstream fout(idmap_path); 148 if (fout.fail()) { 149 return error("failed to open idmap path " + idmap_path); 150 } 151 BinaryStreamVisitor visitor(fout); 152 (*idmap)->accept(&visitor); 153 fout.close(); 154 if (fout.fail()) { 155 return error("failed to write to idmap path " + idmap_path); 156 } 157 158 *_aidl_return = std::make_unique<std::string>(idmap_path); 159 return ok(); 160 } 161 162 } // namespace android::os 163