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