• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
69 using android::base::StringPrintf;
70 
71 /*
72  * Path to external storage where *only* root can access ASEC image files
73  */
74 const char *VolumeManager::SEC_ASECDIR_EXT   = "/mnt/secure/asec";
75 
76 /*
77  * Path to internal storage where *only* root can access ASEC image files
78  */
79 const char *VolumeManager::SEC_ASECDIR_INT   = "/data/app-asec";
80 
81 /*
82  * Path to where secure containers are mounted
83  */
84 const char *VolumeManager::ASECDIR           = "/mnt/asec";
85 
86 /*
87  * Path to where OBBs are mounted
88  */
89 const char *VolumeManager::LOOPDIR           = "/mnt/obb";
90 
91 static const char* kUserMountPath = "/mnt/user";
92 
93 static const unsigned int kMajorBlockMmc = 179;
94 
95 /* writes superblock at end of file or device given by name */
writeSuperBlock(const char * name,struct asec_superblock * sb,unsigned int numImgSectors)96 static 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 
adjustSectorNumExt4(unsigned numSectors)118 static 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 
adjustSectorNumFAT(unsigned numSectors)128 static 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 
setupLoopDevice(char * buffer,size_t len,const char * asecFileName,const char * idHash,bool debug)140 static 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 
setupDevMapperDevice(char * buffer,size_t len,const char * loopDevice,const char * asecFileName,const char * key,const char * idHash,int numImgSectors,bool * createdDMDevice,bool debug)157 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) {
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 
waitForDevMapper(const char * dmDevice)181 static 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 
196 VolumeManager *VolumeManager::sInstance = NULL;
197 
Instance()198 VolumeManager *VolumeManager::Instance() {
199     if (!sInstance)
200         sInstance = new VolumeManager();
201     return sInstance;
202 }
203 
VolumeManager()204 VolumeManager::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 
~VolumeManager()214 VolumeManager::~VolumeManager() {
215     delete mActiveContainers;
216 }
217 
asecHash(const char * id,char * buffer,size_t len)218 char *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 
setDebug(bool enable)250 int VolumeManager::setDebug(bool enable) {
251     mDebug = enable;
252     return 0;
253 }
254 
start()255 int 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 
stop()270 int VolumeManager::stop() {
271     CHECK(mInternalEmulated != nullptr);
272     mInternalEmulated->destroy();
273     mInternalEmulated = nullptr;
274     return 0;
275 }
276 
handleBlockEvent(NetlinkEvent * evt)277 void 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 
addDiskSource(const std::shared_ptr<DiskSource> & diskSource)346 void VolumeManager::addDiskSource(const std::shared_ptr<DiskSource>& diskSource) {
347     mDiskSources.push_back(diskSource);
348 }
349 
findDisk(const std::string & id)350 std::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 
findVolume(const std::string & id)359 std::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 
listVolumes(android::vold::VolumeBase::Type type,std::list<std::string> & list)372 void 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 
benchmarkPrivate(const std::string & id)380 nsecs_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 
forgetPartition(const std::string & partGuid)399 int 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 
linkPrimary(userid_t userId)415 int 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 
onUserAdded(userid_t userId,int userSerialNumber)437 int VolumeManager::onUserAdded(userid_t userId, int userSerialNumber) {
438     mAddedUsers[userId] = userSerialNumber;
439     return 0;
440 }
441 
onUserRemoved(userid_t userId)442 int VolumeManager::onUserRemoved(userid_t userId) {
443     mAddedUsers.erase(userId);
444     return 0;
445 }
446 
onUserStarted(userid_t userId)447 int 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 
onUserStopped(userid_t userId)461 int VolumeManager::onUserStopped(userid_t userId) {
462     mStartedUsers.erase(userId);
463     return 0;
464 }
465 
setPrimary(const std::shared_ptr<android::vold::VolumeBase> & vol)466 int 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 
sane_readlinkat(int dirfd,const char * path,char * buf,size_t bufsiz)474 static 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 
unmount_tree(const char * path)486 static 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 
remountUid(uid_t uid,const std::string & mode)514 int 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 
619 next:
620         close(nsFd);
621         close(pidFd);
622     }
623     closedir(dir);
624     return 0;
625 }
626 
reset()627 int 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 
shutdown()641 int VolumeManager::shutdown() {
642     mInternalEmulated->destroy();
643     for (auto disk : mDisks) {
644         disk->destroy();
645     }
646     mDisks.clear();
647     return 0;
648 }
649 
unmountAll()650 int 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 
getObbMountPath(const char * sourceFile,char * mountPath,int mountPathLen)689 int 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 
getAsecMountPath(const char * id,char * buffer,int maxlen)711 int 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 
getAsecFilesystemPath(const char * id,char * buffer,int maxlen)741 int 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 
createAsec(const char * id,unsigned int numSectors,const char * fstype,const char * key,const int ownerUid,bool isExternal)770 int 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 
resizeAsec(const char * id,unsigned numSectors,const char * key)964 int 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;
1102 fail:
1103     Loop::resizeImageFile(asecFileName, oldNumSec);
1104     return -1;
1105 }
1106 
finalizeAsec(const char * id)1107 int 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 
fixupAsecPermissions(const char * id,gid_t gid,const char * filename)1167 int 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 
renameAsec(const char * id1,const char * id2)1295 int 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 
1359 out_err:
1360     free(asecFilename2);
1361     return -1;
1362 }
1363 
1364 #define UNMOUNT_RETRIES 5
1365 #define UNMOUNT_SLEEP_BETWEEN_RETRY_MS (1000 * 1000)
unmountAsec(const char * id,bool force)1366 int 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 
unmountObb(const char * fileName,bool force)1396 int 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 
unmountLoopImage(const char * id,const char * idHash,const char * fileName,const char * mountPoint,bool force)1414 int 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 
destroyAsec(const char * id,bool force)1502 int 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  */
isLegalAsecId(const char * id) const1549 bool 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 
isAsecInDirectory(const char * dir,const char * asecName) const1576 bool 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 
findAsec(const char * id,char * asecPath,size_t asecPathLen,const char ** directory) const1592 int 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 
mountAsec(const char * id,const char * key,int ownerUid,bool readOnly)1634 int 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  */
mountObb(const char * img,const char * key,int ownerGid)1741 int 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 
listMountedObbs(SocketClient * cli)1825 int 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 
vold_unmountAll(void)1857 extern "C" int vold_unmountAll(void) {
1858     VolumeManager *vm = VolumeManager::Instance();
1859     return vm->unmountAll();
1860 }
1861 
isMountpointMounted(const char * mp)1862 bool 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 
mkdirs(char * path)1882 int 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