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