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