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