int Volume::mountAsecExternal() { char legacy_path[PATH_MAX]; char secure_path[PATH_MAX]; snprintf(legacy_path, PATH_MAX, "%s/android_secure", getMountpoint()); snprintf(secure_path, PATH_MAX, "%s/.android_secure", getMountpoint()); // Recover legacy secure path if (!access(legacy_path, R_OK | X_OK) && access(secure_path, R_OK | X_OK)) { if (rename(legacy_path, secure_path)) { SLOGE("Failed to rename legacy asec dir (%s)", strerror(errno)); } } if (fs_prepare_dir(secure_path, 0770, AID_MEDIA_RW, AID_MEDIA_RW) != 0) { SLOGW("fs_prepare_dir failed: %s", strerror(errno)); return -1; } if (mount(secure_path, SEC_ASECDIR_EXT, "", MS_BIND, NULL)) { SLOGE("Failed to bind mount points %s -> %s (%s)", secure_path, SEC_ASECDIR_EXT, strerror(errno)); return -1; } return 0; }
static void run_sdcardfs(const std::string& source_path, const std::string& label, uid_t uid, gid_t gid, userid_t userid, bool multi_user, bool full_write, bool derive_gid) { std::string dest_path_default = "/mnt/runtime/default/" + label; std::string dest_path_read = "/mnt/runtime/read/" + label; std::string dest_path_write = "/mnt/runtime/write/" + label; umask(0); if (multi_user) { // Multi-user storage is fully isolated per user, so "other" // permissions are completely masked off. if (!sdcardfs_setup(source_path, dest_path_default, uid, gid, multi_user, userid, AID_SDCARD_RW, 0006, derive_gid) || !sdcardfs_setup_bind_remount(dest_path_default, dest_path_read, AID_EVERYBODY, 0027) || !sdcardfs_setup_bind_remount(dest_path_default, dest_path_write, AID_EVERYBODY, full_write ? 0007 : 0027)) { LOG(FATAL) << "failed to sdcardfs_setup"; } } else { // Physical storage is readable by all users on device, but // the Android directories are masked off to a single user // deep inside attr_from_stat(). if (!sdcardfs_setup(source_path, dest_path_default, uid, gid, multi_user, userid, AID_SDCARD_RW, 0006, derive_gid) || !sdcardfs_setup_bind_remount(dest_path_default, dest_path_read, AID_EVERYBODY, full_write ? 0027 : 0022) || !sdcardfs_setup_bind_remount(dest_path_default, dest_path_write, AID_EVERYBODY, full_write ? 0007 : 0022)) { LOG(FATAL) << "failed to sdcardfs_setup"; } } // Will abort if priv-dropping fails. drop_privs(uid, gid); if (multi_user) { std::string obb_path = source_path + "/obb"; fs_prepare_dir(obb_path.c_str(), 0775, uid, gid); } exit(0); }
int initialize_directories() { int res = -1; // Read current filesystem layout version to handle upgrade paths char version_path[PATH_MAX]; snprintf(version_path, PATH_MAX, "%s.layout_version", android_data_dir.path); int oldVersion; if (fs_read_atomic_int(version_path, &oldVersion) == -1) { oldVersion = 0; } int version = oldVersion; // /data/user char *user_data_dir = build_string2(android_data_dir.path, SECONDARY_USER_PREFIX); // /data/data char *legacy_data_dir = build_string2(android_data_dir.path, PRIMARY_USER_PREFIX); // /data/user/0 char *primary_data_dir = build_string3(android_data_dir.path, SECONDARY_USER_PREFIX, "0"); if (!user_data_dir || !legacy_data_dir || !primary_data_dir) { goto fail; } // Make the /data/user directory if necessary if (access(user_data_dir, R_OK) < 0) { if (mkdir(user_data_dir, 0711) < 0) { goto fail; } if (chown(user_data_dir, AID_SYSTEM, AID_SYSTEM) < 0) { goto fail; } if (chmod(user_data_dir, 0711) < 0) { goto fail; } } // Make the /data/user/0 symlink to /data/data if necessary if (access(primary_data_dir, R_OK) < 0) { if (symlink(legacy_data_dir, primary_data_dir)) { goto fail; } } if (version == 0) { // Introducing multi-user, so migrate /data/media contents into /data/media/0 ALOGD("Upgrading /data/media for multi-user"); // Ensure /data/media if (fs_prepare_dir(android_media_dir.path, 0770, AID_MEDIA_RW, AID_MEDIA_RW) == -1) { goto fail; } // /data/media.tmp char media_tmp_dir[PATH_MAX]; snprintf(media_tmp_dir, PATH_MAX, "%smedia.tmp", android_data_dir.path); // Only copy when upgrade not already in progress if (access(media_tmp_dir, F_OK) == -1) { if (rename(android_media_dir.path, media_tmp_dir) == -1) { ALOGE("Failed to move legacy media path: %s", strerror(errno)); goto fail; } } // Create /data/media again if (fs_prepare_dir(android_media_dir.path, 0770, AID_MEDIA_RW, AID_MEDIA_RW) == -1) { goto fail; } // /data/media/0 char owner_media_dir[PATH_MAX]; snprintf(owner_media_dir, PATH_MAX, "%s0", android_media_dir.path); // Move any owner data into place if (access(media_tmp_dir, F_OK) == 0) { if (rename(media_tmp_dir, owner_media_dir) == -1) { ALOGE("Failed to move owner media path: %s", strerror(errno)); goto fail; } } // Ensure media directories for any existing users DIR *dir; struct dirent *dirent; char user_media_dir[PATH_MAX]; dir = opendir(user_data_dir); if (dir != NULL) { while ((dirent = readdir(dir))) { if (dirent->d_type == DT_DIR) { const char *name = dirent->d_name; // skip "." and ".." if (name[0] == '.') { if (name[1] == 0) continue; if ((name[1] == '.') && (name[2] == 0)) continue; } // /data/media/<user_id> snprintf(user_media_dir, PATH_MAX, "%s%s", android_media_dir.path, name); if (fs_prepare_dir(user_media_dir, 0770, AID_MEDIA_RW, AID_MEDIA_RW) == -1) { goto fail; } } } closedir(dir); } version = 1; } // /data/media/obb char media_obb_dir[PATH_MAX]; snprintf(media_obb_dir, PATH_MAX, "%sobb", android_media_dir.path); if (version == 1) { // Introducing /data/media/obb for sharing OBB across users; migrate // any existing OBB files from owner. ALOGD("Upgrading to shared /data/media/obb"); // /data/media/0/Android/obb char owner_obb_path[PATH_MAX]; snprintf(owner_obb_path, PATH_MAX, "%s0/Android/obb", android_media_dir.path); // Only move if target doesn't already exist if (access(media_obb_dir, F_OK) != 0 && access(owner_obb_path, F_OK) == 0) { if (rename(owner_obb_path, media_obb_dir) == -1) { ALOGE("Failed to move OBB from owner: %s", strerror(errno)); goto fail; } } version = 2; } if (ensure_media_user_dirs(0) == -1) { ALOGE("Failed to setup media for user 0"); goto fail; } if (fs_prepare_dir(media_obb_dir, 0770, AID_MEDIA_RW, AID_MEDIA_RW) == -1) { goto fail; } // Persist layout version if changed if (version != oldVersion) { if (fs_write_atomic_int(version_path, version) == -1) { ALOGE("Failed to save version to %s: %s", version_path, strerror(errno)); goto fail; } } // Success! res = 0; fail: free(user_data_dir); free(legacy_data_dir); free(primary_data_dir); return res; }
status_t PublicVolume::doMount() { // TODO: expand to support mounting other filesystems readMetadata(); if (mFsType != "vfat") { LOG(ERROR) << getId() << " unsupported filesystem " << mFsType; return -EIO; } if (vfat::Check(mDevPath)) { LOG(ERROR) << getId() << " failed filesystem check"; return -EIO; } // Use UUID as stable name, if available std::string stableName = getId(); if (!mFsUuid.empty()) { stableName = mFsUuid; } mRawPath = StringPrintf("/mnt/media_rw/%s", stableName.c_str()); mFuseDefault = StringPrintf("/mnt/runtime/default/%s", stableName.c_str()); mFuseRead = StringPrintf("/mnt/runtime/read/%s", stableName.c_str()); mFuseWrite = StringPrintf("/mnt/runtime/write/%s", stableName.c_str()); setInternalPath(mRawPath); if (getMountFlags() & MountFlags::kVisible) { setPath(StringPrintf("/storage/%s", stableName.c_str())); } else { setPath(mRawPath); } if (fs_prepare_dir(mRawPath.c_str(), 0700, AID_ROOT, AID_ROOT) || fs_prepare_dir(mFuseDefault.c_str(), 0700, AID_ROOT, AID_ROOT) || fs_prepare_dir(mFuseRead.c_str(), 0700, AID_ROOT, AID_ROOT) || fs_prepare_dir(mFuseWrite.c_str(), 0700, AID_ROOT, AID_ROOT)) { PLOG(ERROR) << getId() << " failed to create mount points"; return -errno; } if (vfat::Mount(mDevPath, mRawPath, false, false, false, AID_MEDIA_RW, AID_MEDIA_RW, 0007, true)) { PLOG(ERROR) << getId() << " failed to mount " << mDevPath; return -EIO; } if (getMountFlags() & MountFlags::kPrimary) { initAsecStage(); } if (!(getMountFlags() & MountFlags::kVisible)) { // Not visible to apps, so no need to spin up FUSE return OK; } dev_t before = GetDevice(mFuseWrite); if (!(mFusePid = fork())) { if (getMountFlags() & MountFlags::kPrimary) { if (execl(kFusePath, kFusePath, "-u", "1023", // AID_MEDIA_RW "-g", "1023", // AID_MEDIA_RW "-U", std::to_string(getMountUserId()).c_str(), "-w", mRawPath.c_str(), stableName.c_str(), NULL)) { PLOG(ERROR) << "Failed to exec"; } } else { if (execl(kFusePath, kFusePath, "-u", "1023", // AID_MEDIA_RW "-g", "1023", // AID_MEDIA_RW "-U", std::to_string(getMountUserId()).c_str(), mRawPath.c_str(), stableName.c_str(), NULL)) { PLOG(ERROR) << "Failed to exec"; } } LOG(ERROR) << "FUSE exiting"; _exit(1); } if (mFusePid == -1) { PLOG(ERROR) << getId() << " failed to fork"; return -errno; } while (before == GetDevice(mFuseWrite)) { LOG(VERBOSE) << "Waiting for FUSE to spin up..."; usleep(50000); // 50ms } return OK; }
static void run(const char* source_path, const char* label, uid_t uid, gid_t gid, userid_t userid, bool multi_user, bool full_write) { struct fuse_global global; struct fuse fuse_default; struct fuse fuse_read; struct fuse fuse_write; struct fuse_handler handler_default; struct fuse_handler handler_read; struct fuse_handler handler_write; pthread_t thread_default; pthread_t thread_read; pthread_t thread_write; memset(&global, 0, sizeof(global)); memset(&fuse_default, 0, sizeof(fuse_default)); memset(&fuse_read, 0, sizeof(fuse_read)); memset(&fuse_write, 0, sizeof(fuse_write)); memset(&handler_default, 0, sizeof(handler_default)); memset(&handler_read, 0, sizeof(handler_read)); memset(&handler_write, 0, sizeof(handler_write)); pthread_mutex_init(&global.lock, NULL); global.package_to_appid = new AppIdMap; global.uid = uid; global.gid = gid; global.multi_user = multi_user; global.next_generation = 0; global.inode_ctr = 1; memset(&global.root, 0, sizeof(global.root)); global.root.nid = FUSE_ROOT_ID; /* 1 */ global.root.refcount = 2; global.root.namelen = strlen(source_path); global.root.name = strdup(source_path); global.root.userid = userid; global.root.uid = AID_ROOT; global.root.under_android = false; strcpy(global.source_path, source_path); if (multi_user) { global.root.perm = PERM_PRE_ROOT; snprintf(global.obb_path, sizeof(global.obb_path), "%s/obb", source_path); } else { global.root.perm = PERM_ROOT; snprintf(global.obb_path, sizeof(global.obb_path), "%s/Android/obb", source_path); } fuse_default.global = &global; fuse_read.global = &global; fuse_write.global = &global; global.fuse_default = &fuse_default; global.fuse_read = &fuse_read; global.fuse_write = &fuse_write; snprintf(fuse_default.dest_path, PATH_MAX, "/mnt/runtime/default/%s", label); snprintf(fuse_read.dest_path, PATH_MAX, "/mnt/runtime/read/%s", label); snprintf(fuse_write.dest_path, PATH_MAX, "/mnt/runtime/write/%s", label); handler_default.fuse = &fuse_default; handler_read.fuse = &fuse_read; handler_write.fuse = &fuse_write; handler_default.token = 0; handler_read.token = 1; handler_write.token = 2; umask(0); if (multi_user) { /* Multi-user storage is fully isolated per user, so "other" * permissions are completely masked off. */ if (fuse_setup(&fuse_default, AID_SDCARD_RW, 0006) || fuse_setup(&fuse_read, AID_EVERYBODY, 0027) || fuse_setup(&fuse_write, AID_EVERYBODY, full_write ? 0007 : 0027)) { PLOG(FATAL) << "failed to fuse_setup"; } } else { /* Physical storage is readable by all users on device, but * the Android directories are masked off to a single user * deep inside attr_from_stat(). */ if (fuse_setup(&fuse_default, AID_SDCARD_RW, 0006) || fuse_setup(&fuse_read, AID_EVERYBODY, full_write ? 0027 : 0022) || fuse_setup(&fuse_write, AID_EVERYBODY, full_write ? 0007 : 0022)) { PLOG(FATAL) << "failed to fuse_setup"; } } // Will abort if priv-dropping fails. drop_privs(uid, gid); if (multi_user) { fs_prepare_dir(global.obb_path, 0775, uid, gid); } if (pthread_create(&thread_default, NULL, start_handler, &handler_default) || pthread_create(&thread_read, NULL, start_handler, &handler_read) || pthread_create(&thread_write, NULL, start_handler, &handler_write)) { LOG(FATAL) << "failed to pthread_create"; } watch_package_list(&global); LOG(FATAL) << "terminated prematurely"; }