blob: 86e3fd4cd0ab798433ae7a12f7512a4d30b901c9 [file] [log] [blame]
San Mehatf1b736b2009-10-10 17:22:08 -07001/*
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
Yabin Cuid1104f72015-01-02 13:28:28 -080017#include <dirent.h>
San Mehatf1b736b2009-10-10 17:22:08 -070018#include <errno.h>
San Mehata2677e42009-12-13 10:40:18 -080019#include <fcntl.h>
Kenny Root344ca102012-04-03 17:23:01 -070020#include <fts.h>
Yabin Cuid1104f72015-01-02 13:28:28 -080021#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>
San Mehata19b2502010-01-06 10:33:53 -080027#include <sys/stat.h>
28#include <sys/types.h>
Yabin Cuid1104f72015-01-02 13:28:28 -080029#include <unistd.h>
San Mehata19b2502010-01-06 10:33:53 -080030
San Mehata2677e42009-12-13 10:40:18 -080031#include <linux/kdev_t.h>
San Mehatf1b736b2009-10-10 17:22:08 -070032
33#define LOG_TAG "Vold"
34
Kenny Root7b18a7b2010-03-15 13:13:41 -070035#include <openssl/md5.h>
36
Jeff Sharkey36801cc2015-03-13 16:09:20 -070037#include <base/logging.h>
38#include <base/stringprintf.h>
Jeff Sharkey71ebe152013-09-17 17:24:38 -070039#include <cutils/fs.h>
San Mehatf1b736b2009-10-10 17:22:08 -070040#include <cutils/log.h>
41
Robert Craigb9e3ba52014-02-04 10:53:00 -050042#include <selinux/android.h>
43
San Mehatfd7f5872009-10-12 11:32:47 -070044#include <sysutils/NetlinkEvent.h>
45
Kenny Root344ca102012-04-03 17:23:01 -070046#include <private/android_filesystem_config.h>
47
Jeff Sharkey36801cc2015-03-13 16:09:20 -070048#include "EmulatedVolume.h"
San Mehatf1b736b2009-10-10 17:22:08 -070049#include "VolumeManager.h"
Jeff Sharkey36801cc2015-03-13 16:09:20 -070050#include "NetlinkManager.h"
San Mehata2677e42009-12-13 10:40:18 -080051#include "ResponseCode.h"
San Mehata19b2502010-01-06 10:33:53 -080052#include "Loop.h"
Kenny Root344ca102012-04-03 17:23:01 -070053#include "Ext4.h"
San Mehata19b2502010-01-06 10:33:53 -080054#include "Fat.h"
Jeff Sharkey36801cc2015-03-13 16:09:20 -070055#include "Utils.h"
San Mehatb78a32c2010-01-10 13:02:12 -080056#include "Devmapper.h"
San Mehat586536c2010-02-16 17:12:00 -080057#include "Process.h"
San Mehatfcf24fe2010-03-03 12:37:32 -080058#include "Asec.h"
Hiroaki Miyazawa14eab552015-02-04 13:29:15 +090059#include "VoldUtil.h"
Ken Sumrall29d8da82011-05-18 17:20:07 -070060#include "cryptfs.h"
San Mehat23969932010-01-09 07:08:06 -080061
Jeff Sharkey36801cc2015-03-13 16:09:20 -070062#define DEBUG_NETLINK 0
63
Mike Lockwood97f2fc12011-06-07 10:51:38 -070064#define MASS_STORAGE_FILE_PATH "/sys/class/android_usb/android0/f_mass_storage/lun/file"
65
Daniel Rosenberg6a74dca2014-05-23 13:47:00 -070066#define ROUND_UP_POWER_OF_2(number, po2) (((!!(number & ((1U << po2) - 1))) << po2)\
67 + (number & (~((1U << po2) - 1))))
68
Jeff Sharkey36801cc2015-03-13 16:09:20 -070069using android::base::StringPrintf;
70
Jeff Sharkey9f18fe72015-04-01 23:32:18 -070071/*
72 * Path to external storage where *only* root can access ASEC image files
73 */
74const char *VolumeManager::SEC_ASECDIR_EXT = "/mnt/secure/asec";
75
76/*
77 * Path to internal storage where *only* root can access ASEC image files
78 */
79const char *VolumeManager::SEC_ASECDIR_INT = "/data/app-asec";
80
81/*
82 * Path to where secure containers are mounted
83 */
84const char *VolumeManager::ASECDIR = "/mnt/asec";
85
86/*
87 * Path to where OBBs are mounted
88 */
89const char *VolumeManager::LOOPDIR = "/mnt/obb";
90
Jeff Sharkey36801cc2015-03-13 16:09:20 -070091static const char* kUserMountPath = "/mnt/user";
92
93static const unsigned int kMajorBlockScsi = 8;
94static const unsigned int kMajorBlockMmc = 179;
95
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -070096/* writes superblock at end of file or device given by name */
97static int writeSuperBlock(const char* name, struct asec_superblock *sb, unsigned int numImgSectors) {
Jeff Sharkeyce6a9132015-04-08 21:07:21 -070098 int sbfd = open(name, O_RDWR | O_CLOEXEC);
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -070099 if (sbfd < 0) {
100 SLOGE("Failed to open %s for superblock write (%s)", name, strerror(errno));
101 return -1;
102 }
103
104 if (lseek(sbfd, (numImgSectors * 512), SEEK_SET) < 0) {
105 SLOGE("Failed to lseek for superblock (%s)", strerror(errno));
106 close(sbfd);
107 return -1;
108 }
109
110 if (write(sbfd, sb, sizeof(struct asec_superblock)) != sizeof(struct asec_superblock)) {
111 SLOGE("Failed to write superblock (%s)", strerror(errno));
112 close(sbfd);
113 return -1;
114 }
115 close(sbfd);
116 return 0;
117}
118
119static int adjustSectorNumExt4(unsigned numSectors) {
Daniel Rosenberge9196fe2014-06-10 17:16:03 -0700120 // Ext4 started to reserve 2% or 4096 clusters, whichever is smaller for
121 // preventing costly operations or unexpected ENOSPC error.
122 // Ext4::format() uses default block size without clustering.
123 unsigned clusterSectors = 4096 / 512;
124 unsigned reservedSectors = (numSectors * 2)/100 + (numSectors % 50 > 0);
125 numSectors += reservedSectors > (4096 * clusterSectors) ? (4096 * clusterSectors) : reservedSectors;
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -0700126 return ROUND_UP_POWER_OF_2(numSectors, 3);
127}
128
129static int adjustSectorNumFAT(unsigned numSectors) {
130 /*
131 * Add some headroom
132 */
133 unsigned fatSize = (((numSectors * 4) / 512) + 1) * 2;
134 numSectors += fatSize + 2;
135 /*
136 * FAT is aligned to 32 kb with 512b sectors.
137 */
138 return ROUND_UP_POWER_OF_2(numSectors, 6);
139}
140
141static int setupLoopDevice(char* buffer, size_t len, const char* asecFileName, const char* idHash, bool debug) {
142 if (Loop::lookupActive(idHash, buffer, len)) {
143 if (Loop::create(idHash, asecFileName, buffer, len)) {
144 SLOGE("ASEC loop device creation failed for %s (%s)", asecFileName, strerror(errno));
145 return -1;
146 }
147 if (debug) {
148 SLOGD("New loop device created at %s", buffer);
149 }
150 } else {
151 if (debug) {
152 SLOGD("Found active loopback for %s at %s", asecFileName, buffer);
153 }
154 }
155 return 0;
156}
157
158static 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) {
159 if (strcmp(key, "none")) {
160 if (Devmapper::lookupActive(idHash, buffer, len)) {
161 if (Devmapper::create(idHash, loopDevice, key, numImgSectors,
162 buffer, len)) {
163 SLOGE("ASEC device mapping failed for %s (%s)", asecFileName, strerror(errno));
164 return -1;
165 }
166 if (debug) {
167 SLOGD("New devmapper instance created at %s", buffer);
168 }
169 } else {
170 if (debug) {
171 SLOGD("Found active devmapper for %s at %s", asecFileName, buffer);
172 }
173 }
174 *createdDMDevice = true;
175 } else {
176 strcpy(buffer, loopDevice);
177 *createdDMDevice = false;
178 }
179 return 0;
180}
181
182static void waitForDevMapper(const char *dmDevice) {
183 /*
184 * Wait for the device mapper node to be created. Sometimes it takes a
185 * while. Wait for up to 1 second. We could also inspect incoming uevents,
186 * but that would take more effort.
187 */
188 int tries = 25;
189 while (tries--) {
190 if (!access(dmDevice, F_OK) || errno != ENOENT) {
191 break;
192 }
193 usleep(40 * 1000);
194 }
195}
196
San Mehatf1b736b2009-10-10 17:22:08 -0700197VolumeManager *VolumeManager::sInstance = NULL;
198
199VolumeManager *VolumeManager::Instance() {
200 if (!sInstance)
201 sInstance = new VolumeManager();
202 return sInstance;
203}
204
205VolumeManager::VolumeManager() {
San Mehatd9a4e352010-03-12 13:32:47 -0800206 mDebug = false;
San Mehat88705162010-01-15 09:26:28 -0800207 mActiveContainers = new AsecIdCollection();
San Mehatf1b736b2009-10-10 17:22:08 -0700208 mBroadcaster = NULL;
Mike Lockwooda28056b2010-10-28 15:21:24 -0400209 mUmsSharingCount = 0;
210 mSavedDirtyRatio = -1;
211 // set dirty ratio to 0 when UMS is active
212 mUmsDirtyRatio = 0;
San Mehatf1b736b2009-10-10 17:22:08 -0700213}
214
215VolumeManager::~VolumeManager() {
San Mehat88705162010-01-15 09:26:28 -0800216 delete mActiveContainers;
San Mehatf1b736b2009-10-10 17:22:08 -0700217}
218
Kenny Root7b18a7b2010-03-15 13:13:41 -0700219char *VolumeManager::asecHash(const char *id, char *buffer, size_t len) {
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700220 static const char* digits = "0123456789abcdef";
221
Kenny Root7b18a7b2010-03-15 13:13:41 -0700222 unsigned char sig[MD5_DIGEST_LENGTH];
223
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700224 if (buffer == NULL) {
225 SLOGE("Destination buffer is NULL");
226 errno = ESPIPE;
227 return NULL;
228 } else if (id == NULL) {
229 SLOGE("Source buffer is NULL");
230 errno = ESPIPE;
231 return NULL;
232 } else if (len < MD5_ASCII_LENGTH_PLUS_NULL) {
Colin Cross59846b62014-02-06 20:34:29 -0800233 SLOGE("Target hash buffer size < %d bytes (%zu)",
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700234 MD5_ASCII_LENGTH_PLUS_NULL, len);
San Mehatd9a4e352010-03-12 13:32:47 -0800235 errno = ESPIPE;
236 return NULL;
237 }
Kenny Root7b18a7b2010-03-15 13:13:41 -0700238
239 MD5(reinterpret_cast<const unsigned char*>(id), strlen(id), sig);
San Mehatd9a4e352010-03-12 13:32:47 -0800240
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700241 char *p = buffer;
Kenny Root7b18a7b2010-03-15 13:13:41 -0700242 for (int i = 0; i < MD5_DIGEST_LENGTH; i++) {
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700243 *p++ = digits[sig[i] >> 4];
244 *p++ = digits[sig[i] & 0x0F];
San Mehatd9a4e352010-03-12 13:32:47 -0800245 }
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700246 *p = '\0';
San Mehatd9a4e352010-03-12 13:32:47 -0800247
248 return buffer;
249}
250
251void VolumeManager::setDebug(bool enable) {
252 mDebug = enable;
San Mehatd9a4e352010-03-12 13:32:47 -0800253}
254
San Mehatf1b736b2009-10-10 17:22:08 -0700255int VolumeManager::start() {
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700256 // Always start from a clean slate by unmounting everything in
257 // directories that we own, in case we crashed.
Jeff Sharkey9c484982015-03-31 10:35:33 -0700258 unmountAll();
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700259
260 // Assume that we always have an emulated volume on internal
261 // storage; the framework will decide if it should be mounted.
262 mInternalEmulated = std::shared_ptr<android::vold::VolumeBase>(
Jeff Sharkey3161fb32015-04-12 16:03:33 -0700263 new android::vold::EmulatedVolume("/data/media"));
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700264 mInternalEmulated->create();
265
San Mehatf1b736b2009-10-10 17:22:08 -0700266 return 0;
267}
268
269int VolumeManager::stop() {
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700270 mInternalEmulated->destroy();
271 mInternalEmulated = nullptr;
San Mehatf1b736b2009-10-10 17:22:08 -0700272 return 0;
273}
274
San Mehatfd7f5872009-10-12 11:32:47 -0700275void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700276#if DEBUG_NETLINK
277 LOG(VERBOSE) << "handleBlockEvent with action " << (int) evt->getAction();
278 evt->dump();
Tim Murray8439dc92014-12-15 11:56:11 -0800279#endif
San Mehatf1b736b2009-10-10 17:22:08 -0700280
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700281 std::string eventPath(evt->findParam("DEVPATH"));
282 std::string devType(evt->findParam("DEVTYPE"));
283
284 if (devType != "disk") return;
285
286 int major = atoi(evt->findParam("MAJOR"));
287 int minor = atoi(evt->findParam("MINOR"));
288 dev_t device = makedev(major, minor);
289
290 switch (evt->getAction()) {
291 case NetlinkEvent::Action::kAdd: {
292 for (auto source : mDiskSources) {
293 if (source->matches(eventPath)) {
294 // For now, assume that MMC devices are SD, and that
295 // everything else is USB
296 int flags = source->getFlags();
297 if (major == kMajorBlockMmc) {
298 flags |= android::vold::Disk::Flags::kSd;
299 } else {
300 flags |= android::vold::Disk::Flags::kUsb;
301 }
302
303 auto disk = new android::vold::Disk(eventPath, device,
304 source->getNickname(), flags);
305 disk->create();
306 mDisks.push_back(std::shared_ptr<android::vold::Disk>(disk));
307 break;
308 }
309 }
310 break;
311 }
312 case NetlinkEvent::Action::kChange: {
313 for (auto disk : mDisks) {
314 if (disk->getDevice() == device) {
315 disk->readMetadata();
316 disk->readPartitions();
317 }
318 }
319 break;
320 }
321 case NetlinkEvent::Action::kRemove: {
322 auto i = mDisks.begin();
323 while (i != mDisks.end()) {
324 if ((*i)->getDevice() == device) {
325 (*i)->destroy();
326 i = mDisks.erase(i);
327 } else {
328 ++i;
329 }
330 }
331 break;
332 }
333 default: {
334 LOG(WARNING) << "Unexpected block event action " << (int) evt->getAction();
335 break;
336 }
337 }
338}
339
340void VolumeManager::addDiskSource(const std::shared_ptr<DiskSource>& diskSource) {
341 mDiskSources.push_back(diskSource);
342}
343
344std::shared_ptr<android::vold::Disk> VolumeManager::findDisk(const std::string& id) {
345 for (auto disk : mDisks) {
346 if (disk->getId() == id) {
347 return disk;
San Mehatf1b736b2009-10-10 17:22:08 -0700348 }
349 }
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700350 return nullptr;
351}
San Mehatf1b736b2009-10-10 17:22:08 -0700352
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700353std::shared_ptr<android::vold::VolumeBase> VolumeManager::findVolume(const std::string& id) {
354 if (mInternalEmulated->getId() == id) {
355 return mInternalEmulated;
San Mehatf1b736b2009-10-10 17:22:08 -0700356 }
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700357 for (auto disk : mDisks) {
358 auto vol = disk->findVolume(id);
359 if (vol != nullptr) {
360 return vol;
361 }
362 }
363 return nullptr;
364}
365
366int VolumeManager::linkPrimary(userid_t userId) {
367 std::string source(mPrimary->getPath());
368 if (mPrimary->getType() == android::vold::VolumeBase::Type::kEmulated) {
369 source = StringPrintf("%s/%d", source.c_str(), userId);
370 }
371
372 std::string target(StringPrintf("/mnt/user/%d/primary", userId));
373 if (TEMP_FAILURE_RETRY(unlink(target.c_str()))) {
374 if (errno != ENOENT) {
375 SLOGW("Failed to unlink %s: %s", target.c_str(), strerror(errno));
376 }
377 }
378 if (TEMP_FAILURE_RETRY(symlink(source.c_str(), target.c_str()))) {
379 SLOGW("Failed to link %s to %s: %s", source.c_str(), target.c_str(),
380 strerror(errno));
381 return -errno;
382 }
383 return 0;
384}
385
386int VolumeManager::startUser(userid_t userId) {
387 // Note that sometimes the system will spin up processes from Zygote
388 // before actually starting the user, so we're okay if Zygote
389 // already created this directory.
390 std::string path(StringPrintf("%s/%d", kUserMountPath, userId));
391 fs_prepare_dir(path.c_str(), 0755, AID_ROOT, AID_ROOT);
392
393 mUsers.push_back(userId);
394 if (mPrimary) {
395 linkPrimary(userId);
396 }
397 return 0;
398}
399
400int VolumeManager::cleanupUser(userid_t userId) {
401 mUsers.remove(userId);
402 return 0;
403}
404
405int VolumeManager::setPrimary(const std::shared_ptr<android::vold::VolumeBase>& vol) {
406 mPrimary = vol;
407 for (userid_t userId : mUsers) {
408 linkPrimary(userId);
409 }
410 return 0;
411}
412
413int VolumeManager::reset() {
414 // Tear down all existing disks/volumes and start from a blank slate so
415 // newly connected framework hears all events.
416 mInternalEmulated->destroy();
417 mInternalEmulated->create();
418 for (auto disk : mDisks) {
419 disk->destroy();
420 disk->create();
421 }
422 mUsers.clear();
423 return 0;
424}
425
426int VolumeManager::shutdown() {
Jeff Sharkey9c484982015-03-31 10:35:33 -0700427 mInternalEmulated->destroy();
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700428 for (auto disk : mDisks) {
429 disk->destroy();
430 }
431 mDisks.clear();
432 return 0;
San Mehatf1b736b2009-10-10 17:22:08 -0700433}
434
Jeff Sharkey9c484982015-03-31 10:35:33 -0700435int VolumeManager::unmountAll() {
436 // First, try gracefully unmounting all known devices
437 if (mInternalEmulated != nullptr) {
438 mInternalEmulated->unmount();
439 }
440 for (auto disk : mDisks) {
441 disk->unmountAll();
442 }
443
444 // Worst case we might have some stale mounts lurking around, so
445 // force unmount those just to be safe.
446 FILE* fp = setmntent("/proc/mounts", "r");
447 if (fp == NULL) {
448 SLOGE("Error opening /proc/mounts: %s", strerror(errno));
449 return -errno;
450 }
451
452 // Some volumes can be stacked on each other, so force unmount in
453 // reverse order to give us the best chance of success.
454 std::list<std::string> toUnmount;
455 mntent* mentry;
456 while ((mentry = getmntent(fp)) != NULL) {
457 if (strncmp(mentry->mnt_dir, "/mnt/", 5) == 0
458 || strncmp(mentry->mnt_dir, "/storage/", 9) == 0) {
459 toUnmount.push_front(std::string(mentry->mnt_dir));
460 }
461 }
462 endmntent(fp);
463
464 for (auto path : toUnmount) {
465 SLOGW("Tearing down stale mount %s", path.c_str());
466 android::vold::ForceUnmount(path);
467 }
468
469 return 0;
470}
471
Kenny Root508c0e12010-07-12 09:59:49 -0700472int VolumeManager::getObbMountPath(const char *sourceFile, char *mountPath, int mountPathLen) {
473 char idHash[33];
474 if (!asecHash(sourceFile, idHash, sizeof(idHash))) {
475 SLOGE("Hash of '%s' failed (%s)", sourceFile, strerror(errno));
476 return -1;
477 }
478
479 memset(mountPath, 0, mountPathLen);
Jeff Sharkey9f18fe72015-04-01 23:32:18 -0700480 int written = snprintf(mountPath, mountPathLen, "%s/%s", VolumeManager::LOOPDIR, idHash);
rpcraigd1c226f2012-10-09 06:58:16 -0400481 if ((written < 0) || (written >= mountPathLen)) {
482 errno = EINVAL;
483 return -1;
484 }
Kenny Root508c0e12010-07-12 09:59:49 -0700485
486 if (access(mountPath, F_OK)) {
487 errno = ENOENT;
488 return -1;
489 }
490
491 return 0;
492}
493
San Mehata19b2502010-01-06 10:33:53 -0800494int VolumeManager::getAsecMountPath(const char *id, char *buffer, int maxlen) {
San Mehat88ac2c02010-03-23 11:15:58 -0700495 char asecFileName[255];
Kenny Root344ca102012-04-03 17:23:01 -0700496
Nick Kralevich0de7c612014-01-27 14:58:06 -0800497 if (!isLegalAsecId(id)) {
498 SLOGE("getAsecMountPath: Invalid asec id \"%s\"", id);
499 errno = EINVAL;
500 return -1;
501 }
502
Kenny Root344ca102012-04-03 17:23:01 -0700503 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
504 SLOGE("Couldn't find ASEC %s", id);
505 return -1;
506 }
San Mehat88ac2c02010-03-23 11:15:58 -0700507
508 memset(buffer, 0, maxlen);
509 if (access(asecFileName, F_OK)) {
510 errno = ENOENT;
511 return -1;
512 }
San Mehata19b2502010-01-06 10:33:53 -0800513
Jeff Sharkey9f18fe72015-04-01 23:32:18 -0700514 int written = snprintf(buffer, maxlen, "%s/%s", VolumeManager::ASECDIR, id);
rpcraigd1c226f2012-10-09 06:58:16 -0400515 if ((written < 0) || (written >= maxlen)) {
516 SLOGE("getAsecMountPath failed for %s: couldn't construct path in buffer", id);
517 errno = EINVAL;
518 return -1;
519 }
520
San Mehata19b2502010-01-06 10:33:53 -0800521 return 0;
522}
523
Dianne Hackborn736910c2011-06-27 13:37:07 -0700524int VolumeManager::getAsecFilesystemPath(const char *id, char *buffer, int maxlen) {
525 char asecFileName[255];
Kenny Root344ca102012-04-03 17:23:01 -0700526
Nick Kralevich0de7c612014-01-27 14:58:06 -0800527 if (!isLegalAsecId(id)) {
528 SLOGE("getAsecFilesystemPath: Invalid asec id \"%s\"", id);
529 errno = EINVAL;
530 return -1;
531 }
532
Kenny Root344ca102012-04-03 17:23:01 -0700533 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
534 SLOGE("Couldn't find ASEC %s", id);
535 return -1;
536 }
Dianne Hackborn736910c2011-06-27 13:37:07 -0700537
538 memset(buffer, 0, maxlen);
539 if (access(asecFileName, F_OK)) {
540 errno = ENOENT;
541 return -1;
542 }
543
rpcraigd1c226f2012-10-09 06:58:16 -0400544 int written = snprintf(buffer, maxlen, "%s", asecFileName);
545 if ((written < 0) || (written >= maxlen)) {
546 errno = EINVAL;
547 return -1;
548 }
549
Dianne Hackborn736910c2011-06-27 13:37:07 -0700550 return 0;
551}
552
Kenny Root344ca102012-04-03 17:23:01 -0700553int VolumeManager::createAsec(const char *id, unsigned int numSectors, const char *fstype,
554 const char *key, const int ownerUid, bool isExternal) {
San Mehatfcf24fe2010-03-03 12:37:32 -0800555 struct asec_superblock sb;
556 memset(&sb, 0, sizeof(sb));
557
Nick Kralevich0de7c612014-01-27 14:58:06 -0800558 if (!isLegalAsecId(id)) {
559 SLOGE("createAsec: Invalid asec id \"%s\"", id);
560 errno = EINVAL;
561 return -1;
562 }
563
Kenny Root344ca102012-04-03 17:23:01 -0700564 const bool wantFilesystem = strcmp(fstype, "none");
565 bool usingExt4 = false;
566 if (wantFilesystem) {
567 usingExt4 = !strcmp(fstype, "ext4");
568 if (usingExt4) {
569 sb.c_opts |= ASEC_SB_C_OPTS_EXT4;
570 } else if (strcmp(fstype, "fat")) {
571 SLOGE("Invalid filesystem type %s", fstype);
572 errno = EINVAL;
573 return -1;
574 }
575 }
576
San Mehatfcf24fe2010-03-03 12:37:32 -0800577 sb.magic = ASEC_SB_MAGIC;
578 sb.ver = ASEC_SB_VER;
San Mehata19b2502010-01-06 10:33:53 -0800579
San Mehatd31e3802010-02-18 08:37:45 -0800580 if (numSectors < ((1024*1024)/512)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700581 SLOGE("Invalid container size specified (%d sectors)", numSectors);
San Mehatd31e3802010-02-18 08:37:45 -0800582 errno = EINVAL;
583 return -1;
584 }
585
San Mehata19b2502010-01-06 10:33:53 -0800586 char asecFileName[255];
Kenny Root344ca102012-04-03 17:23:01 -0700587
588 if (!findAsec(id, asecFileName, sizeof(asecFileName))) {
589 SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
590 asecFileName, strerror(errno));
591 errno = EADDRINUSE;
592 return -1;
593 }
594
Jeff Sharkey9f18fe72015-04-01 23:32:18 -0700595 const char *asecDir = isExternal ? VolumeManager::SEC_ASECDIR_EXT : VolumeManager::SEC_ASECDIR_INT;
Kenny Root344ca102012-04-03 17:23:01 -0700596
rpcraigd1c226f2012-10-09 06:58:16 -0400597 int written = snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", asecDir, id);
598 if ((written < 0) || (size_t(written) >= sizeof(asecFileName))) {
599 errno = EINVAL;
600 return -1;
601 }
San Mehata19b2502010-01-06 10:33:53 -0800602
603 if (!access(asecFileName, F_OK)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700604 SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
Kenny Root344ca102012-04-03 17:23:01 -0700605 asecFileName, strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800606 errno = EADDRINUSE;
607 return -1;
608 }
609
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -0700610 unsigned numImgSectors;
Daniel Rosenberg6a74dca2014-05-23 13:47:00 -0700611 if (usingExt4)
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -0700612 numImgSectors = adjustSectorNumExt4(numSectors);
Daniel Rosenberg6a74dca2014-05-23 13:47:00 -0700613 else
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -0700614 numImgSectors = adjustSectorNumFAT(numSectors);
San Mehatfcf24fe2010-03-03 12:37:32 -0800615
616 // Add +1 for our superblock which is at the end
617 if (Loop::createImageFile(asecFileName, numImgSectors + 1)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700618 SLOGE("ASEC image file creation failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800619 return -1;
620 }
621
San Mehatd9a4e352010-03-12 13:32:47 -0800622 char idHash[33];
623 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700624 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800625 unlink(asecFileName);
626 return -1;
627 }
628
San Mehata19b2502010-01-06 10:33:53 -0800629 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800630 if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700631 SLOGE("ASEC loop device creation failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800632 unlink(asecFileName);
633 return -1;
634 }
635
San Mehatb78a32c2010-01-10 13:02:12 -0800636 char dmDevice[255];
637 bool cleanupDm = false;
San Mehata19b2502010-01-06 10:33:53 -0800638
San Mehatb78a32c2010-01-10 13:02:12 -0800639 if (strcmp(key, "none")) {
San Mehatfcf24fe2010-03-03 12:37:32 -0800640 // XXX: This is all we support for now
641 sb.c_cipher = ASEC_SB_C_CIPHER_TWOFISH;
San Mehatd9a4e352010-03-12 13:32:47 -0800642 if (Devmapper::create(idHash, loopDevice, key, numImgSectors, dmDevice,
San Mehatb78a32c2010-01-10 13:02:12 -0800643 sizeof(dmDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700644 SLOGE("ASEC device mapping failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800645 Loop::destroyByDevice(loopDevice);
646 unlink(asecFileName);
647 return -1;
648 }
649 cleanupDm = true;
650 } else {
San Mehatfcf24fe2010-03-03 12:37:32 -0800651 sb.c_cipher = ASEC_SB_C_CIPHER_NONE;
San Mehatb78a32c2010-01-10 13:02:12 -0800652 strcpy(dmDevice, loopDevice);
653 }
654
San Mehatfcf24fe2010-03-03 12:37:32 -0800655 /*
656 * Drop down the superblock at the end of the file
657 */
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -0700658 if (writeSuperBlock(loopDevice, &sb, numImgSectors)) {
San Mehatfcf24fe2010-03-03 12:37:32 -0800659 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800660 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800661 }
662 Loop::destroyByDevice(loopDevice);
663 unlink(asecFileName);
664 return -1;
665 }
666
Kenny Root344ca102012-04-03 17:23:01 -0700667 if (wantFilesystem) {
668 int formatStatus;
rpcraiga54e13a2012-09-21 14:17:08 -0400669 char mountPoint[255];
670
Jeff Sharkey9f18fe72015-04-01 23:32:18 -0700671 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id);
rpcraigd1c226f2012-10-09 06:58:16 -0400672 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
673 SLOGE("ASEC fs format failed: couldn't construct mountPoint");
674 if (cleanupDm) {
675 Devmapper::destroy(idHash);
676 }
677 Loop::destroyByDevice(loopDevice);
678 unlink(asecFileName);
679 return -1;
680 }
rpcraiga54e13a2012-09-21 14:17:08 -0400681
Kenny Root344ca102012-04-03 17:23:01 -0700682 if (usingExt4) {
Daniel Rosenberg6a74dca2014-05-23 13:47:00 -0700683 formatStatus = Ext4::format(dmDevice, numImgSectors, mountPoint);
Kenny Root344ca102012-04-03 17:23:01 -0700684 } else {
Ken Sumrall9caab762013-06-11 19:10:20 -0700685 formatStatus = Fat::format(dmDevice, numImgSectors, 0);
San Mehatb78a32c2010-01-10 13:02:12 -0800686 }
San Mehata19b2502010-01-06 10:33:53 -0800687
Kenny Root344ca102012-04-03 17:23:01 -0700688 if (formatStatus < 0) {
689 SLOGE("ASEC fs format failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800690 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800691 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -0800692 }
San Mehateb13a902010-01-07 12:12:50 -0800693 Loop::destroyByDevice(loopDevice);
694 unlink(asecFileName);
695 return -1;
696 }
Kenny Root344ca102012-04-03 17:23:01 -0700697
Kenny Root344ca102012-04-03 17:23:01 -0700698 if (mkdir(mountPoint, 0000)) {
San Mehata1091cb2010-02-28 20:17:20 -0800699 if (errno != EEXIST) {
San Mehat97ac40e2010-03-24 10:24:19 -0700700 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
San Mehata1091cb2010-02-28 20:17:20 -0800701 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800702 Devmapper::destroy(idHash);
San Mehata1091cb2010-02-28 20:17:20 -0800703 }
704 Loop::destroyByDevice(loopDevice);
705 unlink(asecFileName);
706 return -1;
707 }
San Mehatb78a32c2010-01-10 13:02:12 -0800708 }
San Mehata1091cb2010-02-28 20:17:20 -0800709
Kenny Root344ca102012-04-03 17:23:01 -0700710 int mountStatus;
711 if (usingExt4) {
712 mountStatus = Ext4::doMount(dmDevice, mountPoint, false, false, false);
713 } else {
714 mountStatus = Fat::doMount(dmDevice, mountPoint, false, false, false, ownerUid, 0, 0000,
715 false);
716 }
717
718 if (mountStatus) {
San Mehat97ac40e2010-03-24 10:24:19 -0700719 SLOGE("ASEC FAT mount failed (%s)", strerror(errno));
San Mehata1091cb2010-02-28 20:17:20 -0800720 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800721 Devmapper::destroy(idHash);
San Mehata1091cb2010-02-28 20:17:20 -0800722 }
723 Loop::destroyByDevice(loopDevice);
724 unlink(asecFileName);
725 return -1;
726 }
Kenny Root344ca102012-04-03 17:23:01 -0700727
728 if (usingExt4) {
Jeff Sharkeyce6a9132015-04-08 21:07:21 -0700729 int dirfd = open(mountPoint, O_DIRECTORY | O_CLOEXEC);
Kenny Root344ca102012-04-03 17:23:01 -0700730 if (dirfd >= 0) {
731 if (fchown(dirfd, ownerUid, AID_SYSTEM)
732 || fchmod(dirfd, S_IRUSR | S_IWUSR | S_IXUSR | S_ISGID | S_IRGRP | S_IXGRP)) {
733 SLOGI("Cannot chown/chmod new ASEC mount point %s", mountPoint);
734 }
735 close(dirfd);
736 }
737 }
San Mehata1091cb2010-02-28 20:17:20 -0800738 } else {
San Mehat97ac40e2010-03-24 10:24:19 -0700739 SLOGI("Created raw secure container %s (no filesystem)", id);
San Mehata19b2502010-01-06 10:33:53 -0800740 }
San Mehat88705162010-01-15 09:26:28 -0800741
Kenny Rootcbacf782010-09-24 15:11:48 -0700742 mActiveContainers->push_back(new ContainerData(strdup(id), ASEC));
San Mehata19b2502010-01-06 10:33:53 -0800743 return 0;
744}
745
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -0700746int VolumeManager::resizeAsec(const char *id, unsigned numSectors, const char *key) {
747 char asecFileName[255];
748 char mountPoint[255];
749 bool cleanupDm = false;
750
751 if (!isLegalAsecId(id)) {
752 SLOGE("resizeAsec: Invalid asec id \"%s\"", id);
753 errno = EINVAL;
754 return -1;
755 }
756
757 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
758 SLOGE("Couldn't find ASEC %s", id);
759 return -1;
760 }
761
Jeff Sharkey9f18fe72015-04-01 23:32:18 -0700762 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id);
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -0700763 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
764 SLOGE("ASEC resize failed for %s: couldn't construct mountpoint", id);
765 return -1;
766 }
767
768 if (isMountpointMounted(mountPoint)) {
769 SLOGE("ASEC %s mounted. Unmount before resizing", id);
770 errno = EBUSY;
771 return -1;
772 }
773
774 struct asec_superblock sb;
775 int fd;
776 unsigned int oldNumSec = 0;
777
Jeff Sharkeyce6a9132015-04-08 21:07:21 -0700778 if ((fd = open(asecFileName, O_RDONLY | O_CLOEXEC)) < 0) {
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -0700779 SLOGE("Failed to open ASEC file (%s)", strerror(errno));
780 return -1;
781 }
782
783 struct stat info;
784 if (fstat(fd, &info) < 0) {
785 SLOGE("Failed to get file size (%s)", strerror(errno));
786 close(fd);
787 return -1;
788 }
789
790 oldNumSec = info.st_size / 512;
791
792 unsigned numImgSectors;
793 if (sb.c_opts & ASEC_SB_C_OPTS_EXT4)
794 numImgSectors = adjustSectorNumExt4(numSectors);
795 else
796 numImgSectors = adjustSectorNumFAT(numSectors);
797 /*
798 * add one block for the superblock
799 */
800 SLOGD("Resizing from %d sectors to %d sectors", oldNumSec, numImgSectors + 1);
Jeff Sharkey43ed1232014-08-22 12:29:05 -0700801 if (oldNumSec == numImgSectors + 1) {
802 SLOGW("Size unchanged; ignoring resize request");
803 return 0;
804 } else if (oldNumSec > numImgSectors + 1) {
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -0700805 SLOGE("Only growing is currently supported.");
806 close(fd);
807 return -1;
808 }
809
810 /*
811 * Try to read superblock.
812 */
813 memset(&sb, 0, sizeof(struct asec_superblock));
814 if (lseek(fd, ((oldNumSec - 1) * 512), SEEK_SET) < 0) {
815 SLOGE("lseek failed (%s)", strerror(errno));
816 close(fd);
817 return -1;
818 }
819 if (read(fd, &sb, sizeof(struct asec_superblock)) != sizeof(struct asec_superblock)) {
820 SLOGE("superblock read failed (%s)", strerror(errno));
821 close(fd);
822 return -1;
823 }
824 close(fd);
825
826 if (mDebug) {
827 SLOGD("Container sb magic/ver (%.8x/%.2x)", sb.magic, sb.ver);
828 }
829 if (sb.magic != ASEC_SB_MAGIC || sb.ver != ASEC_SB_VER) {
830 SLOGE("Bad container magic/version (%.8x/%.2x)", sb.magic, sb.ver);
831 errno = EMEDIUMTYPE;
832 return -1;
833 }
834
835 if (!(sb.c_opts & ASEC_SB_C_OPTS_EXT4)) {
836 SLOGE("Only ext4 partitions are supported for resize");
837 errno = EINVAL;
838 return -1;
839 }
840
841 if (Loop::resizeImageFile(asecFileName, numImgSectors + 1)) {
842 SLOGE("Resize of ASEC image file failed. Could not resize %s", id);
843 return -1;
844 }
845
846 /*
847 * Drop down a copy of the superblock at the end of the file
848 */
849 if (writeSuperBlock(asecFileName, &sb, numImgSectors))
850 goto fail;
851
852 char idHash[33];
853 if (!asecHash(id, idHash, sizeof(idHash))) {
854 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
855 goto fail;
856 }
857
858 char loopDevice[255];
859 if (setupLoopDevice(loopDevice, sizeof(loopDevice), asecFileName, idHash, mDebug))
860 goto fail;
861
862 char dmDevice[255];
863
864 if (setupDevMapperDevice(dmDevice, sizeof(dmDevice), loopDevice, asecFileName, key, idHash, numImgSectors, &cleanupDm, mDebug)) {
865 Loop::destroyByDevice(loopDevice);
866 goto fail;
867 }
868
869 /*
870 * Wait for the device mapper node to be created.
871 */
872 waitForDevMapper(dmDevice);
873
874 if (Ext4::resize(dmDevice, numImgSectors)) {
875 SLOGE("Unable to resize %s (%s)", id, strerror(errno));
876 if (cleanupDm) {
877 Devmapper::destroy(idHash);
878 }
879 Loop::destroyByDevice(loopDevice);
880 goto fail;
881 }
882
883 return 0;
884fail:
885 Loop::resizeImageFile(asecFileName, oldNumSec);
886 return -1;
887}
888
San Mehata19b2502010-01-06 10:33:53 -0800889int VolumeManager::finalizeAsec(const char *id) {
890 char asecFileName[255];
891 char loopDevice[255];
892 char mountPoint[255];
893
Nick Kralevich0de7c612014-01-27 14:58:06 -0800894 if (!isLegalAsecId(id)) {
895 SLOGE("finalizeAsec: Invalid asec id \"%s\"", id);
896 errno = EINVAL;
897 return -1;
898 }
899
Kenny Root344ca102012-04-03 17:23:01 -0700900 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
901 SLOGE("Couldn't find ASEC %s", id);
902 return -1;
903 }
San Mehata19b2502010-01-06 10:33:53 -0800904
San Mehatd9a4e352010-03-12 13:32:47 -0800905 char idHash[33];
906 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700907 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800908 return -1;
909 }
910
911 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700912 SLOGE("Unable to finalize %s (%s)", id, strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800913 return -1;
914 }
915
Hiroaki Miyazawa14eab552015-02-04 13:29:15 +0900916 unsigned long nr_sec = 0;
Kenny Root344ca102012-04-03 17:23:01 -0700917 struct asec_superblock sb;
918
919 if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) {
920 return -1;
921 }
922
Jeff Sharkey9f18fe72015-04-01 23:32:18 -0700923 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id);
rpcraigd1c226f2012-10-09 06:58:16 -0400924 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
925 SLOGE("ASEC finalize failed: couldn't construct mountPoint");
926 return -1;
927 }
Kenny Root344ca102012-04-03 17:23:01 -0700928
929 int result = 0;
930 if (sb.c_opts & ASEC_SB_C_OPTS_EXT4) {
931 result = Ext4::doMount(loopDevice, mountPoint, true, true, true);
932 } else {
933 result = Fat::doMount(loopDevice, mountPoint, true, true, true, 0, 0, 0227, false);
934 }
935
936 if (result) {
San Mehat97ac40e2010-03-24 10:24:19 -0700937 SLOGE("ASEC finalize mount failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800938 return -1;
939 }
940
San Mehatd9a4e352010-03-12 13:32:47 -0800941 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700942 SLOGD("ASEC %s finalized", id);
San Mehatd9a4e352010-03-12 13:32:47 -0800943 }
San Mehata19b2502010-01-06 10:33:53 -0800944 return 0;
945}
946
Kenny Root344ca102012-04-03 17:23:01 -0700947int VolumeManager::fixupAsecPermissions(const char *id, gid_t gid, const char* filename) {
948 char asecFileName[255];
949 char loopDevice[255];
950 char mountPoint[255];
951
952 if (gid < AID_APP) {
953 SLOGE("Group ID is not in application range");
954 return -1;
955 }
956
Nick Kralevich0de7c612014-01-27 14:58:06 -0800957 if (!isLegalAsecId(id)) {
958 SLOGE("fixupAsecPermissions: Invalid asec id \"%s\"", id);
959 errno = EINVAL;
960 return -1;
961 }
962
Kenny Root344ca102012-04-03 17:23:01 -0700963 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
964 SLOGE("Couldn't find ASEC %s", id);
965 return -1;
966 }
967
968 char idHash[33];
969 if (!asecHash(id, idHash, sizeof(idHash))) {
970 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
971 return -1;
972 }
973
974 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
975 SLOGE("Unable fix permissions during lookup on %s (%s)", id, strerror(errno));
976 return -1;
977 }
978
Hiroaki Miyazawa14eab552015-02-04 13:29:15 +0900979 unsigned long nr_sec = 0;
Kenny Root344ca102012-04-03 17:23:01 -0700980 struct asec_superblock sb;
981
982 if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) {
983 return -1;
984 }
985
Jeff Sharkey9f18fe72015-04-01 23:32:18 -0700986 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id);
rpcraigd1c226f2012-10-09 06:58:16 -0400987 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
988 SLOGE("Unable remount to fix permissions for %s: couldn't construct mountpoint", id);
989 return -1;
990 }
Kenny Root344ca102012-04-03 17:23:01 -0700991
992 int result = 0;
993 if ((sb.c_opts & ASEC_SB_C_OPTS_EXT4) == 0) {
994 return 0;
995 }
996
997 int ret = Ext4::doMount(loopDevice, mountPoint,
998 false /* read-only */,
999 true /* remount */,
1000 false /* executable */);
1001 if (ret) {
1002 SLOGE("Unable remount to fix permissions for %s (%s)", id, strerror(errno));
1003 return -1;
1004 }
1005
1006 char *paths[] = { mountPoint, NULL };
1007
1008 FTS *fts = fts_open(paths, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL);
1009 if (fts) {
1010 // Traverse the entire hierarchy and chown to system UID.
1011 for (FTSENT *ftsent = fts_read(fts); ftsent != NULL; ftsent = fts_read(fts)) {
1012 // We don't care about the lost+found directory.
1013 if (!strcmp(ftsent->fts_name, "lost+found")) {
1014 continue;
1015 }
1016
1017 /*
1018 * There can only be one file marked as private right now.
1019 * This should be more robust, but it satisfies the requirements
1020 * we have for right now.
1021 */
1022 const bool privateFile = !strcmp(ftsent->fts_name, filename);
1023
Jeff Sharkeyce6a9132015-04-08 21:07:21 -07001024 int fd = open(ftsent->fts_accpath, O_NOFOLLOW | O_CLOEXEC);
Kenny Root344ca102012-04-03 17:23:01 -07001025 if (fd < 0) {
1026 SLOGE("Couldn't open file %s: %s", ftsent->fts_accpath, strerror(errno));
1027 result = -1;
1028 continue;
1029 }
1030
1031 result |= fchown(fd, AID_SYSTEM, privateFile? gid : AID_SYSTEM);
1032
1033 if (ftsent->fts_info & FTS_D) {
Kenny Root1a673c82012-05-10 16:45:29 -07001034 result |= fchmod(fd, 0755);
Kenny Root348c8ab2012-05-10 15:39:53 -07001035 } else if (ftsent->fts_info & FTS_F) {
Kenny Root344ca102012-04-03 17:23:01 -07001036 result |= fchmod(fd, privateFile ? 0640 : 0644);
1037 }
Robert Craigb9e3ba52014-02-04 10:53:00 -05001038
Stephen Smalley5093e612014-02-12 09:43:08 -05001039 if (selinux_android_restorecon(ftsent->fts_path, 0) < 0) {
Robert Craigb9e3ba52014-02-04 10:53:00 -05001040 SLOGE("restorecon failed for %s: %s\n", ftsent->fts_path, strerror(errno));
1041 result |= -1;
1042 }
1043
Kenny Root344ca102012-04-03 17:23:01 -07001044 close(fd);
1045 }
1046 fts_close(fts);
1047
1048 // Finally make the directory readable by everyone.
Jeff Sharkeyce6a9132015-04-08 21:07:21 -07001049 int dirfd = open(mountPoint, O_DIRECTORY | O_CLOEXEC);
Kenny Root344ca102012-04-03 17:23:01 -07001050 if (dirfd < 0 || fchmod(dirfd, 0755)) {
1051 SLOGE("Couldn't change owner of existing directory %s: %s", mountPoint, strerror(errno));
1052 result |= -1;
1053 }
1054 close(dirfd);
1055 } else {
1056 result |= -1;
1057 }
1058
1059 result |= Ext4::doMount(loopDevice, mountPoint,
1060 true /* read-only */,
1061 true /* remount */,
1062 true /* execute */);
1063
1064 if (result) {
1065 SLOGE("ASEC fix permissions failed (%s)", strerror(errno));
1066 return -1;
1067 }
1068
1069 if (mDebug) {
1070 SLOGD("ASEC %s permissions fixed", id);
1071 }
1072 return 0;
1073}
1074
San Mehat048b0802010-01-23 08:17:06 -08001075int VolumeManager::renameAsec(const char *id1, const char *id2) {
Kenny Root344ca102012-04-03 17:23:01 -07001076 char asecFilename1[255];
San Mehat048b0802010-01-23 08:17:06 -08001077 char *asecFilename2;
1078 char mountPoint[255];
1079
Kenny Root344ca102012-04-03 17:23:01 -07001080 const char *dir;
1081
Nick Kralevich0de7c612014-01-27 14:58:06 -08001082 if (!isLegalAsecId(id1)) {
1083 SLOGE("renameAsec: Invalid asec id1 \"%s\"", id1);
1084 errno = EINVAL;
1085 return -1;
1086 }
1087
1088 if (!isLegalAsecId(id2)) {
1089 SLOGE("renameAsec: Invalid asec id2 \"%s\"", id2);
1090 errno = EINVAL;
1091 return -1;
1092 }
1093
Kenny Root344ca102012-04-03 17:23:01 -07001094 if (findAsec(id1, asecFilename1, sizeof(asecFilename1), &dir)) {
1095 SLOGE("Couldn't find ASEC %s", id1);
1096 return -1;
1097 }
1098
1099 asprintf(&asecFilename2, "%s/%s.asec", dir, id2);
San Mehat048b0802010-01-23 08:17:06 -08001100
Jeff Sharkey9f18fe72015-04-01 23:32:18 -07001101 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id1);
rpcraigd1c226f2012-10-09 06:58:16 -04001102 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
1103 SLOGE("Rename failed: couldn't construct mountpoint");
1104 goto out_err;
1105 }
1106
San Mehat048b0802010-01-23 08:17:06 -08001107 if (isMountpointMounted(mountPoint)) {
San Mehat97ac40e2010-03-24 10:24:19 -07001108 SLOGW("Rename attempt when src mounted");
San Mehat048b0802010-01-23 08:17:06 -08001109 errno = EBUSY;
1110 goto out_err;
1111 }
1112
Jeff Sharkey9f18fe72015-04-01 23:32:18 -07001113 written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id2);
rpcraigd1c226f2012-10-09 06:58:16 -04001114 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
1115 SLOGE("Rename failed: couldn't construct mountpoint2");
1116 goto out_err;
1117 }
1118
San Mehat96956ed2010-02-24 08:42:51 -08001119 if (isMountpointMounted(mountPoint)) {
San Mehat97ac40e2010-03-24 10:24:19 -07001120 SLOGW("Rename attempt when dst mounted");
San Mehat96956ed2010-02-24 08:42:51 -08001121 errno = EBUSY;
1122 goto out_err;
1123 }
1124
San Mehat048b0802010-01-23 08:17:06 -08001125 if (!access(asecFilename2, F_OK)) {
San Mehat97ac40e2010-03-24 10:24:19 -07001126 SLOGE("Rename attempt when dst exists");
San Mehat048b0802010-01-23 08:17:06 -08001127 errno = EADDRINUSE;
1128 goto out_err;
1129 }
1130
1131 if (rename(asecFilename1, asecFilename2)) {
San Mehat97ac40e2010-03-24 10:24:19 -07001132 SLOGE("Rename of '%s' to '%s' failed (%s)", asecFilename1, asecFilename2, strerror(errno));
San Mehat048b0802010-01-23 08:17:06 -08001133 goto out_err;
1134 }
1135
San Mehat048b0802010-01-23 08:17:06 -08001136 free(asecFilename2);
1137 return 0;
1138
1139out_err:
San Mehat048b0802010-01-23 08:17:06 -08001140 free(asecFilename2);
1141 return -1;
1142}
1143
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001144#define UNMOUNT_RETRIES 5
1145#define UNMOUNT_SLEEP_BETWEEN_RETRY_MS (1000 * 1000)
San Mehat4ba89482010-02-18 09:00:18 -08001146int VolumeManager::unmountAsec(const char *id, bool force) {
San Mehata19b2502010-01-06 10:33:53 -08001147 char asecFileName[255];
1148 char mountPoint[255];
1149
Nick Kralevich0de7c612014-01-27 14:58:06 -08001150 if (!isLegalAsecId(id)) {
1151 SLOGE("unmountAsec: Invalid asec id \"%s\"", id);
1152 errno = EINVAL;
1153 return -1;
1154 }
1155
Kenny Root344ca102012-04-03 17:23:01 -07001156 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
1157 SLOGE("Couldn't find ASEC %s", id);
1158 return -1;
1159 }
1160
Jeff Sharkey9f18fe72015-04-01 23:32:18 -07001161 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id);
rpcraigd1c226f2012-10-09 06:58:16 -04001162 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
1163 SLOGE("ASEC unmount failed for %s: couldn't construct mountpoint", id);
1164 return -1;
1165 }
San Mehata19b2502010-01-06 10:33:53 -08001166
San Mehatd9a4e352010-03-12 13:32:47 -08001167 char idHash[33];
1168 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -07001169 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -08001170 return -1;
1171 }
1172
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001173 return unmountLoopImage(id, idHash, asecFileName, mountPoint, force);
1174}
1175
Kenny Root508c0e12010-07-12 09:59:49 -07001176int VolumeManager::unmountObb(const char *fileName, bool force) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001177 char mountPoint[255];
1178
1179 char idHash[33];
1180 if (!asecHash(fileName, idHash, sizeof(idHash))) {
1181 SLOGE("Hash of '%s' failed (%s)", fileName, strerror(errno));
1182 return -1;
1183 }
1184
Jeff Sharkey9f18fe72015-04-01 23:32:18 -07001185 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::LOOPDIR, idHash);
rpcraigd1c226f2012-10-09 06:58:16 -04001186 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
1187 SLOGE("OBB unmount failed for %s: couldn't construct mountpoint", fileName);
1188 return -1;
1189 }
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001190
1191 return unmountLoopImage(fileName, idHash, fileName, mountPoint, force);
1192}
1193
1194int VolumeManager::unmountLoopImage(const char *id, const char *idHash,
1195 const char *fileName, const char *mountPoint, bool force) {
San Mehat0586d542010-01-12 15:38:59 -08001196 if (!isMountpointMounted(mountPoint)) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001197 SLOGE("Unmount request for %s when not mounted", id);
Kenny Root918e5f92010-09-30 18:00:52 -07001198 errno = ENOENT;
San Mehatb78a32c2010-01-10 13:02:12 -08001199 return -1;
1200 }
San Mehat23969932010-01-09 07:08:06 -08001201
San Mehatb78a32c2010-01-10 13:02:12 -08001202 int i, rc;
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001203 for (i = 1; i <= UNMOUNT_RETRIES; i++) {
San Mehatb78a32c2010-01-10 13:02:12 -08001204 rc = umount(mountPoint);
1205 if (!rc) {
1206 break;
San Mehata19b2502010-01-06 10:33:53 -08001207 }
San Mehatb78a32c2010-01-10 13:02:12 -08001208 if (rc && (errno == EINVAL || errno == ENOENT)) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001209 SLOGI("Container %s unmounted OK", id);
San Mehatb78a32c2010-01-10 13:02:12 -08001210 rc = 0;
1211 break;
San Mehata19b2502010-01-06 10:33:53 -08001212 }
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001213 SLOGW("%s unmount attempt %d failed (%s)",
San Mehat8c940ef2010-02-13 14:19:53 -08001214 id, i, strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -08001215
Jeff Sharkey36801cc2015-03-13 16:09:20 -07001216 int signal = 0; // default is to just complain
San Mehat4ba89482010-02-18 09:00:18 -08001217
1218 if (force) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001219 if (i > (UNMOUNT_RETRIES - 2))
Jeff Sharkey36801cc2015-03-13 16:09:20 -07001220 signal = SIGKILL;
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001221 else if (i > (UNMOUNT_RETRIES - 3))
Jeff Sharkey36801cc2015-03-13 16:09:20 -07001222 signal = SIGTERM;
San Mehat4ba89482010-02-18 09:00:18 -08001223 }
San Mehat8c940ef2010-02-13 14:19:53 -08001224
Jeff Sharkey36801cc2015-03-13 16:09:20 -07001225 Process::killProcessesWithOpenFiles(mountPoint, signal);
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001226 usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
San Mehatb78a32c2010-01-10 13:02:12 -08001227 }
1228
1229 if (rc) {
San Mehat4ba89482010-02-18 09:00:18 -08001230 errno = EBUSY;
San Mehat97ac40e2010-03-24 10:24:19 -07001231 SLOGE("Failed to unmount container %s (%s)", id, strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -08001232 return -1;
1233 }
1234
San Mehat12f4b892010-02-24 11:43:22 -08001235 int retries = 10;
1236
1237 while(retries--) {
1238 if (!rmdir(mountPoint)) {
1239 break;
1240 }
1241
San Mehat97ac40e2010-03-24 10:24:19 -07001242 SLOGW("Failed to rmdir %s (%s)", mountPoint, strerror(errno));
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001243 usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
San Mehat12f4b892010-02-24 11:43:22 -08001244 }
1245
1246 if (!retries) {
San Mehat97ac40e2010-03-24 10:24:19 -07001247 SLOGE("Timed out trying to rmdir %s (%s)", mountPoint, strerror(errno));
San Mehatf5c61982010-02-03 11:04:46 -08001248 }
San Mehat88705162010-01-15 09:26:28 -08001249
Paul Lawrence60dec162014-09-02 10:52:15 -07001250 for (i=1; i <= UNMOUNT_RETRIES; i++) {
1251 if (Devmapper::destroy(idHash) && errno != ENXIO) {
1252 SLOGE("Failed to destroy devmapper instance (%s)", strerror(errno));
1253 usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
1254 continue;
1255 } else {
1256 break;
1257 }
San Mehata19b2502010-01-06 10:33:53 -08001258 }
1259
1260 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -08001261 if (!Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
San Mehata19b2502010-01-06 10:33:53 -08001262 Loop::destroyByDevice(loopDevice);
San Mehatd9a4e352010-03-12 13:32:47 -08001263 } else {
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001264 SLOGW("Failed to find loop device for {%s} (%s)", fileName, strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -08001265 }
San Mehat88705162010-01-15 09:26:28 -08001266
1267 AsecIdCollection::iterator it;
1268 for (it = mActiveContainers->begin(); it != mActiveContainers->end(); ++it) {
Kenny Rootcbacf782010-09-24 15:11:48 -07001269 ContainerData* cd = *it;
1270 if (!strcmp(cd->id, id)) {
San Mehat88705162010-01-15 09:26:28 -08001271 free(*it);
1272 mActiveContainers->erase(it);
1273 break;
1274 }
1275 }
1276 if (it == mActiveContainers->end()) {
San Mehat97ac40e2010-03-24 10:24:19 -07001277 SLOGW("mActiveContainers is inconsistent!");
San Mehat88705162010-01-15 09:26:28 -08001278 }
San Mehatb78a32c2010-01-10 13:02:12 -08001279 return 0;
1280}
1281
San Mehat4ba89482010-02-18 09:00:18 -08001282int VolumeManager::destroyAsec(const char *id, bool force) {
San Mehatb78a32c2010-01-10 13:02:12 -08001283 char asecFileName[255];
1284 char mountPoint[255];
1285
Nick Kralevich0de7c612014-01-27 14:58:06 -08001286 if (!isLegalAsecId(id)) {
1287 SLOGE("destroyAsec: Invalid asec id \"%s\"", id);
1288 errno = EINVAL;
1289 return -1;
1290 }
1291
Kenny Root344ca102012-04-03 17:23:01 -07001292 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
1293 SLOGE("Couldn't find ASEC %s", id);
1294 return -1;
1295 }
1296
Jeff Sharkey9f18fe72015-04-01 23:32:18 -07001297 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id);
rpcraigd1c226f2012-10-09 06:58:16 -04001298 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
1299 SLOGE("ASEC destroy failed for %s: couldn't construct mountpoint", id);
1300 return -1;
1301 }
San Mehatb78a32c2010-01-10 13:02:12 -08001302
San Mehat0586d542010-01-12 15:38:59 -08001303 if (isMountpointMounted(mountPoint)) {
San Mehatd9a4e352010-03-12 13:32:47 -08001304 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -07001305 SLOGD("Unmounting container before destroy");
San Mehatd9a4e352010-03-12 13:32:47 -08001306 }
San Mehat4ba89482010-02-18 09:00:18 -08001307 if (unmountAsec(id, force)) {
San Mehat97ac40e2010-03-24 10:24:19 -07001308 SLOGE("Failed to unmount asec %s for destroy (%s)", id, strerror(errno));
San Mehat0586d542010-01-12 15:38:59 -08001309 return -1;
1310 }
1311 }
San Mehata19b2502010-01-06 10:33:53 -08001312
San Mehat0586d542010-01-12 15:38:59 -08001313 if (unlink(asecFileName)) {
San Mehat97ac40e2010-03-24 10:24:19 -07001314 SLOGE("Failed to unlink asec '%s' (%s)", asecFileName, strerror(errno));
San Mehat0586d542010-01-12 15:38:59 -08001315 return -1;
1316 }
San Mehata19b2502010-01-06 10:33:53 -08001317
San Mehatd9a4e352010-03-12 13:32:47 -08001318 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -07001319 SLOGD("ASEC %s destroyed", id);
San Mehatd9a4e352010-03-12 13:32:47 -08001320 }
San Mehata19b2502010-01-06 10:33:53 -08001321 return 0;
1322}
1323
Nick Kralevich0de7c612014-01-27 14:58:06 -08001324/*
1325 * Legal ASEC ids consist of alphanumeric characters, '-',
1326 * '_', or '.'. ".." is not allowed. The first or last character
1327 * of the ASEC id cannot be '.' (dot).
1328 */
1329bool VolumeManager::isLegalAsecId(const char *id) const {
1330 size_t i;
1331 size_t len = strlen(id);
1332
1333 if (len == 0) {
1334 return false;
1335 }
1336 if ((id[0] == '.') || (id[len - 1] == '.')) {
1337 return false;
1338 }
1339
1340 for (i = 0; i < len; i++) {
1341 if (id[i] == '.') {
1342 // i=0 is guaranteed never to have a dot. See above.
1343 if (id[i-1] == '.') return false;
1344 continue;
1345 }
1346 if (id[i] == '_' || id[i] == '-') continue;
1347 if (id[i] >= 'a' && id[i] <= 'z') continue;
1348 if (id[i] >= 'A' && id[i] <= 'Z') continue;
1349 if (id[i] >= '0' && id[i] <= '9') continue;
1350 return false;
1351 }
1352
1353 return true;
1354}
1355
Kenny Root344ca102012-04-03 17:23:01 -07001356bool VolumeManager::isAsecInDirectory(const char *dir, const char *asecName) const {
Jeff Sharkeyce6a9132015-04-08 21:07:21 -07001357 int dirfd = open(dir, O_DIRECTORY | O_CLOEXEC);
Kenny Root344ca102012-04-03 17:23:01 -07001358 if (dirfd < 0) {
1359 SLOGE("Couldn't open internal ASEC dir (%s)", strerror(errno));
Nick Kralevich25e581a2015-02-06 08:55:08 -08001360 return false;
Kenny Root344ca102012-04-03 17:23:01 -07001361 }
1362
Nick Kralevich25e581a2015-02-06 08:55:08 -08001363 struct stat sb;
1364 bool ret = (fstatat(dirfd, asecName, &sb, AT_SYMLINK_NOFOLLOW) == 0)
1365 && S_ISREG(sb.st_mode);
Kenny Root344ca102012-04-03 17:23:01 -07001366
1367 close(dirfd);
1368
1369 return ret;
1370}
1371
1372int VolumeManager::findAsec(const char *id, char *asecPath, size_t asecPathLen,
1373 const char **directory) const {
Kenny Root344ca102012-04-03 17:23:01 -07001374 char *asecName;
1375
Nick Kralevich0de7c612014-01-27 14:58:06 -08001376 if (!isLegalAsecId(id)) {
1377 SLOGE("findAsec: Invalid asec id \"%s\"", id);
1378 errno = EINVAL;
1379 return -1;
1380 }
1381
Kenny Root344ca102012-04-03 17:23:01 -07001382 if (asprintf(&asecName, "%s.asec", id) < 0) {
1383 SLOGE("Couldn't allocate string to write ASEC name");
1384 return -1;
1385 }
1386
1387 const char *dir;
Jeff Sharkey9f18fe72015-04-01 23:32:18 -07001388 if (isAsecInDirectory(VolumeManager::SEC_ASECDIR_INT, asecName)) {
1389 dir = VolumeManager::SEC_ASECDIR_INT;
1390 } else if (isAsecInDirectory(VolumeManager::SEC_ASECDIR_EXT, asecName)) {
1391 dir = VolumeManager::SEC_ASECDIR_EXT;
Kenny Root344ca102012-04-03 17:23:01 -07001392 } else {
1393 free(asecName);
1394 return -1;
1395 }
1396
1397 if (directory != NULL) {
1398 *directory = dir;
1399 }
1400
1401 if (asecPath != NULL) {
1402 int written = snprintf(asecPath, asecPathLen, "%s/%s", dir, asecName);
rpcraigd1c226f2012-10-09 06:58:16 -04001403 if ((written < 0) || (size_t(written) >= asecPathLen)) {
1404 SLOGE("findAsec failed for %s: couldn't construct ASEC path", id);
Kenny Root344ca102012-04-03 17:23:01 -07001405 free(asecName);
1406 return -1;
1407 }
1408 }
1409
1410 free(asecName);
1411 return 0;
1412}
1413
Jeff Sharkey43ed1232014-08-22 12:29:05 -07001414int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid, bool readOnly) {
San Mehata19b2502010-01-06 10:33:53 -08001415 char asecFileName[255];
1416 char mountPoint[255];
1417
Nick Kralevich0de7c612014-01-27 14:58:06 -08001418 if (!isLegalAsecId(id)) {
1419 SLOGE("mountAsec: Invalid asec id \"%s\"", id);
1420 errno = EINVAL;
1421 return -1;
1422 }
1423
Kenny Root344ca102012-04-03 17:23:01 -07001424 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
1425 SLOGE("Couldn't find ASEC %s", id);
1426 return -1;
1427 }
1428
Jeff Sharkey9f18fe72015-04-01 23:32:18 -07001429 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id);
rpcraigd1c226f2012-10-09 06:58:16 -04001430 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
Colin Cross59846b62014-02-06 20:34:29 -08001431 SLOGE("ASEC mount failed for %s: couldn't construct mountpoint", id);
rpcraigd1c226f2012-10-09 06:58:16 -04001432 return -1;
1433 }
San Mehata19b2502010-01-06 10:33:53 -08001434
1435 if (isMountpointMounted(mountPoint)) {
San Mehat97ac40e2010-03-24 10:24:19 -07001436 SLOGE("ASEC %s already mounted", id);
San Mehata19b2502010-01-06 10:33:53 -08001437 errno = EBUSY;
1438 return -1;
1439 }
1440
San Mehatd9a4e352010-03-12 13:32:47 -08001441 char idHash[33];
1442 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -07001443 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -08001444 return -1;
1445 }
Kenny Root7b18a7b2010-03-15 13:13:41 -07001446
San Mehata19b2502010-01-06 10:33:53 -08001447 char loopDevice[255];
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -07001448 if (setupLoopDevice(loopDevice, sizeof(loopDevice), asecFileName, idHash, mDebug))
1449 return -1;
San Mehatb78a32c2010-01-10 13:02:12 -08001450
1451 char dmDevice[255];
1452 bool cleanupDm = false;
Tim Murray8439dc92014-12-15 11:56:11 -08001453
Hiroaki Miyazawa14eab552015-02-04 13:29:15 +09001454 unsigned long nr_sec = 0;
San Mehatfcf24fe2010-03-03 12:37:32 -08001455 struct asec_superblock sb;
San Mehatfcf24fe2010-03-03 12:37:32 -08001456
Kenny Root344ca102012-04-03 17:23:01 -07001457 if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) {
1458 return -1;
1459 }
San Mehatfcf24fe2010-03-03 12:37:32 -08001460
San Mehatd9a4e352010-03-12 13:32:47 -08001461 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -07001462 SLOGD("Container sb magic/ver (%.8x/%.2x)", sb.magic, sb.ver);
San Mehatd9a4e352010-03-12 13:32:47 -08001463 }
San Mehatfcf24fe2010-03-03 12:37:32 -08001464 if (sb.magic != ASEC_SB_MAGIC || sb.ver != ASEC_SB_VER) {
San Mehat97ac40e2010-03-24 10:24:19 -07001465 SLOGE("Bad container magic/version (%.8x/%.2x)", sb.magic, sb.ver);
San Mehatfcf24fe2010-03-03 12:37:32 -08001466 Loop::destroyByDevice(loopDevice);
1467 errno = EMEDIUMTYPE;
1468 return -1;
1469 }
1470 nr_sec--; // We don't want the devmapping to extend onto our superblock
1471
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -07001472 if (setupDevMapperDevice(dmDevice, sizeof(dmDevice), loopDevice, asecFileName, key, idHash , nr_sec, &cleanupDm, mDebug)) {
1473 Loop::destroyByDevice(loopDevice);
1474 return -1;
San Mehata19b2502010-01-06 10:33:53 -08001475 }
1476
Kenny Root344ca102012-04-03 17:23:01 -07001477 if (mkdir(mountPoint, 0000)) {
San Mehatb78a32c2010-01-10 13:02:12 -08001478 if (errno != EEXIST) {
San Mehat97ac40e2010-03-24 10:24:19 -07001479 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -08001480 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -08001481 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -08001482 }
1483 Loop::destroyByDevice(loopDevice);
1484 return -1;
1485 }
San Mehata19b2502010-01-06 10:33:53 -08001486 }
1487
Kenny Rootcdc2a1c2012-05-03 13:49:46 -07001488 /*
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -07001489 * Wait for the device mapper node to be created.
Kenny Rootcdc2a1c2012-05-03 13:49:46 -07001490 */
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -07001491 waitForDevMapper(dmDevice);
Kenny Rootcdc2a1c2012-05-03 13:49:46 -07001492
Kenny Root344ca102012-04-03 17:23:01 -07001493 int result;
1494 if (sb.c_opts & ASEC_SB_C_OPTS_EXT4) {
Jeff Sharkey43ed1232014-08-22 12:29:05 -07001495 result = Ext4::doMount(dmDevice, mountPoint, readOnly, false, readOnly);
Kenny Root344ca102012-04-03 17:23:01 -07001496 } else {
Jeff Sharkey43ed1232014-08-22 12:29:05 -07001497 result = Fat::doMount(dmDevice, mountPoint, readOnly, false, readOnly, ownerUid, 0, 0222, false);
Kenny Root344ca102012-04-03 17:23:01 -07001498 }
1499
1500 if (result) {
San Mehat97ac40e2010-03-24 10:24:19 -07001501 SLOGE("ASEC mount failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -08001502 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -08001503 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -08001504 }
1505 Loop::destroyByDevice(loopDevice);
San Mehata19b2502010-01-06 10:33:53 -08001506 return -1;
1507 }
1508
Kenny Rootcbacf782010-09-24 15:11:48 -07001509 mActiveContainers->push_back(new ContainerData(strdup(id), ASEC));
San Mehatd9a4e352010-03-12 13:32:47 -08001510 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -07001511 SLOGD("ASEC %s mounted", id);
San Mehatd9a4e352010-03-12 13:32:47 -08001512 }
San Mehata19b2502010-01-06 10:33:53 -08001513 return 0;
1514}
1515
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001516/**
1517 * Mounts an image file <code>img</code>.
1518 */
Jeff Sharkey69479042012-09-25 16:14:57 -07001519int VolumeManager::mountObb(const char *img, const char *key, int ownerGid) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001520 char mountPoint[255];
1521
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001522 char idHash[33];
1523 if (!asecHash(img, idHash, sizeof(idHash))) {
1524 SLOGE("Hash of '%s' failed (%s)", img, strerror(errno));
1525 return -1;
1526 }
1527
Jeff Sharkey9f18fe72015-04-01 23:32:18 -07001528 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::LOOPDIR, idHash);
rpcraigd1c226f2012-10-09 06:58:16 -04001529 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
Colin Cross59846b62014-02-06 20:34:29 -08001530 SLOGE("OBB mount failed for %s: couldn't construct mountpoint", img);
rpcraigd1c226f2012-10-09 06:58:16 -04001531 return -1;
1532 }
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001533
1534 if (isMountpointMounted(mountPoint)) {
1535 SLOGE("Image %s already mounted", img);
1536 errno = EBUSY;
1537 return -1;
1538 }
1539
1540 char loopDevice[255];
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -07001541 if (setupLoopDevice(loopDevice, sizeof(loopDevice), img, idHash, mDebug))
1542 return -1;
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001543
1544 char dmDevice[255];
1545 bool cleanupDm = false;
1546 int fd;
Hiroaki Miyazawa14eab552015-02-04 13:29:15 +09001547 unsigned long nr_sec = 0;
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001548
Jeff Sharkeyce6a9132015-04-08 21:07:21 -07001549 if ((fd = open(loopDevice, O_RDWR | O_CLOEXEC)) < 0) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001550 SLOGE("Failed to open loopdevice (%s)", strerror(errno));
1551 Loop::destroyByDevice(loopDevice);
1552 return -1;
1553 }
1554
Hiroaki Miyazawa14eab552015-02-04 13:29:15 +09001555 get_blkdev_size(fd, &nr_sec);
1556 if (nr_sec == 0) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001557 SLOGE("Failed to get loop size (%s)", strerror(errno));
1558 Loop::destroyByDevice(loopDevice);
1559 close(fd);
1560 return -1;
1561 }
1562
1563 close(fd);
1564
Hiroaki Miyazawa14eab552015-02-04 13:29:15 +09001565 if (setupDevMapperDevice(dmDevice, sizeof(loopDevice), loopDevice, img,key, idHash, nr_sec, &cleanupDm, mDebug)) {
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -07001566 Loop::destroyByDevice(loopDevice);
1567 return -1;
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001568 }
1569
1570 if (mkdir(mountPoint, 0755)) {
1571 if (errno != EEXIST) {
1572 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
1573 if (cleanupDm) {
1574 Devmapper::destroy(idHash);
1575 }
1576 Loop::destroyByDevice(loopDevice);
1577 return -1;
1578 }
1579 }
1580
Jeff Sharkey69479042012-09-25 16:14:57 -07001581 if (Fat::doMount(dmDevice, mountPoint, true, false, true, 0, ownerGid,
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001582 0227, false)) {
1583 SLOGE("Image mount failed (%s)", strerror(errno));
1584 if (cleanupDm) {
1585 Devmapper::destroy(idHash);
1586 }
1587 Loop::destroyByDevice(loopDevice);
1588 return -1;
1589 }
1590
Kenny Rootcbacf782010-09-24 15:11:48 -07001591 mActiveContainers->push_back(new ContainerData(strdup(img), OBB));
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001592 if (mDebug) {
1593 SLOGD("Image %s mounted", img);
1594 }
1595 return 0;
1596}
1597
Kenny Root508c0e12010-07-12 09:59:49 -07001598int VolumeManager::listMountedObbs(SocketClient* cli) {
Yabin Cuid1104f72015-01-02 13:28:28 -08001599 FILE *fp = setmntent("/proc/mounts", "r");
1600 if (fp == NULL) {
Kenny Root508c0e12010-07-12 09:59:49 -07001601 SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
1602 return -1;
1603 }
1604
1605 // Create a string to compare against that has a trailing slash
Jeff Sharkey9f18fe72015-04-01 23:32:18 -07001606 int loopDirLen = strlen(VolumeManager::LOOPDIR);
Kenny Root508c0e12010-07-12 09:59:49 -07001607 char loopDir[loopDirLen + 2];
Jeff Sharkey9f18fe72015-04-01 23:32:18 -07001608 strcpy(loopDir, VolumeManager::LOOPDIR);
Kenny Root508c0e12010-07-12 09:59:49 -07001609 loopDir[loopDirLen++] = '/';
1610 loopDir[loopDirLen] = '\0';
1611
Yabin Cuid1104f72015-01-02 13:28:28 -08001612 mntent* mentry;
1613 while ((mentry = getmntent(fp)) != NULL) {
1614 if (!strncmp(mentry->mnt_dir, loopDir, loopDirLen)) {
Jeff Sharkeyce6a9132015-04-08 21:07:21 -07001615 int fd = open(mentry->mnt_fsname, O_RDONLY | O_CLOEXEC);
Kenny Root508c0e12010-07-12 09:59:49 -07001616 if (fd >= 0) {
1617 struct loop_info64 li;
1618 if (ioctl(fd, LOOP_GET_STATUS64, &li) >= 0) {
1619 cli->sendMsg(ResponseCode::AsecListResult,
1620 (const char*) li.lo_file_name, false);
1621 }
1622 close(fd);
1623 }
1624 }
1625 }
Yabin Cuid1104f72015-01-02 13:28:28 -08001626 endmntent(fp);
Kenny Root508c0e12010-07-12 09:59:49 -07001627 return 0;
1628}
1629
Jeff Sharkey9c484982015-03-31 10:35:33 -07001630extern "C" int vold_unmountAll(void) {
Ken Sumrall425524d2012-06-14 20:55:28 -07001631 VolumeManager *vm = VolumeManager::Instance();
Jeff Sharkey9c484982015-03-31 10:35:33 -07001632 return vm->unmountAll();
Ken Sumrall425524d2012-06-14 20:55:28 -07001633}
1634
San Mehata19b2502010-01-06 10:33:53 -08001635bool VolumeManager::isMountpointMounted(const char *mp)
1636{
Yabin Cuid1104f72015-01-02 13:28:28 -08001637 FILE *fp = setmntent("/proc/mounts", "r");
1638 if (fp == NULL) {
San Mehat97ac40e2010-03-24 10:24:19 -07001639 SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -08001640 return false;
1641 }
1642
Yabin Cuid1104f72015-01-02 13:28:28 -08001643 bool found_mp = false;
1644 mntent* mentry;
1645 while ((mentry = getmntent(fp)) != NULL) {
1646 if (strcmp(mentry->mnt_dir, mp) == 0) {
1647 found_mp = true;
1648 break;
San Mehata19b2502010-01-06 10:33:53 -08001649 }
San Mehata19b2502010-01-06 10:33:53 -08001650 }
Yabin Cuid1104f72015-01-02 13:28:28 -08001651 endmntent(fp);
1652 return found_mp;
San Mehata19b2502010-01-06 10:33:53 -08001653}
1654
Jeff Sharkey71ebe152013-09-17 17:24:38 -07001655int VolumeManager::mkdirs(char* path) {
Jeff Sharkey36801cc2015-03-13 16:09:20 -07001656 // Only offer to create directories for paths managed by vold
1657 if (strncmp(path, "/storage/", 9) == 0) {
1658 // fs_mkdirs() does symlink checking and relative path enforcement
1659 return fs_mkdirs(path, 0700);
Jeff Sharkey71ebe152013-09-17 17:24:38 -07001660 } else {
Cylen Yao27cfee32014-05-02 19:23:42 +08001661 SLOGE("Failed to find mounted volume for %s", path);
Jeff Sharkey71ebe152013-09-17 17:24:38 -07001662 return -EINVAL;
1663 }
Jeff Sharkey71ebe152013-09-17 17:24:38 -07001664}