1/* 2 * Copyright (C) 2008 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 <dirent.h> 18#include <errno.h> 19#include <fcntl.h> 20#include <fts.h> 21#include <mntent.h> 22#include <stdio.h> 23#include <stdlib.h> 24#include <string.h> 25#include <sys/ioctl.h> 26#include <sys/mount.h> 27#include <sys/stat.h> 28#include <sys/types.h> 29#include <sys/wait.h> 30#include <unistd.h> 31 32#include <linux/kdev_t.h> 33 34#define LOG_TAG "Vold" 35 36#include <openssl/md5.h> 37 38#include <android-base/logging.h> 39#include <android-base/stringprintf.h> 40#include <cutils/fs.h> 41#include <cutils/log.h> 42 43#include <selinux/android.h> 44 45#include <sysutils/NetlinkEvent.h> 46 47#include <private/android_filesystem_config.h> 48 49#include "Benchmark.h" 50#include "EmulatedVolume.h" 51#include "VolumeManager.h" 52#include "NetlinkManager.h" 53#include "ResponseCode.h" 54#include "Loop.h" 55#include "fs/Ext4.h" 56#include "fs/Vfat.h" 57#include "Utils.h" 58#include "Devmapper.h" 59#include "Process.h" 60#include "Asec.h" 61#include "VoldUtil.h" 62#include "cryptfs.h" 63 64#define MASS_STORAGE_FILE_PATH "/sys/class/android_usb/android0/f_mass_storage/lun/file" 65 66#define ROUND_UP_POWER_OF_2(number, po2) (((!!(number & ((1U << po2) - 1))) << po2)\ 67 + (number & (~((1U << po2) - 1)))) 68 69using android::base::StringPrintf; 70 71/* 72 * Path to external storage where *only* root can access ASEC image files 73 */ 74const char *VolumeManager::SEC_ASECDIR_EXT = "/mnt/secure/asec"; 75 76/* 77 * Path to internal storage where *only* root can access ASEC image files 78 */ 79const char *VolumeManager::SEC_ASECDIR_INT = "/data/app-asec"; 80 81/* 82 * Path to where secure containers are mounted 83 */ 84const char *VolumeManager::ASECDIR = "/mnt/asec"; 85 86/* 87 * Path to where OBBs are mounted 88 */ 89const char *VolumeManager::LOOPDIR = "/mnt/obb"; 90 91static const char* kUserMountPath = "/mnt/user"; 92 93static const unsigned int kMajorBlockMmc = 179; 94static const unsigned int kMajorBlockExperimentalMin = 240; 95static const unsigned int kMajorBlockExperimentalMax = 254; 96 97/* writes superblock at end of file or device given by name */ 98static int writeSuperBlock(const char* name, struct asec_superblock *sb, unsigned int numImgSectors) { 99 int sbfd = open(name, O_RDWR | O_CLOEXEC); 100 if (sbfd < 0) { 101 SLOGE("Failed to open %s for superblock write (%s)", name, strerror(errno)); 102 return -1; 103 } 104 105 if (lseek(sbfd, (numImgSectors * 512), SEEK_SET) < 0) { 106 SLOGE("Failed to lseek for superblock (%s)", strerror(errno)); 107 close(sbfd); 108 return -1; 109 } 110 111 if (write(sbfd, sb, sizeof(struct asec_superblock)) != sizeof(struct asec_superblock)) { 112 SLOGE("Failed to write superblock (%s)", strerror(errno)); 113 close(sbfd); 114 return -1; 115 } 116 close(sbfd); 117 return 0; 118} 119 120static unsigned long adjustSectorNumExt4(unsigned long numSectors) { 121 // Ext4 started to reserve 2% or 4096 clusters, whichever is smaller for 122 // preventing costly operations or unexpected ENOSPC error. 123 // Ext4::format() uses default block size without clustering. 124 unsigned long clusterSectors = 4096 / 512; 125 unsigned long reservedSectors = (numSectors * 2)/100 + (numSectors % 50 > 0); 126 numSectors += reservedSectors > (4096 * clusterSectors) ? (4096 * clusterSectors) : reservedSectors; 127 return ROUND_UP_POWER_OF_2(numSectors, 3); 128} 129 130static unsigned long adjustSectorNumFAT(unsigned long numSectors) { 131 /* 132 * Add some headroom 133 */ 134 unsigned long fatSize = (((numSectors * 4) / 512) + 1) * 2; 135 numSectors += fatSize + 2; 136 /* 137 * FAT is aligned to 32 kb with 512b sectors. 138 */ 139 return ROUND_UP_POWER_OF_2(numSectors, 6); 140} 141 142static int setupLoopDevice(char* buffer, size_t len, const char* asecFileName, const char* idHash, bool debug) { 143 if (Loop::lookupActive(idHash, buffer, len)) { 144 if (Loop::create(idHash, asecFileName, buffer, len)) { 145 SLOGE("ASEC loop device creation failed for %s (%s)", asecFileName, strerror(errno)); 146 return -1; 147 } 148 if (debug) { 149 SLOGD("New loop device created at %s", buffer); 150 } 151 } else { 152 if (debug) { 153 SLOGD("Found active loopback for %s at %s", asecFileName, buffer); 154 } 155 } 156 return 0; 157} 158 159static int setupDevMapperDevice(char* buffer, size_t len, const char* loopDevice, const char* asecFileName, const char* key, const char* idHash , unsigned long numImgSectors, bool* createdDMDevice, bool debug) { 160 if (strcmp(key, "none")) { 161 if (Devmapper::lookupActive(idHash, buffer, len)) { 162 if (Devmapper::create(idHash, loopDevice, key, numImgSectors, 163 buffer, len)) { 164 SLOGE("ASEC device mapping failed for %s (%s)", asecFileName, strerror(errno)); 165 return -1; 166 } 167 if (debug) { 168 SLOGD("New devmapper instance created at %s", buffer); 169 } 170 } else { 171 if (debug) { 172 SLOGD("Found active devmapper for %s at %s", asecFileName, buffer); 173 } 174 } 175 *createdDMDevice = true; 176 } else { 177 strcpy(buffer, loopDevice); 178 *createdDMDevice = false; 179 } 180 return 0; 181} 182 183static void waitForDevMapper(const char *dmDevice) { 184 /* 185 * Wait for the device mapper node to be created. Sometimes it takes a 186 * while. Wait for up to 1 second. We could also inspect incoming uevents, 187 * but that would take more effort. 188 */ 189 int tries = 25; 190 while (tries--) { 191 if (!access(dmDevice, F_OK) || errno != ENOENT) { 192 break; 193 } 194 usleep(40 * 1000); 195 } 196} 197 198VolumeManager *VolumeManager::sInstance = NULL; 199 200VolumeManager *VolumeManager::Instance() { 201 if (!sInstance) 202 sInstance = new VolumeManager(); 203 return sInstance; 204} 205 206VolumeManager::VolumeManager() { 207 mDebug = false; 208 mActiveContainers = new AsecIdCollection(); 209 mBroadcaster = NULL; 210 mUmsSharingCount = 0; 211 mSavedDirtyRatio = -1; 212 // set dirty ratio to 0 when UMS is active 213 mUmsDirtyRatio = 0; 214} 215 216VolumeManager::~VolumeManager() { 217 delete mActiveContainers; 218} 219 220char *VolumeManager::asecHash(const char *id, char *buffer, size_t len) { 221 static const char* digits = "0123456789abcdef"; 222 223 unsigned char sig[MD5_DIGEST_LENGTH]; 224 225 if (buffer == NULL) { 226 SLOGE("Destination buffer is NULL"); 227 errno = ESPIPE; 228 return NULL; 229 } else if (id == NULL) { 230 SLOGE("Source buffer is NULL"); 231 errno = ESPIPE; 232 return NULL; 233 } else if (len < MD5_ASCII_LENGTH_PLUS_NULL) { 234 SLOGE("Target hash buffer size < %d bytes (%zu)", 235 MD5_ASCII_LENGTH_PLUS_NULL, len); 236 errno = ESPIPE; 237 return NULL; 238 } 239 240 MD5(reinterpret_cast<const unsigned char*>(id), strlen(id), sig); 241 242 char *p = buffer; 243 for (int i = 0; i < MD5_DIGEST_LENGTH; i++) { 244 *p++ = digits[sig[i] >> 4]; 245 *p++ = digits[sig[i] & 0x0F]; 246 } 247 *p = '\0'; 248 249 return buffer; 250} 251 252int VolumeManager::setDebug(bool enable) { 253 mDebug = enable; 254 return 0; 255} 256 257int VolumeManager::start() { 258 // Always start from a clean slate by unmounting everything in 259 // directories that we own, in case we crashed. 260 unmountAll(); 261 262 // Assume that we always have an emulated volume on internal 263 // storage; the framework will decide if it should be mounted. 264 CHECK(mInternalEmulated == nullptr); 265 mInternalEmulated = std::shared_ptr<android::vold::VolumeBase>( 266 new android::vold::EmulatedVolume("/data/media")); 267 mInternalEmulated->create(); 268 269 return 0; 270} 271 272int VolumeManager::stop() { 273 CHECK(mInternalEmulated != nullptr); 274 mInternalEmulated->destroy(); 275 mInternalEmulated = nullptr; 276 return 0; 277} 278 279void VolumeManager::handleBlockEvent(NetlinkEvent *evt) { 280 std::lock_guard<std::mutex> lock(mLock); 281 282 if (mDebug) { 283 LOG(VERBOSE) << "----------------"; 284 LOG(VERBOSE) << "handleBlockEvent with action " << (int) evt->getAction(); 285 evt->dump(); 286 } 287 288 std::string eventPath(evt->findParam("DEVPATH")?evt->findParam("DEVPATH"):""); 289 std::string devType(evt->findParam("DEVTYPE")?evt->findParam("DEVTYPE"):""); 290 291 if (devType != "disk") return; 292 293 int major = atoi(evt->findParam("MAJOR")); 294 int minor = atoi(evt->findParam("MINOR")); 295 dev_t device = makedev(major, minor); 296 297 switch (evt->getAction()) { 298 case NetlinkEvent::Action::kAdd: { 299 for (auto source : mDiskSources) { 300 if (source->matches(eventPath)) { 301 // For now, assume that MMC and virtio-blk (the latter is 302 // emulator-specific; see Disk.cpp for details) devices are SD, 303 // and that everything else is USB 304 int flags = source->getFlags(); 305 if (major == kMajorBlockMmc 306 || (android::vold::IsRunningInEmulator() 307 && major >= (int) kMajorBlockExperimentalMin 308 && major <= (int) kMajorBlockExperimentalMax)) { 309 flags |= android::vold::Disk::Flags::kSd; 310 } else { 311 flags |= android::vold::Disk::Flags::kUsb; 312 } 313 314 auto disk = new android::vold::Disk(eventPath, device, 315 source->getNickname(), flags); 316 disk->create(); 317 mDisks.push_back(std::shared_ptr<android::vold::Disk>(disk)); 318 break; 319 } 320 } 321 break; 322 } 323 case NetlinkEvent::Action::kChange: { 324 LOG(DEBUG) << "Disk at " << major << ":" << minor << " changed"; 325 for (auto disk : mDisks) { 326 if (disk->getDevice() == device) { 327 disk->readMetadata(); 328 disk->readPartitions(); 329 } 330 } 331 break; 332 } 333 case NetlinkEvent::Action::kRemove: { 334 auto i = mDisks.begin(); 335 while (i != mDisks.end()) { 336 if ((*i)->getDevice() == device) { 337 (*i)->destroy(); 338 i = mDisks.erase(i); 339 } else { 340 ++i; 341 } 342 } 343 break; 344 } 345 default: { 346 LOG(WARNING) << "Unexpected block event action " << (int) evt->getAction(); 347 break; 348 } 349 } 350} 351 352void VolumeManager::addDiskSource(const std::shared_ptr<DiskSource>& diskSource) { 353 mDiskSources.push_back(diskSource); 354} 355 356std::shared_ptr<android::vold::Disk> VolumeManager::findDisk(const std::string& id) { 357 for (auto disk : mDisks) { 358 if (disk->getId() == id) { 359 return disk; 360 } 361 } 362 return nullptr; 363} 364 365std::shared_ptr<android::vold::VolumeBase> VolumeManager::findVolume(const std::string& id) { 366 if (mInternalEmulated->getId() == id) { 367 return mInternalEmulated; 368 } 369 for (auto disk : mDisks) { 370 auto vol = disk->findVolume(id); 371 if (vol != nullptr) { 372 return vol; 373 } 374 } 375 return nullptr; 376} 377 378void VolumeManager::listVolumes(android::vold::VolumeBase::Type type, 379 std::list<std::string>& list) { 380 list.clear(); 381 for (auto disk : mDisks) { 382 disk->listVolumes(type, list); 383 } 384} 385 386nsecs_t VolumeManager::benchmarkPrivate(const std::string& id) { 387 std::string path; 388 if (id == "private" || id == "null") { 389 path = "/data"; 390 } else { 391 auto vol = findVolume(id); 392 if (vol != nullptr && vol->getState() == android::vold::VolumeBase::State::kMounted) { 393 path = vol->getPath(); 394 } 395 } 396 397 if (path.empty()) { 398 LOG(WARNING) << "Failed to find volume for " << id; 399 return -1; 400 } 401 402 return android::vold::BenchmarkPrivate(path); 403} 404 405int VolumeManager::forgetPartition(const std::string& partGuid) { 406 std::string normalizedGuid; 407 if (android::vold::NormalizeHex(partGuid, normalizedGuid)) { 408 LOG(WARNING) << "Invalid GUID " << partGuid; 409 return -1; 410 } 411 412 std::string keyPath = android::vold::BuildKeyPath(normalizedGuid); 413 if (unlink(keyPath.c_str()) != 0) { 414 LOG(ERROR) << "Failed to unlink " << keyPath; 415 return -1; 416 } 417 418 return 0; 419} 420 421int VolumeManager::linkPrimary(userid_t userId) { 422 std::string source(mPrimary->getPath()); 423 if (mPrimary->getType() == android::vold::VolumeBase::Type::kEmulated) { 424 source = StringPrintf("%s/%d", source.c_str(), userId); 425 fs_prepare_dir(source.c_str(), 0755, AID_ROOT, AID_ROOT); 426 } 427 428 std::string target(StringPrintf("/mnt/user/%d/primary", userId)); 429 if (TEMP_FAILURE_RETRY(unlink(target.c_str()))) { 430 if (errno != ENOENT) { 431 SLOGW("Failed to unlink %s: %s", target.c_str(), strerror(errno)); 432 } 433 } 434 LOG(DEBUG) << "Linking " << source << " to " << target; 435 if (TEMP_FAILURE_RETRY(symlink(source.c_str(), target.c_str()))) { 436 SLOGW("Failed to link %s to %s: %s", source.c_str(), target.c_str(), 437 strerror(errno)); 438 return -errno; 439 } 440 return 0; 441} 442 443int VolumeManager::onUserAdded(userid_t userId, int userSerialNumber) { 444 mAddedUsers[userId] = userSerialNumber; 445 return 0; 446} 447 448int VolumeManager::onUserRemoved(userid_t userId) { 449 mAddedUsers.erase(userId); 450 return 0; 451} 452 453int VolumeManager::onUserStarted(userid_t userId) { 454 // Note that sometimes the system will spin up processes from Zygote 455 // before actually starting the user, so we're okay if Zygote 456 // already created this directory. 457 std::string path(StringPrintf("%s/%d", kUserMountPath, userId)); 458 fs_prepare_dir(path.c_str(), 0755, AID_ROOT, AID_ROOT); 459 460 mStartedUsers.insert(userId); 461 if (mPrimary) { 462 linkPrimary(userId); 463 } 464 return 0; 465} 466 467int VolumeManager::onUserStopped(userid_t userId) { 468 mStartedUsers.erase(userId); 469 return 0; 470} 471 472int VolumeManager::setPrimary(const std::shared_ptr<android::vold::VolumeBase>& vol) { 473 mPrimary = vol; 474 for (userid_t userId : mStartedUsers) { 475 linkPrimary(userId); 476 } 477 return 0; 478} 479 480static int unmount_tree(const char* path) { 481 size_t path_len = strlen(path); 482 483 FILE* fp = setmntent("/proc/mounts", "r"); 484 if (fp == NULL) { 485 ALOGE("Error opening /proc/mounts: %s", strerror(errno)); 486 return -errno; 487 } 488 489 // Some volumes can be stacked on each other, so force unmount in 490 // reverse order to give us the best chance of success. 491 std::list<std::string> toUnmount; 492 mntent* mentry; 493 while ((mentry = getmntent(fp)) != NULL) { 494 if (strncmp(mentry->mnt_dir, path, path_len) == 0) { 495 toUnmount.push_front(std::string(mentry->mnt_dir)); 496 } 497 } 498 endmntent(fp); 499 500 for (auto path : toUnmount) { 501 if (umount2(path.c_str(), MNT_DETACH)) { 502 ALOGW("Failed to unmount %s: %s", path.c_str(), strerror(errno)); 503 } 504 } 505 return 0; 506} 507 508int VolumeManager::remountUid(uid_t uid, const std::string& mode) { 509 LOG(DEBUG) << "Remounting " << uid << " as mode " << mode; 510 511 DIR* dir; 512 struct dirent* de; 513 char rootName[PATH_MAX]; 514 char pidName[PATH_MAX]; 515 int pidFd; 516 int nsFd; 517 struct stat sb; 518 pid_t child; 519 520 if (!(dir = opendir("/proc"))) { 521 PLOG(ERROR) << "Failed to opendir"; 522 return -1; 523 } 524 525 // Figure out root namespace to compare against below 526 if (android::vold::SaneReadLinkAt(dirfd(dir), "1/ns/mnt", rootName, PATH_MAX) == -1) { 527 PLOG(ERROR) << "Failed to readlink"; 528 closedir(dir); 529 return -1; 530 } 531 532 // Poke through all running PIDs look for apps running as UID 533 while ((de = readdir(dir))) { 534 pidFd = -1; 535 nsFd = -1; 536 537 pidFd = openat(dirfd(dir), de->d_name, O_RDONLY | O_DIRECTORY | O_CLOEXEC); 538 if (pidFd < 0) { 539 goto next; 540 } 541 if (fstat(pidFd, &sb) != 0) { 542 PLOG(WARNING) << "Failed to stat " << de->d_name; 543 goto next; 544 } 545 if (sb.st_uid != uid) { 546 goto next; 547 } 548 549 // Matches so far, but refuse to touch if in root namespace 550 LOG(DEBUG) << "Found matching PID " << de->d_name; 551 if (android::vold::SaneReadLinkAt(pidFd, "ns/mnt", pidName, PATH_MAX) == -1) { 552 PLOG(WARNING) << "Failed to read namespace for " << de->d_name; 553 goto next; 554 } 555 if (!strcmp(rootName, pidName)) { 556 LOG(WARNING) << "Skipping due to root namespace"; 557 goto next; 558 } 559 560 // We purposefully leave the namespace open across the fork 561 nsFd = openat(pidFd, "ns/mnt", O_RDONLY); 562 if (nsFd < 0) { 563 PLOG(WARNING) << "Failed to open namespace for " << de->d_name; 564 goto next; 565 } 566 567 if (!(child = fork())) { 568 if (setns(nsFd, CLONE_NEWNS) != 0) { 569 PLOG(ERROR) << "Failed to setns for " << de->d_name; 570 _exit(1); 571 } 572 573 unmount_tree("/storage"); 574 575 std::string storageSource; 576 if (mode == "default") { 577 storageSource = "/mnt/runtime/default"; 578 } else if (mode == "read") { 579 storageSource = "/mnt/runtime/read"; 580 } else if (mode == "write") { 581 storageSource = "/mnt/runtime/write"; 582 } else { 583 // Sane default of no storage visible 584 _exit(0); 585 } 586 if (TEMP_FAILURE_RETRY(mount(storageSource.c_str(), "/storage", 587 NULL, MS_BIND | MS_REC | MS_SLAVE, NULL)) == -1) { 588 PLOG(ERROR) << "Failed to mount " << storageSource << " for " 589 << de->d_name; 590 _exit(1); 591 } 592 593 // Mount user-specific symlink helper into place 594 userid_t user_id = multiuser_get_user_id(uid); 595 std::string userSource(StringPrintf("/mnt/user/%d", user_id)); 596 if (TEMP_FAILURE_RETRY(mount(userSource.c_str(), "/storage/self", 597 NULL, MS_BIND, NULL)) == -1) { 598 PLOG(ERROR) << "Failed to mount " << userSource << " for " 599 << de->d_name; 600 _exit(1); 601 } 602 603 _exit(0); 604 } 605 606 if (child == -1) { 607 PLOG(ERROR) << "Failed to fork"; 608 goto next; 609 } else { 610 TEMP_FAILURE_RETRY(waitpid(child, nullptr, 0)); 611 } 612 613next: 614 close(nsFd); 615 close(pidFd); 616 } 617 closedir(dir); 618 return 0; 619} 620 621int VolumeManager::reset() { 622 // Tear down all existing disks/volumes and start from a blank slate so 623 // newly connected framework hears all events. 624 mInternalEmulated->destroy(); 625 mInternalEmulated->create(); 626 for (auto disk : mDisks) { 627 disk->destroy(); 628 disk->create(); 629 } 630 mAddedUsers.clear(); 631 mStartedUsers.clear(); 632 return 0; 633} 634 635int VolumeManager::shutdown() { 636 mInternalEmulated->destroy(); 637 for (auto disk : mDisks) { 638 disk->destroy(); 639 } 640 mDisks.clear(); 641 return 0; 642} 643 644int VolumeManager::unmountAll() { 645 std::lock_guard<std::mutex> lock(mLock); 646 647 // First, try gracefully unmounting all known devices 648 if (mInternalEmulated != nullptr) { 649 mInternalEmulated->unmount(); 650 } 651 for (auto disk : mDisks) { 652 disk->unmountAll(); 653 } 654 655 // Worst case we might have some stale mounts lurking around, so 656 // force unmount those just to be safe. 657 FILE* fp = setmntent("/proc/mounts", "r"); 658 if (fp == NULL) { 659 SLOGE("Error opening /proc/mounts: %s", strerror(errno)); 660 return -errno; 661 } 662 663 // Some volumes can be stacked on each other, so force unmount in 664 // reverse order to give us the best chance of success. 665 std::list<std::string> toUnmount; 666 mntent* mentry; 667 while ((mentry = getmntent(fp)) != NULL) { 668 if (strncmp(mentry->mnt_dir, "/mnt/", 5) == 0 669 || strncmp(mentry->mnt_dir, "/storage/", 9) == 0) { 670 toUnmount.push_front(std::string(mentry->mnt_dir)); 671 } 672 } 673 endmntent(fp); 674 675 for (auto path : toUnmount) { 676 SLOGW("Tearing down stale mount %s", path.c_str()); 677 android::vold::ForceUnmount(path); 678 } 679 680 return 0; 681} 682 683int VolumeManager::getObbMountPath(const char *sourceFile, char *mountPath, int mountPathLen) { 684 char idHash[33]; 685 if (!asecHash(sourceFile, idHash, sizeof(idHash))) { 686 SLOGE("Hash of '%s' failed (%s)", sourceFile, strerror(errno)); 687 return -1; 688 } 689 690 memset(mountPath, 0, mountPathLen); 691 int written = snprintf(mountPath, mountPathLen, "%s/%s", VolumeManager::LOOPDIR, idHash); 692 if ((written < 0) || (written >= mountPathLen)) { 693 errno = EINVAL; 694 return -1; 695 } 696 697 if (access(mountPath, F_OK)) { 698 errno = ENOENT; 699 return -1; 700 } 701 702 return 0; 703} 704 705int VolumeManager::getAsecMountPath(const char *id, char *buffer, int maxlen) { 706 char asecFileName[255]; 707 708 if (!isLegalAsecId(id)) { 709 SLOGE("getAsecMountPath: Invalid asec id \"%s\"", id); 710 errno = EINVAL; 711 return -1; 712 } 713 714 if (findAsec(id, asecFileName, sizeof(asecFileName))) { 715 SLOGE("Couldn't find ASEC %s", id); 716 return -1; 717 } 718 719 memset(buffer, 0, maxlen); 720 if (access(asecFileName, F_OK)) { 721 errno = ENOENT; 722 return -1; 723 } 724 725 int written = snprintf(buffer, maxlen, "%s/%s", VolumeManager::ASECDIR, id); 726 if ((written < 0) || (written >= maxlen)) { 727 SLOGE("getAsecMountPath failed for %s: couldn't construct path in buffer", id); 728 errno = EINVAL; 729 return -1; 730 } 731 732 return 0; 733} 734 735int VolumeManager::getAsecFilesystemPath(const char *id, char *buffer, int maxlen) { 736 char asecFileName[255]; 737 738 if (!isLegalAsecId(id)) { 739 SLOGE("getAsecFilesystemPath: Invalid asec id \"%s\"", id); 740 errno = EINVAL; 741 return -1; 742 } 743 744 if (findAsec(id, asecFileName, sizeof(asecFileName))) { 745 SLOGE("Couldn't find ASEC %s", id); 746 return -1; 747 } 748 749 memset(buffer, 0, maxlen); 750 if (access(asecFileName, F_OK)) { 751 errno = ENOENT; 752 return -1; 753 } 754 755 int written = snprintf(buffer, maxlen, "%s", asecFileName); 756 if ((written < 0) || (written >= maxlen)) { 757 errno = EINVAL; 758 return -1; 759 } 760 761 return 0; 762} 763 764int VolumeManager::createAsec(const char *id, unsigned long numSectors, const char *fstype, 765 const char *key, const int ownerUid, bool isExternal) { 766 struct asec_superblock sb; 767 memset(&sb, 0, sizeof(sb)); 768 769 if (!isLegalAsecId(id)) { 770 SLOGE("createAsec: Invalid asec id \"%s\"", id); 771 errno = EINVAL; 772 return -1; 773 } 774 775 const bool wantFilesystem = strcmp(fstype, "none"); 776 bool usingExt4 = false; 777 if (wantFilesystem) { 778 usingExt4 = !strcmp(fstype, "ext4"); 779 if (usingExt4) { 780 sb.c_opts |= ASEC_SB_C_OPTS_EXT4; 781 } else if (strcmp(fstype, "fat")) { 782 SLOGE("Invalid filesystem type %s", fstype); 783 errno = EINVAL; 784 return -1; 785 } 786 } 787 788 sb.magic = ASEC_SB_MAGIC; 789 sb.ver = ASEC_SB_VER; 790 791 if (numSectors < ((1024*1024)/512)) { 792 SLOGE("Invalid container size specified (%lu sectors)", numSectors); 793 errno = EINVAL; 794 return -1; 795 } 796 797 char asecFileName[255]; 798 799 if (!findAsec(id, asecFileName, sizeof(asecFileName))) { 800 SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)", 801 asecFileName, strerror(errno)); 802 errno = EADDRINUSE; 803 return -1; 804 } 805 806 const char *asecDir = isExternal ? VolumeManager::SEC_ASECDIR_EXT : VolumeManager::SEC_ASECDIR_INT; 807 808 int written = snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", asecDir, id); 809 if ((written < 0) || (size_t(written) >= sizeof(asecFileName))) { 810 errno = EINVAL; 811 return -1; 812 } 813 814 if (!access(asecFileName, F_OK)) { 815 SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)", 816 asecFileName, strerror(errno)); 817 errno = EADDRINUSE; 818 return -1; 819 } 820 821 unsigned long numImgSectors; 822 if (usingExt4) 823 numImgSectors = adjustSectorNumExt4(numSectors); 824 else 825 numImgSectors = adjustSectorNumFAT(numSectors); 826 827 // Add +1 for our superblock which is at the end 828 if (Loop::createImageFile(asecFileName, numImgSectors + 1)) { 829 SLOGE("ASEC image file creation failed (%s)", strerror(errno)); 830 return -1; 831 } 832 833 char idHash[33]; 834 if (!asecHash(id, idHash, sizeof(idHash))) { 835 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno)); 836 unlink(asecFileName); 837 return -1; 838 } 839 840 char loopDevice[255]; 841 if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) { 842 SLOGE("ASEC loop device creation failed (%s)", strerror(errno)); 843 unlink(asecFileName); 844 return -1; 845 } 846 847 char dmDevice[255]; 848 bool cleanupDm = false; 849 850 if (strcmp(key, "none")) { 851 // XXX: This is all we support for now 852 sb.c_cipher = ASEC_SB_C_CIPHER_TWOFISH; 853 if (Devmapper::create(idHash, loopDevice, key, numImgSectors, dmDevice, 854 sizeof(dmDevice))) { 855 SLOGE("ASEC device mapping failed (%s)", strerror(errno)); 856 Loop::destroyByDevice(loopDevice); 857 unlink(asecFileName); 858 return -1; 859 } 860 cleanupDm = true; 861 } else { 862 sb.c_cipher = ASEC_SB_C_CIPHER_NONE; 863 strcpy(dmDevice, loopDevice); 864 } 865 866 /* 867 * Drop down the superblock at the end of the file 868 */ 869 if (writeSuperBlock(loopDevice, &sb, numImgSectors)) { 870 if (cleanupDm) { 871 Devmapper::destroy(idHash); 872 } 873 Loop::destroyByDevice(loopDevice); 874 unlink(asecFileName); 875 return -1; 876 } 877 878 if (wantFilesystem) { 879 int formatStatus; 880 char mountPoint[255]; 881 882 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id); 883 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) { 884 SLOGE("ASEC fs format failed: couldn't construct mountPoint"); 885 if (cleanupDm) { 886 Devmapper::destroy(idHash); 887 } 888 Loop::destroyByDevice(loopDevice); 889 unlink(asecFileName); 890 return -1; 891 } 892 893 if (usingExt4) { 894 formatStatus = android::vold::ext4::Format(dmDevice, numImgSectors, mountPoint); 895 } else { 896 formatStatus = android::vold::vfat::Format(dmDevice, numImgSectors); 897 } 898 899 if (formatStatus < 0) { 900 SLOGE("ASEC fs format failed (%s)", strerror(errno)); 901 if (cleanupDm) { 902 Devmapper::destroy(idHash); 903 } 904 Loop::destroyByDevice(loopDevice); 905 unlink(asecFileName); 906 return -1; 907 } 908 909 if (mkdir(mountPoint, 0000)) { 910 if (errno != EEXIST) { 911 SLOGE("Mountpoint creation failed (%s)", strerror(errno)); 912 if (cleanupDm) { 913 Devmapper::destroy(idHash); 914 } 915 Loop::destroyByDevice(loopDevice); 916 unlink(asecFileName); 917 return -1; 918 } 919 } 920 921 int mountStatus; 922 if (usingExt4) { 923 mountStatus = android::vold::ext4::Mount(dmDevice, mountPoint, 924 false, false, false); 925 } else { 926 mountStatus = android::vold::vfat::Mount(dmDevice, mountPoint, 927 false, false, false, ownerUid, 0, 0000, false); 928 } 929 930 if (mountStatus) { 931 SLOGE("ASEC FAT mount failed (%s)", strerror(errno)); 932 if (cleanupDm) { 933 Devmapper::destroy(idHash); 934 } 935 Loop::destroyByDevice(loopDevice); 936 unlink(asecFileName); 937 return -1; 938 } 939 940 if (usingExt4) { 941 int dirfd = open(mountPoint, O_DIRECTORY | O_CLOEXEC); 942 if (dirfd >= 0) { 943 if (fchown(dirfd, ownerUid, AID_SYSTEM) 944 || fchmod(dirfd, S_IRUSR | S_IWUSR | S_IXUSR | S_ISGID | S_IRGRP | S_IXGRP)) { 945 SLOGI("Cannot chown/chmod new ASEC mount point %s", mountPoint); 946 } 947 close(dirfd); 948 } 949 } 950 } else { 951 SLOGI("Created raw secure container %s (no filesystem)", id); 952 } 953 954 mActiveContainers->push_back(new ContainerData(strdup(id), ASEC)); 955 return 0; 956} 957 958int VolumeManager::resizeAsec(const char *id, unsigned long numSectors, const char *key) { 959 char asecFileName[255]; 960 char mountPoint[255]; 961 bool cleanupDm = false; 962 963 if (!isLegalAsecId(id)) { 964 SLOGE("resizeAsec: Invalid asec id \"%s\"", id); 965 errno = EINVAL; 966 return -1; 967 } 968 969 if (findAsec(id, asecFileName, sizeof(asecFileName))) { 970 SLOGE("Couldn't find ASEC %s", id); 971 return -1; 972 } 973 974 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id); 975 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) { 976 SLOGE("ASEC resize failed for %s: couldn't construct mountpoint", id); 977 return -1; 978 } 979 980 if (isMountpointMounted(mountPoint)) { 981 SLOGE("ASEC %s mounted. Unmount before resizing", id); 982 errno = EBUSY; 983 return -1; 984 } 985 986 struct asec_superblock sb; 987 int fd; 988 unsigned long oldNumSec = 0; 989 990 if ((fd = open(asecFileName, O_RDONLY | O_CLOEXEC)) < 0) { 991 SLOGE("Failed to open ASEC file (%s)", strerror(errno)); 992 return -1; 993 } 994 995 struct stat info; 996 if (fstat(fd, &info) < 0) { 997 SLOGE("Failed to get file size (%s)", strerror(errno)); 998 close(fd); 999 return -1; 1000 } 1001 1002 oldNumSec = info.st_size / 512; 1003 1004 unsigned long numImgSectors; 1005 if (sb.c_opts & ASEC_SB_C_OPTS_EXT4) 1006 numImgSectors = adjustSectorNumExt4(numSectors); 1007 else 1008 numImgSectors = adjustSectorNumFAT(numSectors); 1009 /* 1010 * add one block for the superblock 1011 */ 1012 SLOGD("Resizing from %lu sectors to %lu sectors", oldNumSec, numImgSectors + 1); 1013 if (oldNumSec == numImgSectors + 1) { 1014 SLOGW("Size unchanged; ignoring resize request"); 1015 return 0; 1016 } else if (oldNumSec > numImgSectors + 1) { 1017 SLOGE("Only growing is currently supported."); 1018 close(fd); 1019 return -1; 1020 } 1021 1022 /* 1023 * Try to read superblock. 1024 */ 1025 memset(&sb, 0, sizeof(struct asec_superblock)); 1026 if (lseek(fd, ((oldNumSec - 1) * 512), SEEK_SET) < 0) { 1027 SLOGE("lseek failed (%s)", strerror(errno)); 1028 close(fd); 1029 return -1; 1030 } 1031 if (read(fd, &sb, sizeof(struct asec_superblock)) != sizeof(struct asec_superblock)) { 1032 SLOGE("superblock read failed (%s)", strerror(errno)); 1033 close(fd); 1034 return -1; 1035 } 1036 close(fd); 1037 1038 if (mDebug) { 1039 SLOGD("Container sb magic/ver (%.8x/%.2x)", sb.magic, sb.ver); 1040 } 1041 if (sb.magic != ASEC_SB_MAGIC || sb.ver != ASEC_SB_VER) { 1042 SLOGE("Bad container magic/version (%.8x/%.2x)", sb.magic, sb.ver); 1043 errno = EMEDIUMTYPE; 1044 return -1; 1045 } 1046 1047 if (!(sb.c_opts & ASEC_SB_C_OPTS_EXT4)) { 1048 SLOGE("Only ext4 partitions are supported for resize"); 1049 errno = EINVAL; 1050 return -1; 1051 } 1052 1053 if (Loop::resizeImageFile(asecFileName, numImgSectors + 1)) { 1054 SLOGE("Resize of ASEC image file failed. Could not resize %s", id); 1055 return -1; 1056 } 1057 1058 /* 1059 * Drop down a copy of the superblock at the end of the file 1060 */ 1061 if (writeSuperBlock(asecFileName, &sb, numImgSectors)) 1062 goto fail; 1063 1064 char idHash[33]; 1065 if (!asecHash(id, idHash, sizeof(idHash))) { 1066 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno)); 1067 goto fail; 1068 } 1069 1070 char loopDevice[255]; 1071 if (setupLoopDevice(loopDevice, sizeof(loopDevice), asecFileName, idHash, mDebug)) 1072 goto fail; 1073 1074 char dmDevice[255]; 1075 1076 if (setupDevMapperDevice(dmDevice, sizeof(dmDevice), loopDevice, asecFileName, key, idHash, numImgSectors, &cleanupDm, mDebug)) { 1077 Loop::destroyByDevice(loopDevice); 1078 goto fail; 1079 } 1080 1081 /* 1082 * Wait for the device mapper node to be created. 1083 */ 1084 waitForDevMapper(dmDevice); 1085 1086 if (android::vold::ext4::Resize(dmDevice, numImgSectors)) { 1087 SLOGE("Unable to resize %s (%s)", id, strerror(errno)); 1088 if (cleanupDm) { 1089 Devmapper::destroy(idHash); 1090 } 1091 Loop::destroyByDevice(loopDevice); 1092 goto fail; 1093 } 1094 1095 return 0; 1096fail: 1097 Loop::resizeImageFile(asecFileName, oldNumSec); 1098 return -1; 1099} 1100 1101int VolumeManager::finalizeAsec(const char *id) { 1102 char asecFileName[255]; 1103 char loopDevice[255]; 1104 char mountPoint[255]; 1105 1106 if (!isLegalAsecId(id)) { 1107 SLOGE("finalizeAsec: Invalid asec id \"%s\"", id); 1108 errno = EINVAL; 1109 return -1; 1110 } 1111 1112 if (findAsec(id, asecFileName, sizeof(asecFileName))) { 1113 SLOGE("Couldn't find ASEC %s", id); 1114 return -1; 1115 } 1116 1117 char idHash[33]; 1118 if (!asecHash(id, idHash, sizeof(idHash))) { 1119 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno)); 1120 return -1; 1121 } 1122 1123 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) { 1124 SLOGE("Unable to finalize %s (%s)", id, strerror(errno)); 1125 return -1; 1126 } 1127 1128 unsigned long nr_sec = 0; 1129 struct asec_superblock sb; 1130 1131 if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) { 1132 return -1; 1133 } 1134 1135 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id); 1136 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) { 1137 SLOGE("ASEC finalize failed: couldn't construct mountPoint"); 1138 return -1; 1139 } 1140 1141 int result = 0; 1142 if (sb.c_opts & ASEC_SB_C_OPTS_EXT4) { 1143 result = android::vold::ext4::Mount(loopDevice, mountPoint, 1144 true, true, true); 1145 } else { 1146 result = android::vold::vfat::Mount(loopDevice, mountPoint, 1147 true, true, true, 0, 0, 0227, false); 1148 } 1149 1150 if (result) { 1151 SLOGE("ASEC finalize mount failed (%s)", strerror(errno)); 1152 return -1; 1153 } 1154 1155 if (mDebug) { 1156 SLOGD("ASEC %s finalized", id); 1157 } 1158 return 0; 1159} 1160 1161int VolumeManager::fixupAsecPermissions(const char *id, gid_t gid, const char* filename) { 1162 char asecFileName[255]; 1163 char loopDevice[255]; 1164 char mountPoint[255]; 1165 1166 if (gid < AID_APP) { 1167 SLOGE("Group ID is not in application range"); 1168 return -1; 1169 } 1170 1171 if (!isLegalAsecId(id)) { 1172 SLOGE("fixupAsecPermissions: Invalid asec id \"%s\"", id); 1173 errno = EINVAL; 1174 return -1; 1175 } 1176 1177 if (findAsec(id, asecFileName, sizeof(asecFileName))) { 1178 SLOGE("Couldn't find ASEC %s", id); 1179 return -1; 1180 } 1181 1182 char idHash[33]; 1183 if (!asecHash(id, idHash, sizeof(idHash))) { 1184 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno)); 1185 return -1; 1186 } 1187 1188 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) { 1189 SLOGE("Unable fix permissions during lookup on %s (%s)", id, strerror(errno)); 1190 return -1; 1191 } 1192 1193 unsigned long nr_sec = 0; 1194 struct asec_superblock sb; 1195 1196 if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) { 1197 return -1; 1198 } 1199 1200 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id); 1201 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) { 1202 SLOGE("Unable remount to fix permissions for %s: couldn't construct mountpoint", id); 1203 return -1; 1204 } 1205 1206 int result = 0; 1207 if ((sb.c_opts & ASEC_SB_C_OPTS_EXT4) == 0) { 1208 return 0; 1209 } 1210 1211 int ret = android::vold::ext4::Mount(loopDevice, mountPoint, 1212 false /* read-only */, 1213 true /* remount */, 1214 false /* executable */); 1215 if (ret) { 1216 SLOGE("Unable remount to fix permissions for %s (%s)", id, strerror(errno)); 1217 return -1; 1218 } 1219 1220 char *paths[] = { mountPoint, NULL }; 1221 1222 FTS *fts = fts_open(paths, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL); 1223 if (fts) { 1224 // Traverse the entire hierarchy and chown to system UID. 1225 for (FTSENT *ftsent = fts_read(fts); ftsent != NULL; ftsent = fts_read(fts)) { 1226 // We don't care about the lost+found directory. 1227 if (!strcmp(ftsent->fts_name, "lost+found")) { 1228 continue; 1229 } 1230 1231 /* 1232 * There can only be one file marked as private right now. 1233 * This should be more robust, but it satisfies the requirements 1234 * we have for right now. 1235 */ 1236 const bool privateFile = !strcmp(ftsent->fts_name, filename); 1237 1238 int fd = open(ftsent->fts_accpath, O_NOFOLLOW | O_CLOEXEC); 1239 if (fd < 0) { 1240 SLOGE("Couldn't open file %s: %s", ftsent->fts_accpath, strerror(errno)); 1241 result = -1; 1242 continue; 1243 } 1244 1245 result |= fchown(fd, AID_SYSTEM, privateFile? gid : AID_SYSTEM); 1246 1247 if (ftsent->fts_info & FTS_D) { 1248 result |= fchmod(fd, 0755); 1249 } else if (ftsent->fts_info & FTS_F) { 1250 result |= fchmod(fd, privateFile ? 0640 : 0644); 1251 } 1252 1253 if (selinux_android_restorecon(ftsent->fts_path, 0) < 0) { 1254 SLOGE("restorecon failed for %s: %s\n", ftsent->fts_path, strerror(errno)); 1255 result |= -1; 1256 } 1257 1258 close(fd); 1259 } 1260 fts_close(fts); 1261 1262 // Finally make the directory readable by everyone. 1263 int dirfd = open(mountPoint, O_DIRECTORY | O_CLOEXEC); 1264 if (dirfd < 0 || fchmod(dirfd, 0755)) { 1265 SLOGE("Couldn't change owner of existing directory %s: %s", mountPoint, strerror(errno)); 1266 result |= -1; 1267 } 1268 close(dirfd); 1269 } else { 1270 result |= -1; 1271 } 1272 1273 result |= android::vold::ext4::Mount(loopDevice, mountPoint, 1274 true /* read-only */, 1275 true /* remount */, 1276 true /* execute */); 1277 1278 if (result) { 1279 SLOGE("ASEC fix permissions failed (%s)", strerror(errno)); 1280 return -1; 1281 } 1282 1283 if (mDebug) { 1284 SLOGD("ASEC %s permissions fixed", id); 1285 } 1286 return 0; 1287} 1288 1289int VolumeManager::renameAsec(const char *id1, const char *id2) { 1290 char asecFilename1[255]; 1291 char *asecFilename2; 1292 char mountPoint[255]; 1293 1294 const char *dir; 1295 1296 if (!isLegalAsecId(id1)) { 1297 SLOGE("renameAsec: Invalid asec id1 \"%s\"", id1); 1298 errno = EINVAL; 1299 return -1; 1300 } 1301 1302 if (!isLegalAsecId(id2)) { 1303 SLOGE("renameAsec: Invalid asec id2 \"%s\"", id2); 1304 errno = EINVAL; 1305 return -1; 1306 } 1307 1308 if (findAsec(id1, asecFilename1, sizeof(asecFilename1), &dir)) { 1309 SLOGE("Couldn't find ASEC %s", id1); 1310 return -1; 1311 } 1312 1313 asprintf(&asecFilename2, "%s/%s.asec", dir, id2); 1314 1315 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id1); 1316 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) { 1317 SLOGE("Rename failed: couldn't construct mountpoint"); 1318 goto out_err; 1319 } 1320 1321 if (isMountpointMounted(mountPoint)) { 1322 SLOGW("Rename attempt when src mounted"); 1323 errno = EBUSY; 1324 goto out_err; 1325 } 1326 1327 written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id2); 1328 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) { 1329 SLOGE("Rename failed: couldn't construct mountpoint2"); 1330 goto out_err; 1331 } 1332 1333 if (isMountpointMounted(mountPoint)) { 1334 SLOGW("Rename attempt when dst mounted"); 1335 errno = EBUSY; 1336 goto out_err; 1337 } 1338 1339 if (!access(asecFilename2, F_OK)) { 1340 SLOGE("Rename attempt when dst exists"); 1341 errno = EADDRINUSE; 1342 goto out_err; 1343 } 1344 1345 if (rename(asecFilename1, asecFilename2)) { 1346 SLOGE("Rename of '%s' to '%s' failed (%s)", asecFilename1, asecFilename2, strerror(errno)); 1347 goto out_err; 1348 } 1349 1350 free(asecFilename2); 1351 return 0; 1352 1353out_err: 1354 free(asecFilename2); 1355 return -1; 1356} 1357 1358#define UNMOUNT_RETRIES 5 1359#define UNMOUNT_SLEEP_BETWEEN_RETRY_MS (1000 * 1000) 1360int VolumeManager::unmountAsec(const char *id, bool force) { 1361 char asecFileName[255]; 1362 char mountPoint[255]; 1363 1364 if (!isLegalAsecId(id)) { 1365 SLOGE("unmountAsec: Invalid asec id \"%s\"", id); 1366 errno = EINVAL; 1367 return -1; 1368 } 1369 1370 if (findAsec(id, asecFileName, sizeof(asecFileName))) { 1371 SLOGE("Couldn't find ASEC %s", id); 1372 return -1; 1373 } 1374 1375 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id); 1376 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) { 1377 SLOGE("ASEC unmount failed for %s: couldn't construct mountpoint", id); 1378 return -1; 1379 } 1380 1381 char idHash[33]; 1382 if (!asecHash(id, idHash, sizeof(idHash))) { 1383 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno)); 1384 return -1; 1385 } 1386 1387 return unmountLoopImage(id, idHash, asecFileName, mountPoint, force); 1388} 1389 1390int VolumeManager::unmountObb(const char *fileName, bool force) { 1391 char mountPoint[255]; 1392 1393 char idHash[33]; 1394 if (!asecHash(fileName, idHash, sizeof(idHash))) { 1395 SLOGE("Hash of '%s' failed (%s)", fileName, strerror(errno)); 1396 return -1; 1397 } 1398 1399 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::LOOPDIR, idHash); 1400 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) { 1401 SLOGE("OBB unmount failed for %s: couldn't construct mountpoint", fileName); 1402 return -1; 1403 } 1404 1405 return unmountLoopImage(fileName, idHash, fileName, mountPoint, force); 1406} 1407 1408int VolumeManager::unmountLoopImage(const char *id, const char *idHash, 1409 const char *fileName, const char *mountPoint, bool force) { 1410 if (!isMountpointMounted(mountPoint)) { 1411 SLOGE("Unmount request for %s when not mounted", id); 1412 errno = ENOENT; 1413 return -1; 1414 } 1415 1416 int i, rc; 1417 for (i = 1; i <= UNMOUNT_RETRIES; i++) { 1418 rc = umount(mountPoint); 1419 if (!rc) { 1420 break; 1421 } 1422 if (rc && (errno == EINVAL || errno == ENOENT)) { 1423 SLOGI("Container %s unmounted OK", id); 1424 rc = 0; 1425 break; 1426 } 1427 SLOGW("%s unmount attempt %d failed (%s)", 1428 id, i, strerror(errno)); 1429 1430 int signal = 0; // default is to just complain 1431 1432 if (force) { 1433 if (i > (UNMOUNT_RETRIES - 2)) 1434 signal = SIGKILL; 1435 else if (i > (UNMOUNT_RETRIES - 3)) 1436 signal = SIGTERM; 1437 } 1438 1439 Process::killProcessesWithOpenFiles(mountPoint, signal); 1440 usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS); 1441 } 1442 1443 if (rc) { 1444 errno = EBUSY; 1445 SLOGE("Failed to unmount container %s (%s)", id, strerror(errno)); 1446 return -1; 1447 } 1448 1449 int retries = 10; 1450 1451 while(retries--) { 1452 if (!rmdir(mountPoint)) { 1453 break; 1454 } 1455 1456 SLOGW("Failed to rmdir %s (%s)", mountPoint, strerror(errno)); 1457 usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS); 1458 } 1459 1460 if (!retries) { 1461 SLOGE("Timed out trying to rmdir %s (%s)", mountPoint, strerror(errno)); 1462 } 1463 1464 for (i=1; i <= UNMOUNT_RETRIES; i++) { 1465 if (Devmapper::destroy(idHash) && errno != ENXIO) { 1466 SLOGE("Failed to destroy devmapper instance (%s)", strerror(errno)); 1467 usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS); 1468 continue; 1469 } else { 1470 break; 1471 } 1472 } 1473 1474 char loopDevice[255]; 1475 if (!Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) { 1476 Loop::destroyByDevice(loopDevice); 1477 } else { 1478 SLOGW("Failed to find loop device for {%s} (%s)", fileName, strerror(errno)); 1479 } 1480 1481 AsecIdCollection::iterator it; 1482 for (it = mActiveContainers->begin(); it != mActiveContainers->end(); ++it) { 1483 ContainerData* cd = *it; 1484 if (!strcmp(cd->id, id)) { 1485 free(*it); 1486 mActiveContainers->erase(it); 1487 break; 1488 } 1489 } 1490 if (it == mActiveContainers->end()) { 1491 SLOGW("mActiveContainers is inconsistent!"); 1492 } 1493 return 0; 1494} 1495 1496int VolumeManager::destroyAsec(const char *id, bool force) { 1497 char asecFileName[255]; 1498 char mountPoint[255]; 1499 1500 if (!isLegalAsecId(id)) { 1501 SLOGE("destroyAsec: Invalid asec id \"%s\"", id); 1502 errno = EINVAL; 1503 return -1; 1504 } 1505 1506 if (findAsec(id, asecFileName, sizeof(asecFileName))) { 1507 SLOGE("Couldn't find ASEC %s", id); 1508 return -1; 1509 } 1510 1511 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id); 1512 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) { 1513 SLOGE("ASEC destroy failed for %s: couldn't construct mountpoint", id); 1514 return -1; 1515 } 1516 1517 if (isMountpointMounted(mountPoint)) { 1518 if (mDebug) { 1519 SLOGD("Unmounting container before destroy"); 1520 } 1521 if (unmountAsec(id, force)) { 1522 SLOGE("Failed to unmount asec %s for destroy (%s)", id, strerror(errno)); 1523 return -1; 1524 } 1525 } 1526 1527 if (unlink(asecFileName)) { 1528 SLOGE("Failed to unlink asec '%s' (%s)", asecFileName, strerror(errno)); 1529 return -1; 1530 } 1531 1532 if (mDebug) { 1533 SLOGD("ASEC %s destroyed", id); 1534 } 1535 return 0; 1536} 1537 1538/* 1539 * Legal ASEC ids consist of alphanumeric characters, '-', 1540 * '_', or '.'. ".." is not allowed. The first or last character 1541 * of the ASEC id cannot be '.' (dot). 1542 */ 1543bool VolumeManager::isLegalAsecId(const char *id) const { 1544 size_t i; 1545 size_t len = strlen(id); 1546 1547 if (len == 0) { 1548 return false; 1549 } 1550 if ((id[0] == '.') || (id[len - 1] == '.')) { 1551 return false; 1552 } 1553 1554 for (i = 0; i < len; i++) { 1555 if (id[i] == '.') { 1556 // i=0 is guaranteed never to have a dot. See above. 1557 if (id[i-1] == '.') return false; 1558 continue; 1559 } 1560 if (id[i] == '_' || id[i] == '-') continue; 1561 if (id[i] >= 'a' && id[i] <= 'z') continue; 1562 if (id[i] >= 'A' && id[i] <= 'Z') continue; 1563 if (id[i] >= '0' && id[i] <= '9') continue; 1564 return false; 1565 } 1566 1567 return true; 1568} 1569 1570bool VolumeManager::isAsecInDirectory(const char *dir, const char *asecName) const { 1571 int dirfd = open(dir, O_DIRECTORY | O_CLOEXEC); 1572 if (dirfd < 0) { 1573 SLOGE("Couldn't open internal ASEC dir (%s)", strerror(errno)); 1574 return false; 1575 } 1576 1577 struct stat sb; 1578 bool ret = (fstatat(dirfd, asecName, &sb, AT_SYMLINK_NOFOLLOW) == 0) 1579 && S_ISREG(sb.st_mode); 1580 1581 close(dirfd); 1582 1583 return ret; 1584} 1585 1586int VolumeManager::findAsec(const char *id, char *asecPath, size_t asecPathLen, 1587 const char **directory) const { 1588 char *asecName; 1589 1590 if (!isLegalAsecId(id)) { 1591 SLOGE("findAsec: Invalid asec id \"%s\"", id); 1592 errno = EINVAL; 1593 return -1; 1594 } 1595 1596 if (asprintf(&asecName, "%s.asec", id) < 0) { 1597 SLOGE("Couldn't allocate string to write ASEC name"); 1598 return -1; 1599 } 1600 1601 const char *dir; 1602 if (isAsecInDirectory(VolumeManager::SEC_ASECDIR_INT, asecName)) { 1603 dir = VolumeManager::SEC_ASECDIR_INT; 1604 } else if (isAsecInDirectory(VolumeManager::SEC_ASECDIR_EXT, asecName)) { 1605 dir = VolumeManager::SEC_ASECDIR_EXT; 1606 } else { 1607 free(asecName); 1608 return -1; 1609 } 1610 1611 if (directory != NULL) { 1612 *directory = dir; 1613 } 1614 1615 if (asecPath != NULL) { 1616 int written = snprintf(asecPath, asecPathLen, "%s/%s", dir, asecName); 1617 if ((written < 0) || (size_t(written) >= asecPathLen)) { 1618 SLOGE("findAsec failed for %s: couldn't construct ASEC path", id); 1619 free(asecName); 1620 return -1; 1621 } 1622 } 1623 1624 free(asecName); 1625 return 0; 1626} 1627 1628int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid, bool readOnly) { 1629 char asecFileName[255]; 1630 char mountPoint[255]; 1631 1632 if (!isLegalAsecId(id)) { 1633 SLOGE("mountAsec: Invalid asec id \"%s\"", id); 1634 errno = EINVAL; 1635 return -1; 1636 } 1637 1638 if (findAsec(id, asecFileName, sizeof(asecFileName))) { 1639 SLOGE("Couldn't find ASEC %s", id); 1640 return -1; 1641 } 1642 1643 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id); 1644 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) { 1645 SLOGE("ASEC mount failed for %s: couldn't construct mountpoint", id); 1646 return -1; 1647 } 1648 1649 if (isMountpointMounted(mountPoint)) { 1650 SLOGE("ASEC %s already mounted", id); 1651 errno = EBUSY; 1652 return -1; 1653 } 1654 1655 char idHash[33]; 1656 if (!asecHash(id, idHash, sizeof(idHash))) { 1657 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno)); 1658 return -1; 1659 } 1660 1661 char loopDevice[255]; 1662 if (setupLoopDevice(loopDevice, sizeof(loopDevice), asecFileName, idHash, mDebug)) 1663 return -1; 1664 1665 char dmDevice[255]; 1666 bool cleanupDm = false; 1667 1668 unsigned long nr_sec = 0; 1669 struct asec_superblock sb; 1670 1671 if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) { 1672 return -1; 1673 } 1674 1675 if (mDebug) { 1676 SLOGD("Container sb magic/ver (%.8x/%.2x)", sb.magic, sb.ver); 1677 } 1678 if (sb.magic != ASEC_SB_MAGIC || sb.ver != ASEC_SB_VER) { 1679 SLOGE("Bad container magic/version (%.8x/%.2x)", sb.magic, sb.ver); 1680 Loop::destroyByDevice(loopDevice); 1681 errno = EMEDIUMTYPE; 1682 return -1; 1683 } 1684 nr_sec--; // We don't want the devmapping to extend onto our superblock 1685 1686 if (setupDevMapperDevice(dmDevice, sizeof(dmDevice), loopDevice, asecFileName, key, idHash , nr_sec, &cleanupDm, mDebug)) { 1687 Loop::destroyByDevice(loopDevice); 1688 return -1; 1689 } 1690 1691 if (mkdir(mountPoint, 0000)) { 1692 if (errno != EEXIST) { 1693 SLOGE("Mountpoint creation failed (%s)", strerror(errno)); 1694 if (cleanupDm) { 1695 Devmapper::destroy(idHash); 1696 } 1697 Loop::destroyByDevice(loopDevice); 1698 return -1; 1699 } 1700 } 1701 1702 /* 1703 * Wait for the device mapper node to be created. 1704 */ 1705 waitForDevMapper(dmDevice); 1706 1707 int result; 1708 if (sb.c_opts & ASEC_SB_C_OPTS_EXT4) { 1709 result = android::vold::ext4::Mount(dmDevice, mountPoint, 1710 readOnly, false, readOnly); 1711 } else { 1712 result = android::vold::vfat::Mount(dmDevice, mountPoint, 1713 readOnly, false, readOnly, ownerUid, 0, 0222, false); 1714 } 1715 1716 if (result) { 1717 SLOGE("ASEC mount failed (%s)", strerror(errno)); 1718 if (cleanupDm) { 1719 Devmapper::destroy(idHash); 1720 } 1721 Loop::destroyByDevice(loopDevice); 1722 return -1; 1723 } 1724 1725 mActiveContainers->push_back(new ContainerData(strdup(id), ASEC)); 1726 if (mDebug) { 1727 SLOGD("ASEC %s mounted", id); 1728 } 1729 return 0; 1730} 1731 1732/** 1733 * Mounts an image file <code>img</code>. 1734 */ 1735int VolumeManager::mountObb(const char *img, const char *key, int ownerGid) { 1736 char mountPoint[255]; 1737 1738 char idHash[33]; 1739 if (!asecHash(img, idHash, sizeof(idHash))) { 1740 SLOGE("Hash of '%s' failed (%s)", img, strerror(errno)); 1741 return -1; 1742 } 1743 1744 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::LOOPDIR, idHash); 1745 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) { 1746 SLOGE("OBB mount failed for %s: couldn't construct mountpoint", img); 1747 return -1; 1748 } 1749 1750 if (isMountpointMounted(mountPoint)) { 1751 SLOGE("Image %s already mounted", img); 1752 errno = EBUSY; 1753 return -1; 1754 } 1755 1756 char loopDevice[255]; 1757 if (setupLoopDevice(loopDevice, sizeof(loopDevice), img, idHash, mDebug)) 1758 return -1; 1759 1760 char dmDevice[255]; 1761 bool cleanupDm = false; 1762 int fd; 1763 unsigned long nr_sec = 0; 1764 1765 if ((fd = open(loopDevice, O_RDWR | O_CLOEXEC)) < 0) { 1766 SLOGE("Failed to open loopdevice (%s)", strerror(errno)); 1767 Loop::destroyByDevice(loopDevice); 1768 return -1; 1769 } 1770 1771 get_blkdev_size(fd, &nr_sec); 1772 if (nr_sec == 0) { 1773 SLOGE("Failed to get loop size (%s)", strerror(errno)); 1774 Loop::destroyByDevice(loopDevice); 1775 close(fd); 1776 return -1; 1777 } 1778 1779 close(fd); 1780 1781 if (setupDevMapperDevice(dmDevice, sizeof(loopDevice), loopDevice, img,key, idHash, nr_sec, &cleanupDm, mDebug)) { 1782 Loop::destroyByDevice(loopDevice); 1783 return -1; 1784 } 1785 1786 if (mkdir(mountPoint, 0755)) { 1787 if (errno != EEXIST) { 1788 SLOGE("Mountpoint creation failed (%s)", strerror(errno)); 1789 if (cleanupDm) { 1790 Devmapper::destroy(idHash); 1791 } 1792 Loop::destroyByDevice(loopDevice); 1793 return -1; 1794 } 1795 } 1796 1797 /* 1798 * Wait for the device mapper node to be created. 1799 */ 1800 waitForDevMapper(dmDevice); 1801 1802 if (android::vold::vfat::Mount(dmDevice, mountPoint, 1803 true, false, true, 0, ownerGid, 0227, false)) { 1804 SLOGE("Image mount failed (%s)", strerror(errno)); 1805 if (cleanupDm) { 1806 Devmapper::destroy(idHash); 1807 } 1808 Loop::destroyByDevice(loopDevice); 1809 return -1; 1810 } 1811 1812 mActiveContainers->push_back(new ContainerData(strdup(img), OBB)); 1813 if (mDebug) { 1814 SLOGD("Image %s mounted", img); 1815 } 1816 return 0; 1817} 1818 1819int VolumeManager::listMountedObbs(SocketClient* cli) { 1820 FILE *fp = setmntent("/proc/mounts", "r"); 1821 if (fp == NULL) { 1822 SLOGE("Error opening /proc/mounts (%s)", strerror(errno)); 1823 return -1; 1824 } 1825 1826 // Create a string to compare against that has a trailing slash 1827 int loopDirLen = strlen(VolumeManager::LOOPDIR); 1828 char loopDir[loopDirLen + 2]; 1829 strcpy(loopDir, VolumeManager::LOOPDIR); 1830 loopDir[loopDirLen++] = '/'; 1831 loopDir[loopDirLen] = '\0'; 1832 1833 mntent* mentry; 1834 while ((mentry = getmntent(fp)) != NULL) { 1835 if (!strncmp(mentry->mnt_dir, loopDir, loopDirLen)) { 1836 int fd = open(mentry->mnt_fsname, O_RDONLY | O_CLOEXEC); 1837 if (fd >= 0) { 1838 struct loop_info64 li; 1839 if (ioctl(fd, LOOP_GET_STATUS64, &li) >= 0) { 1840 cli->sendMsg(ResponseCode::AsecListResult, 1841 (const char*) li.lo_file_name, false); 1842 } 1843 close(fd); 1844 } 1845 } 1846 } 1847 endmntent(fp); 1848 return 0; 1849} 1850 1851extern "C" int vold_unmountAll(void) { 1852 VolumeManager *vm = VolumeManager::Instance(); 1853 return vm->unmountAll(); 1854} 1855 1856bool VolumeManager::isMountpointMounted(const char *mp) 1857{ 1858 FILE *fp = setmntent("/proc/mounts", "r"); 1859 if (fp == NULL) { 1860 SLOGE("Error opening /proc/mounts (%s)", strerror(errno)); 1861 return false; 1862 } 1863 1864 bool found_mp = false; 1865 mntent* mentry; 1866 while ((mentry = getmntent(fp)) != NULL) { 1867 if (strcmp(mentry->mnt_dir, mp) == 0) { 1868 found_mp = true; 1869 break; 1870 } 1871 } 1872 endmntent(fp); 1873 return found_mp; 1874} 1875 1876int VolumeManager::mkdirs(char* path) { 1877 // Only offer to create directories for paths managed by vold 1878 if (strncmp(path, "/storage/", 9) == 0) { 1879 // fs_mkdirs() does symlink checking and relative path enforcement 1880 return fs_mkdirs(path, 0700); 1881 } else { 1882 SLOGE("Failed to find mounted volume for %s", path); 1883 return -EINVAL; 1884 } 1885} 1886