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 22 #include <cerrno> 23 #include <cstring> 24 #include <filesystem> 25 #include <fstream> 26 #include <limits> 27 #include <memory> 28 #include <ostream> 29 #include <string> 30 #include <utility> 31 #include <vector> 32 33 #include "android-base/macros.h" 34 #include "android-base/stringprintf.h" 35 #include "binder/IPCThreadState.h" 36 #include "idmap2/BinaryStreamVisitor.h" 37 #include "idmap2/FileUtils.h" 38 #include "idmap2/Idmap.h" 39 #include "idmap2/PrettyPrintVisitor.h" 40 #include "idmap2/Result.h" 41 #include "idmap2/SysTrace.h" 42 #include <fcntl.h> 43 44 using android::base::StringPrintf; 45 using android::binder::Status; 46 using android::idmap2::BinaryStreamVisitor; 47 using android::idmap2::FabricatedOverlayContainer; 48 using android::idmap2::Idmap; 49 using android::idmap2::IdmapHeader; 50 using android::idmap2::OverlayResourceContainer; 51 using android::idmap2::PrettyPrintVisitor; 52 using android::idmap2::TargetResourceContainer; 53 using android::idmap2::utils::kIdmapCacheDir; 54 using android::idmap2::utils::kIdmapFilePermissionMask; 55 using android::idmap2::utils::RandomStringForPath; 56 using android::idmap2::utils::UidHasWriteAccessToPath; 57 58 using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask; 59 60 namespace { 61 62 constexpr const char* kFrameworkPath = "/system/framework/framework-res.apk"; 63 ok()64 Status ok() { 65 return Status::ok(); 66 } 67 error(const std::string & msg)68 Status error(const std::string& msg) { 69 LOG(ERROR) << msg; 70 return Status::fromExceptionCode(Status::EX_NONE, msg.c_str()); 71 } 72 ConvertAidlArgToPolicyBitmask(int32_t arg)73 PolicyBitmask ConvertAidlArgToPolicyBitmask(int32_t arg) { 74 return static_cast<PolicyBitmask>(arg); 75 } 76 77 } // namespace 78 79 namespace android::os { 80 getIdmapPath(const std::string & overlay_path,int32_t user_id ATTRIBUTE_UNUSED,std::string * _aidl_return)81 Status Idmap2Service::getIdmapPath(const std::string& overlay_path, 82 int32_t user_id ATTRIBUTE_UNUSED, std::string* _aidl_return) { 83 assert(_aidl_return); 84 SYSTRACE << "Idmap2Service::getIdmapPath " << overlay_path; 85 *_aidl_return = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_path); 86 return ok(); 87 } 88 removeIdmap(const std::string & overlay_path,int32_t user_id ATTRIBUTE_UNUSED,bool * _aidl_return)89 Status Idmap2Service::removeIdmap(const std::string& overlay_path, int32_t user_id ATTRIBUTE_UNUSED, 90 bool* _aidl_return) { 91 assert(_aidl_return); 92 SYSTRACE << "Idmap2Service::removeIdmap " << overlay_path; 93 const uid_t uid = IPCThreadState::self()->getCallingUid(); 94 const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_path); 95 if (!UidHasWriteAccessToPath(uid, idmap_path)) { 96 *_aidl_return = false; 97 return error(base::StringPrintf("failed to unlink %s: calling uid %d lacks write access", 98 idmap_path.c_str(), uid)); 99 } 100 if (unlink(idmap_path.c_str()) != 0) { 101 *_aidl_return = false; 102 return error("failed to unlink " + idmap_path + ": " + strerror(errno)); 103 } 104 *_aidl_return = true; 105 return ok(); 106 } 107 verifyIdmap(const std::string & target_path,const std::string & overlay_path,const std::string & overlay_name,int32_t fulfilled_policies,bool enforce_overlayable,int32_t user_id ATTRIBUTE_UNUSED,bool * _aidl_return)108 Status Idmap2Service::verifyIdmap(const std::string& target_path, const std::string& overlay_path, 109 const std::string& overlay_name, int32_t fulfilled_policies, 110 bool enforce_overlayable, int32_t user_id ATTRIBUTE_UNUSED, 111 bool* _aidl_return) { 112 SYSTRACE << "Idmap2Service::verifyIdmap " << overlay_path; 113 assert(_aidl_return); 114 115 const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_path); 116 std::ifstream fin(idmap_path); 117 const std::unique_ptr<const IdmapHeader> header = IdmapHeader::FromBinaryStream(fin); 118 fin.close(); 119 if (!header) { 120 *_aidl_return = false; 121 LOG(WARNING) << "failed to parse idmap header of '" << idmap_path << "'"; 122 return ok(); 123 } 124 125 const auto target = GetTargetContainer(target_path); 126 if (!target) { 127 *_aidl_return = false; 128 LOG(WARNING) << "failed to load target '" << target_path << "'"; 129 return ok(); 130 } 131 132 const auto overlay = OverlayResourceContainer::FromPath(overlay_path); 133 if (!overlay) { 134 *_aidl_return = false; 135 LOG(WARNING) << "failed to load overlay '" << overlay_path << "'"; 136 return ok(); 137 } 138 139 auto up_to_date = 140 header->IsUpToDate(*GetPointer(*target), **overlay, overlay_name, 141 ConvertAidlArgToPolicyBitmask(fulfilled_policies), enforce_overlayable); 142 143 *_aidl_return = static_cast<bool>(up_to_date); 144 if (!up_to_date) { 145 LOG(WARNING) << "idmap '" << idmap_path 146 << "' not up to date : " << up_to_date.GetErrorMessage(); 147 } 148 return ok(); 149 } 150 createIdmap(const std::string & target_path,const std::string & overlay_path,const std::string & overlay_name,int32_t fulfilled_policies,bool enforce_overlayable,int32_t user_id ATTRIBUTE_UNUSED,std::optional<std::string> * _aidl_return)151 Status Idmap2Service::createIdmap(const std::string& target_path, const std::string& overlay_path, 152 const std::string& overlay_name, int32_t fulfilled_policies, 153 bool enforce_overlayable, int32_t user_id ATTRIBUTE_UNUSED, 154 std::optional<std::string>* _aidl_return) { 155 assert(_aidl_return); 156 SYSTRACE << "Idmap2Service::createIdmap " << target_path << " " << overlay_path; 157 _aidl_return->reset(); 158 159 const PolicyBitmask policy_bitmask = ConvertAidlArgToPolicyBitmask(fulfilled_policies); 160 161 const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_path); 162 const uid_t uid = IPCThreadState::self()->getCallingUid(); 163 if (!UidHasWriteAccessToPath(uid, idmap_path)) { 164 return error(base::StringPrintf("will not write to %s: calling uid %d lacks write accesss", 165 idmap_path.c_str(), uid)); 166 } 167 168 // idmap files are mapped with mmap in libandroidfw. Deleting and recreating the idmap guarantees 169 // that existing memory maps will continue to be valid and unaffected. The file must be deleted 170 // before attempting to create the idmap, so that if idmap creation fails, the overlay will no 171 // longer be usable. 172 unlink(idmap_path.c_str()); 173 174 const auto target = GetTargetContainer(target_path); 175 if (!target) { 176 return error("failed to load target '%s'" + target_path); 177 } 178 179 const auto overlay = OverlayResourceContainer::FromPath(overlay_path); 180 if (!overlay) { 181 return error("failed to load apk overlay '%s'" + overlay_path); 182 } 183 184 const auto idmap = Idmap::FromContainers(*GetPointer(*target), **overlay, overlay_name, 185 policy_bitmask, enforce_overlayable); 186 if (!idmap) { 187 return error(idmap.GetErrorMessage()); 188 } 189 190 umask(kIdmapFilePermissionMask); 191 std::ofstream fout(idmap_path); 192 if (fout.fail()) { 193 return error("failed to open idmap path " + idmap_path); 194 } 195 196 BinaryStreamVisitor visitor(fout); 197 (*idmap)->accept(&visitor); 198 fout.close(); 199 if (fout.fail()) { 200 unlink(idmap_path.c_str()); 201 return error("failed to write to idmap path " + idmap_path); 202 } 203 204 *_aidl_return = idmap_path; 205 return ok(); 206 } 207 GetTargetContainer(const std::string & target_path)208 idmap2::Result<Idmap2Service::TargetResourceContainerPtr> Idmap2Service::GetTargetContainer( 209 const std::string& target_path) { 210 if (target_path == kFrameworkPath) { 211 if (framework_apk_cache_ == nullptr) { 212 // Initialize the framework APK cache. 213 auto target = TargetResourceContainer::FromPath(target_path); 214 if (!target) { 215 return target.GetError(); 216 } 217 framework_apk_cache_ = std::move(*target); 218 } 219 return {framework_apk_cache_.get()}; 220 } 221 222 auto target = TargetResourceContainer::FromPath(target_path); 223 if (!target) { 224 return target.GetError(); 225 } 226 return {std::move(*target)}; 227 } 228 createFabricatedOverlay(const os::FabricatedOverlayInternal & overlay,std::optional<os::FabricatedOverlayInfo> * _aidl_return)229 Status Idmap2Service::createFabricatedOverlay( 230 const os::FabricatedOverlayInternal& overlay, 231 std::optional<os::FabricatedOverlayInfo>* _aidl_return) { 232 idmap2::FabricatedOverlay::Builder builder(overlay.packageName, overlay.overlayName, 233 overlay.targetPackageName); 234 if (!overlay.targetOverlayable.empty()) { 235 builder.SetOverlayable(overlay.targetOverlayable); 236 } 237 238 for (const auto& res : overlay.entries) { 239 if (res.dataType == Res_value::TYPE_STRING) { 240 builder.SetResourceValue(res.resourceName, res.dataType, res.stringData.value(), 241 res.configuration.value_or(std::string())); 242 } else if (res.binaryData.has_value()) { 243 builder.SetResourceValue(res.resourceName, res.binaryData->get(), 244 res.configuration.value_or(std::string())); 245 } else { 246 builder.SetResourceValue(res.resourceName, res.dataType, res.data, 247 res.configuration.value_or(std::string())); 248 } 249 } 250 251 // Generate the file path of the fabricated overlay and ensure it does not collide with an 252 // existing path. Re-registering a fabricated overlay will always result in an updated path. 253 std::string path; 254 std::string file_name; 255 do { 256 constexpr size_t kSuffixLength = 4; 257 const std::string random_suffix = RandomStringForPath(kSuffixLength); 258 file_name = StringPrintf("%s-%s-%s.frro", overlay.packageName.c_str(), 259 overlay.overlayName.c_str(), random_suffix.c_str()); 260 path = StringPrintf("%s/%s", kIdmapCacheDir, file_name.c_str()); 261 262 // Invoking std::filesystem::exists with a file name greater than 255 characters will cause this 263 // process to abort since the name exceeds the maximum file name size. 264 const size_t kMaxFileNameLength = 255; 265 if (file_name.size() > kMaxFileNameLength) { 266 return error( 267 base::StringPrintf("fabricated overlay file name '%s' longer than %zu characters", 268 file_name.c_str(), kMaxFileNameLength)); 269 } 270 } while (std::filesystem::exists(path)); 271 builder.setFrroPath(path); 272 273 const uid_t uid = IPCThreadState::self()->getCallingUid(); 274 if (!UidHasWriteAccessToPath(uid, path)) { 275 return error(base::StringPrintf("will not write to %s: calling uid %d lacks write access", 276 path.c_str(), uid)); 277 } 278 279 const auto frro = builder.Build(); 280 if (!frro) { 281 return error(StringPrintf("failed to serialize '%s:%s': %s", overlay.packageName.c_str(), 282 overlay.overlayName.c_str(), frro.GetErrorMessage().c_str())); 283 } 284 // Persist the fabricated overlay. 285 umask(kIdmapFilePermissionMask); 286 std::ofstream fout(path); 287 if (fout.fail()) { 288 return error("failed to open frro path " + path); 289 } 290 auto result = frro->ToBinaryStream(fout); 291 if (!result) { 292 unlink(path.c_str()); 293 return error("failed to write to frro path " + path + ": " + result.GetErrorMessage()); 294 } 295 if (fout.fail()) { 296 unlink(path.c_str()); 297 return error("failed to write to frro path " + path); 298 } 299 300 os::FabricatedOverlayInfo out_info; 301 out_info.packageName = overlay.packageName; 302 out_info.overlayName = overlay.overlayName; 303 out_info.targetPackageName = overlay.targetPackageName; 304 out_info.targetOverlayable = overlay.targetOverlayable; 305 out_info.path = path; 306 *_aidl_return = out_info; 307 return ok(); 308 } 309 acquireFabricatedOverlayIterator(int32_t * _aidl_return)310 Status Idmap2Service::acquireFabricatedOverlayIterator(int32_t* _aidl_return) { 311 std::lock_guard l(frro_iter_mutex_); 312 if (frro_iter_.has_value()) { 313 LOG(WARNING) << "active ffro iterator was not previously released"; 314 } 315 frro_iter_ = std::filesystem::directory_iterator(kIdmapCacheDir); 316 if (frro_iter_id_ == std::numeric_limits<int32_t>::max()) { 317 frro_iter_id_ = 0; 318 } else { 319 ++frro_iter_id_; 320 } 321 *_aidl_return = frro_iter_id_; 322 return ok(); 323 } 324 releaseFabricatedOverlayIterator(int32_t iteratorId)325 Status Idmap2Service::releaseFabricatedOverlayIterator(int32_t iteratorId) { 326 std::lock_guard l(frro_iter_mutex_); 327 if (!frro_iter_.has_value()) { 328 LOG(WARNING) << "no active ffro iterator to release"; 329 } else if (frro_iter_id_ != iteratorId) { 330 LOG(WARNING) << "incorrect iterator id in a call to release"; 331 } else { 332 frro_iter_.reset(); 333 } 334 return ok(); 335 } 336 nextFabricatedOverlayInfos(int32_t iteratorId,std::vector<os::FabricatedOverlayInfo> * _aidl_return)337 Status Idmap2Service::nextFabricatedOverlayInfos(int32_t iteratorId, 338 std::vector<os::FabricatedOverlayInfo>* _aidl_return) { 339 std::lock_guard l(frro_iter_mutex_); 340 341 constexpr size_t kMaxEntryCount = 100; 342 if (!frro_iter_.has_value()) { 343 return error("no active frro iterator"); 344 } else if (frro_iter_id_ != iteratorId) { 345 return error("incorrect iterator id in a call to next"); 346 } 347 348 size_t count = 0; 349 auto& entry_iter = *frro_iter_; 350 auto entry_iter_end = end(*frro_iter_); 351 for (; entry_iter != entry_iter_end && count < kMaxEntryCount; ++entry_iter) { 352 auto& entry = *entry_iter; 353 if (!entry.is_regular_file() || !android::IsFabricatedOverlay(entry.path().native())) { 354 continue; 355 } 356 357 const auto overlay = FabricatedOverlayContainer::FromPath(entry.path().native()); 358 if (!overlay) { 359 LOG(WARNING) << "Failed to open '" << entry.path() << "': " << overlay.GetErrorMessage(); 360 continue; 361 } 362 363 auto info = (*overlay)->GetManifestInfo(); 364 os::FabricatedOverlayInfo out_info; 365 out_info.packageName = std::move(info.package_name); 366 out_info.overlayName = std::move(info.name); 367 out_info.targetPackageName = std::move(info.target_package); 368 out_info.targetOverlayable = std::move(info.target_name); 369 out_info.path = entry.path(); 370 _aidl_return->emplace_back(std::move(out_info)); 371 count++; 372 } 373 return ok(); 374 } 375 deleteFabricatedOverlay(const std::string & overlay_path,bool * _aidl_return)376 binder::Status Idmap2Service::deleteFabricatedOverlay(const std::string& overlay_path, 377 bool* _aidl_return) { 378 SYSTRACE << "Idmap2Service::deleteFabricatedOverlay " << overlay_path; 379 const uid_t uid = IPCThreadState::self()->getCallingUid(); 380 381 if (!UidHasWriteAccessToPath(uid, overlay_path)) { 382 *_aidl_return = false; 383 return error(base::StringPrintf("failed to unlink %s: calling uid %d lacks write access", 384 overlay_path.c_str(), uid)); 385 } 386 387 const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_path); 388 if (!UidHasWriteAccessToPath(uid, idmap_path)) { 389 *_aidl_return = false; 390 return error(base::StringPrintf("failed to unlink %s: calling uid %d lacks write access", 391 idmap_path.c_str(), uid)); 392 } 393 394 if (unlink(overlay_path.c_str()) != 0) { 395 *_aidl_return = false; 396 return error("failed to unlink " + overlay_path + ": " + strerror(errno)); 397 } 398 399 if (unlink(idmap_path.c_str()) != 0) { 400 *_aidl_return = false; 401 return error("failed to unlink " + idmap_path + ": " + strerror(errno)); 402 } 403 404 *_aidl_return = true; 405 return ok(); 406 } 407 dumpIdmap(const std::string & overlay_path,std::string * _aidl_return)408 binder::Status Idmap2Service::dumpIdmap(const std::string& overlay_path, 409 std::string* _aidl_return) { 410 assert(_aidl_return); 411 412 const auto idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_path); 413 std::ifstream fin(idmap_path); 414 const auto idmap = Idmap::FromBinaryStream(fin); 415 fin.close(); 416 if (!idmap) { 417 return error(idmap.GetErrorMessage()); 418 } 419 420 std::stringstream stream; 421 PrettyPrintVisitor visitor(stream); 422 (*idmap)->accept(&visitor); 423 *_aidl_return = stream.str(); 424 425 return ok(); 426 } 427 428 } // namespace android::os 429