Home | History | Annotate | Download | only in vold
      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 <stdlib.h>
     18 #include <string.h>
     19 #include <dirent.h>
     20 #include <errno.h>
     21 #include <fcntl.h>
     22 
     23 #include <sys/types.h>
     24 #include <sys/stat.h>
     25 #include <sys/types.h>
     26 #include <sys/mman.h>
     27 #include <sys/mount.h>
     28 
     29 #include <linux/kdev_t.h>
     30 
     31 #include <cutils/properties.h>
     32 
     33 #include <diskconfig/diskconfig.h>
     34 
     35 #define LOG_TAG "Vold"
     36 
     37 #include <cutils/log.h>
     38 
     39 #include "Volume.h"
     40 #include "VolumeManager.h"
     41 #include "ResponseCode.h"
     42 #include "Fat.h"
     43 #include "Process.h"
     44 
     45 extern "C" void dos_partition_dec(void const *pp, struct dos_partition *d);
     46 extern "C" void dos_partition_enc(void *pp, struct dos_partition *d);
     47 
     48 
     49 /*
     50  * Secure directory - stuff that only root can see
     51  */
     52 const char *Volume::SECDIR            = "/mnt/secure";
     53 
     54 /*
     55  * Secure staging directory - where media is mounted for preparation
     56  */
     57 const char *Volume::SEC_STGDIR        = "/mnt/secure/staging";
     58 
     59 /*
     60  * Path to the directory on the media which contains publicly accessable
     61  * asec imagefiles. This path will be obscured before the mount is
     62  * exposed to non priviledged users.
     63  */
     64 const char *Volume::SEC_STG_SECIMGDIR = "/mnt/secure/staging/.android_secure";
     65 
     66 /*
     67  * Path to where *only* root can access asec imagefiles
     68  */
     69 const char *Volume::SEC_ASECDIR       = "/mnt/secure/asec";
     70 
     71 /*
     72  * Path to where secure containers are mounted
     73  */
     74 const char *Volume::ASECDIR           = "/mnt/asec";
     75 
     76 static const char *stateToStr(int state) {
     77     if (state == Volume::State_Init)
     78         return "Initializing";
     79     else if (state == Volume::State_NoMedia)
     80         return "No-Media";
     81     else if (state == Volume::State_Idle)
     82         return "Idle-Unmounted";
     83     else if (state == Volume::State_Pending)
     84         return "Pending";
     85     else if (state == Volume::State_Mounted)
     86         return "Mounted";
     87     else if (state == Volume::State_Unmounting)
     88         return "Unmounting";
     89     else if (state == Volume::State_Checking)
     90         return "Checking";
     91     else if (state == Volume::State_Formatting)
     92         return "Formatting";
     93     else if (state == Volume::State_Shared)
     94         return "Shared-Unmounted";
     95     else if (state == Volume::State_SharedMnt)
     96         return "Shared-Mounted";
     97     else
     98         return "Unknown-Error";
     99 }
    100 
    101 Volume::Volume(VolumeManager *vm, const char *label, const char *mount_point) {
    102     mVm = vm;
    103     mDebug = false;
    104     mLabel = strdup(label);
    105     mMountpoint = strdup(mount_point);
    106     mState = Volume::State_Init;
    107     mCurrentlyMountedKdev = -1;
    108 }
    109 
    110 Volume::~Volume() {
    111     free(mLabel);
    112     free(mMountpoint);
    113 }
    114 
    115 void Volume::protectFromAutorunStupidity() {
    116     char filename[255];
    117 
    118     snprintf(filename, sizeof(filename), "%s/autorun.inf", SEC_STGDIR);
    119     if (!access(filename, F_OK)) {
    120         SLOGW("Volume contains an autorun.inf! - removing");
    121         /*
    122          * Ensure the filename is all lower-case so
    123          * the process killer can find the inode.
    124          * Probably being paranoid here but meh.
    125          */
    126         rename(filename, filename);
    127         Process::killProcessesWithOpenFiles(filename, 2);
    128         if (unlink(filename)) {
    129             SLOGE("Failed to remove %s (%s)", filename, strerror(errno));
    130         }
    131     }
    132 }
    133 
    134 void Volume::setDebug(bool enable) {
    135     mDebug = enable;
    136 }
    137 
    138 dev_t Volume::getDiskDevice() {
    139     return MKDEV(0, 0);
    140 };
    141 
    142 void Volume::handleVolumeShared() {
    143 }
    144 
    145 void Volume::handleVolumeUnshared() {
    146 }
    147 
    148 int Volume::handleBlockEvent(NetlinkEvent *evt) {
    149     errno = ENOSYS;
    150     return -1;
    151 }
    152 
    153 void Volume::setState(int state) {
    154     char msg[255];
    155     int oldState = mState;
    156 
    157     if (oldState == state) {
    158         SLOGW("Duplicate state (%d)\n", state);
    159         return;
    160     }
    161 
    162     mState = state;
    163 
    164     SLOGD("Volume %s state changing %d (%s) -> %d (%s)", mLabel,
    165          oldState, stateToStr(oldState), mState, stateToStr(mState));
    166     snprintf(msg, sizeof(msg),
    167              "Volume %s %s state changed from %d (%s) to %d (%s)", getLabel(),
    168              getMountpoint(), oldState, stateToStr(oldState), mState,
    169              stateToStr(mState));
    170 
    171     mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeStateChange,
    172                                          msg, false);
    173 }
    174 
    175 int Volume::createDeviceNode(const char *path, int major, int minor) {
    176     mode_t mode = 0660 | S_IFBLK;
    177     dev_t dev = (major << 8) | minor;
    178     if (mknod(path, mode, dev) < 0) {
    179         if (errno != EEXIST) {
    180             return -1;
    181         }
    182     }
    183     return 0;
    184 }
    185 
    186 int Volume::formatVol() {
    187 
    188     if (getState() == Volume::State_NoMedia) {
    189         errno = ENODEV;
    190         return -1;
    191     } else if (getState() != Volume::State_Idle) {
    192         errno = EBUSY;
    193         return -1;
    194     }
    195 
    196     if (isMountpointMounted(getMountpoint())) {
    197         SLOGW("Volume is idle but appears to be mounted - fixing");
    198         setState(Volume::State_Mounted);
    199         // mCurrentlyMountedKdev = XXX
    200         errno = EBUSY;
    201         return -1;
    202     }
    203 
    204     char devicePath[255];
    205     dev_t diskNode = getDiskDevice();
    206     dev_t partNode = MKDEV(MAJOR(diskNode), 1); // XXX: Hmmm
    207 
    208     sprintf(devicePath, "/dev/block/vold/%d:%d",
    209             MAJOR(diskNode), MINOR(diskNode));
    210 
    211     if (mDebug) {
    212         SLOGI("Formatting volume %s (%s)", getLabel(), devicePath);
    213     }
    214     setState(Volume::State_Formatting);
    215 
    216     if (initializeMbr(devicePath)) {
    217         SLOGE("Failed to initialize MBR (%s)", strerror(errno));
    218         goto err;
    219     }
    220 
    221     sprintf(devicePath, "/dev/block/vold/%d:%d",
    222             MAJOR(partNode), MINOR(partNode));
    223 
    224     if (Fat::format(devicePath, 0)) {
    225         SLOGE("Failed to format (%s)", strerror(errno));
    226         goto err;
    227     }
    228 
    229     setState(Volume::State_Idle);
    230     return 0;
    231 err:
    232     return -1;
    233 }
    234 
    235 bool Volume::isMountpointMounted(const char *path) {
    236     char device[256];
    237     char mount_path[256];
    238     char rest[256];
    239     FILE *fp;
    240     char line[1024];
    241 
    242     if (!(fp = fopen("/proc/mounts", "r"))) {
    243         SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
    244         return false;
    245     }
    246 
    247     while(fgets(line, sizeof(line), fp)) {
    248         line[strlen(line)-1] = '\0';
    249         sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
    250         if (!strcmp(mount_path, path)) {
    251             fclose(fp);
    252             return true;
    253         }
    254 
    255     }
    256 
    257     fclose(fp);
    258     return false;
    259 }
    260 
    261 int Volume::mountVol() {
    262     dev_t deviceNodes[4];
    263     int n, i, rc = 0;
    264     char errmsg[255];
    265 
    266     if (getState() == Volume::State_NoMedia) {
    267         snprintf(errmsg, sizeof(errmsg),
    268                  "Volume %s %s mount failed - no media",
    269                  getLabel(), getMountpoint());
    270         mVm->getBroadcaster()->sendBroadcast(
    271                                          ResponseCode::VolumeMountFailedNoMedia,
    272                                          errmsg, false);
    273         errno = ENODEV;
    274         return -1;
    275     } else if (getState() != Volume::State_Idle) {
    276         errno = EBUSY;
    277         return -1;
    278     }
    279 
    280     if (isMountpointMounted(getMountpoint())) {
    281         SLOGW("Volume is idle but appears to be mounted - fixing");
    282         setState(Volume::State_Mounted);
    283         // mCurrentlyMountedKdev = XXX
    284         return 0;
    285     }
    286 
    287     n = getDeviceNodes((dev_t *) &deviceNodes, 4);
    288     if (!n) {
    289         SLOGE("Failed to get device nodes (%s)\n", strerror(errno));
    290         return -1;
    291     }
    292 
    293     for (i = 0; i < n; i++) {
    294         char devicePath[255];
    295 
    296         sprintf(devicePath, "/dev/block/vold/%d:%d", MAJOR(deviceNodes[i]),
    297                 MINOR(deviceNodes[i]));
    298 
    299         SLOGI("%s being considered for volume %s\n", devicePath, getLabel());
    300 
    301         errno = 0;
    302         setState(Volume::State_Checking);
    303 
    304         if (Fat::check(devicePath)) {
    305             if (errno == ENODATA) {
    306                 SLOGW("%s does not contain a FAT filesystem\n", devicePath);
    307                 continue;
    308             }
    309             errno = EIO;
    310             /* Badness - abort the mount */
    311             SLOGE("%s failed FS checks (%s)", devicePath, strerror(errno));
    312             setState(Volume::State_Idle);
    313             return -1;
    314         }
    315 
    316         /*
    317          * Mount the device on our internal staging mountpoint so we can
    318          * muck with it before exposing it to non priviledged users.
    319          */
    320         errno = 0;
    321         if (Fat::doMount(devicePath, "/mnt/secure/staging", false, false, 1000, 1015, 0702, true)) {
    322             SLOGE("%s failed to mount via VFAT (%s)\n", devicePath, strerror(errno));
    323             continue;
    324         }
    325 
    326         SLOGI("Device %s, target %s mounted @ /mnt/secure/staging", devicePath, getMountpoint());
    327 
    328         protectFromAutorunStupidity();
    329 
    330         if (createBindMounts()) {
    331             SLOGE("Failed to create bindmounts (%s)", strerror(errno));
    332             umount("/mnt/secure/staging");
    333             setState(Volume::State_Idle);
    334             return -1;
    335         }
    336 
    337         /*
    338          * Now that the bindmount trickery is done, atomically move the
    339          * whole subtree to expose it to non priviledged users.
    340          */
    341         if (doMoveMount("/mnt/secure/staging", getMountpoint(), false)) {
    342             SLOGE("Failed to move mount (%s)", strerror(errno));
    343             umount("/mnt/secure/staging");
    344             setState(Volume::State_Idle);
    345             return -1;
    346         }
    347         setState(Volume::State_Mounted);
    348         mCurrentlyMountedKdev = deviceNodes[i];
    349         return 0;
    350     }
    351 
    352     SLOGE("Volume %s found no suitable devices for mounting :(\n", getLabel());
    353     setState(Volume::State_Idle);
    354 
    355     return -1;
    356 }
    357 
    358 int Volume::createBindMounts() {
    359     unsigned long flags;
    360 
    361     /*
    362      * Rename old /android_secure -> /.android_secure
    363      */
    364     if (!access("/mnt/secure/staging/android_secure", R_OK | X_OK) &&
    365          access(SEC_STG_SECIMGDIR, R_OK | X_OK)) {
    366         if (rename("/mnt/secure/staging/android_secure", SEC_STG_SECIMGDIR)) {
    367             SLOGE("Failed to rename legacy asec dir (%s)", strerror(errno));
    368         }
    369     }
    370 
    371     /*
    372      * Ensure that /android_secure exists and is a directory
    373      */
    374     if (access(SEC_STG_SECIMGDIR, R_OK | X_OK)) {
    375         if (errno == ENOENT) {
    376             if (mkdir(SEC_STG_SECIMGDIR, 0777)) {
    377                 SLOGE("Failed to create %s (%s)", SEC_STG_SECIMGDIR, strerror(errno));
    378                 return -1;
    379             }
    380         } else {
    381             SLOGE("Failed to access %s (%s)", SEC_STG_SECIMGDIR, strerror(errno));
    382             return -1;
    383         }
    384     } else {
    385         struct stat sbuf;
    386 
    387         if (stat(SEC_STG_SECIMGDIR, &sbuf)) {
    388             SLOGE("Failed to stat %s (%s)", SEC_STG_SECIMGDIR, strerror(errno));
    389             return -1;
    390         }
    391         if (!S_ISDIR(sbuf.st_mode)) {
    392             SLOGE("%s is not a directory", SEC_STG_SECIMGDIR);
    393             errno = ENOTDIR;
    394             return -1;
    395         }
    396     }
    397 
    398     /*
    399      * Bind mount /mnt/secure/staging/android_secure -> /mnt/secure/asec so we'll
    400      * have a root only accessable mountpoint for it.
    401      */
    402     if (mount(SEC_STG_SECIMGDIR, SEC_ASECDIR, "", MS_BIND, NULL)) {
    403         SLOGE("Failed to bind mount points %s -> %s (%s)",
    404                 SEC_STG_SECIMGDIR, SEC_ASECDIR, strerror(errno));
    405         return -1;
    406     }
    407 
    408     /*
    409      * Mount a read-only, zero-sized tmpfs  on <mountpoint>/android_secure to
    410      * obscure the underlying directory from everybody - sneaky eh? ;)
    411      */
    412     if (mount("tmpfs", SEC_STG_SECIMGDIR, "tmpfs", MS_RDONLY, "size=0,mode=000,uid=0,gid=0")) {
    413         SLOGE("Failed to obscure %s (%s)", SEC_STG_SECIMGDIR, strerror(errno));
    414         umount("/mnt/asec_secure");
    415         return -1;
    416     }
    417 
    418     return 0;
    419 }
    420 
    421 int Volume::doMoveMount(const char *src, const char *dst, bool force) {
    422     unsigned int flags = MS_MOVE;
    423     int retries = 5;
    424 
    425     while(retries--) {
    426         if (!mount(src, dst, "", flags, NULL)) {
    427             if (mDebug) {
    428                 SLOGD("Moved mount %s -> %s sucessfully", src, dst);
    429             }
    430             return 0;
    431         } else if (errno != EBUSY) {
    432             SLOGE("Failed to move mount %s -> %s (%s)", src, dst, strerror(errno));
    433             return -1;
    434         }
    435         int action = 0;
    436 
    437         if (force) {
    438             if (retries == 1) {
    439                 action = 2; // SIGKILL
    440             } else if (retries == 2) {
    441                 action = 1; // SIGHUP
    442             }
    443         }
    444         SLOGW("Failed to move %s -> %s (%s, retries %d, action %d)",
    445                 src, dst, strerror(errno), retries, action);
    446         Process::killProcessesWithOpenFiles(src, action);
    447         usleep(1000*250);
    448     }
    449 
    450     errno = EBUSY;
    451     SLOGE("Giving up on move %s -> %s (%s)", src, dst, strerror(errno));
    452     return -1;
    453 }
    454 
    455 int Volume::doUnmount(const char *path, bool force) {
    456     int retries = 10;
    457 
    458     if (mDebug) {
    459         SLOGD("Unmounting {%s}, force = %d", path, force);
    460     }
    461 
    462     while (retries--) {
    463         if (!umount(path) || errno == EINVAL || errno == ENOENT) {
    464             SLOGI("%s sucessfully unmounted", path);
    465             return 0;
    466         }
    467 
    468         int action = 0;
    469 
    470         if (force) {
    471             if (retries == 1) {
    472                 action = 2; // SIGKILL
    473             } else if (retries == 2) {
    474                 action = 1; // SIGHUP
    475             }
    476         }
    477 
    478         SLOGW("Failed to unmount %s (%s, retries %d, action %d)",
    479                 path, strerror(errno), retries, action);
    480 
    481         Process::killProcessesWithOpenFiles(path, action);
    482         usleep(1000*1000);
    483     }
    484     errno = EBUSY;
    485     SLOGE("Giving up on unmount %s (%s)", path, strerror(errno));
    486     return -1;
    487 }
    488 
    489 int Volume::unmountVol(bool force) {
    490     int i, rc;
    491 
    492     if (getState() != Volume::State_Mounted) {
    493         SLOGE("Volume %s unmount request when not mounted", getLabel());
    494         errno = EINVAL;
    495         return -1;
    496     }
    497 
    498     setState(Volume::State_Unmounting);
    499     usleep(1000 * 1000); // Give the framework some time to react
    500 
    501     /*
    502      * First move the mountpoint back to our internal staging point
    503      * so nobody else can muck with it while we work.
    504      */
    505     if (doMoveMount(getMountpoint(), SEC_STGDIR, force)) {
    506         SLOGE("Failed to move mount %s => %s (%s)", getMountpoint(), SEC_STGDIR, strerror(errno));
    507         setState(Volume::State_Mounted);
    508         return -1;
    509     }
    510 
    511     protectFromAutorunStupidity();
    512 
    513     /*
    514      * Unmount the tmpfs which was obscuring the asec image directory
    515      * from non root users
    516      */
    517 
    518     if (doUnmount(Volume::SEC_STG_SECIMGDIR, force)) {
    519         SLOGE("Failed to unmount tmpfs on %s (%s)", SEC_STG_SECIMGDIR, strerror(errno));
    520         goto fail_republish;
    521     }
    522 
    523     /*
    524      * Remove the bindmount we were using to keep a reference to
    525      * the previously obscured directory.
    526      */
    527 
    528     if (doUnmount(Volume::SEC_ASECDIR, force)) {
    529         SLOGE("Failed to remove bindmount on %s (%s)", SEC_ASECDIR, strerror(errno));
    530         goto fail_remount_tmpfs;
    531     }
    532 
    533     /*
    534      * Finally, unmount the actual block device from the staging dir
    535      */
    536     if (doUnmount(Volume::SEC_STGDIR, force)) {
    537         SLOGE("Failed to unmount %s (%s)", SEC_STGDIR, strerror(errno));
    538         goto fail_recreate_bindmount;
    539     }
    540 
    541     SLOGI("%s unmounted sucessfully", getMountpoint());
    542 
    543     setState(Volume::State_Idle);
    544     mCurrentlyMountedKdev = -1;
    545     return 0;
    546 
    547     /*
    548      * Failure handling - try to restore everything back the way it was
    549      */
    550 fail_recreate_bindmount:
    551     if (mount(SEC_STG_SECIMGDIR, SEC_ASECDIR, "", MS_BIND, NULL)) {
    552         SLOGE("Failed to restore bindmount after failure! - Storage will appear offline!");
    553         goto out_nomedia;
    554     }
    555 fail_remount_tmpfs:
    556     if (mount("tmpfs", SEC_STG_SECIMGDIR, "tmpfs", MS_RDONLY, "size=0,mode=0,uid=0,gid=0")) {
    557         SLOGE("Failed to restore tmpfs after failure! - Storage will appear offline!");
    558         goto out_nomedia;
    559     }
    560 fail_republish:
    561     if (doMoveMount(SEC_STGDIR, getMountpoint(), force)) {
    562         SLOGE("Failed to republish mount after failure! - Storage will appear offline!");
    563         goto out_nomedia;
    564     }
    565 
    566     setState(Volume::State_Mounted);
    567     return -1;
    568 
    569 out_nomedia:
    570     setState(Volume::State_NoMedia);
    571     return -1;
    572 }
    573 
    574 int Volume::initializeMbr(const char *deviceNode) {
    575     struct disk_info dinfo;
    576 
    577     memset(&dinfo, 0, sizeof(dinfo));
    578 
    579     if (!(dinfo.part_lst = (struct part_info *) malloc(MAX_NUM_PARTS * sizeof(struct part_info)))) {
    580         SLOGE("Failed to malloc prt_lst");
    581         return -1;
    582     }
    583 
    584     memset(dinfo.part_lst, 0, MAX_NUM_PARTS * sizeof(struct part_info));
    585     dinfo.device = strdup(deviceNode);
    586     dinfo.scheme = PART_SCHEME_MBR;
    587     dinfo.sect_size = 512;
    588     dinfo.skip_lba = 2048;
    589     dinfo.num_lba = 0;
    590     dinfo.num_parts = 1;
    591 
    592     struct part_info *pinfo = &dinfo.part_lst[0];
    593 
    594     pinfo->name = strdup("android_sdcard");
    595     pinfo->flags |= PART_ACTIVE_FLAG;
    596     pinfo->type = PC_PART_TYPE_FAT32;
    597     pinfo->len_kb = -1;
    598 
    599     int rc = apply_disk_config(&dinfo, 0);
    600 
    601     if (rc) {
    602         SLOGE("Failed to apply disk configuration (%d)", rc);
    603         goto out;
    604     }
    605 
    606  out:
    607     free(pinfo->name);
    608     free(dinfo.device);
    609     free(dinfo.part_lst);
    610 
    611     return rc;
    612 }
    613