blob: bbafa428f962d4cb50230c2f5ff62a899ecc628d [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
Mike Lockwood97f2fc12011-06-07 10:51:38 -070062#define MASS_STORAGE_FILE_PATH "/sys/class/android_usb/android0/f_mass_storage/lun/file"
63
Daniel Rosenberg6a74dca2014-05-23 13:47:00 -070064#define ROUND_UP_POWER_OF_2(number, po2) (((!!(number & ((1U << po2) - 1))) << po2)\
65 + (number & (~((1U << po2) - 1))))
66
Jeff Sharkey36801cc2015-03-13 16:09:20 -070067using android::base::StringPrintf;
68
Jeff Sharkey9f18fe72015-04-01 23:32:18 -070069/*
70 * Path to external storage where *only* root can access ASEC image files
71 */
72const char *VolumeManager::SEC_ASECDIR_EXT = "/mnt/secure/asec";
73
74/*
75 * Path to internal storage where *only* root can access ASEC image files
76 */
77const char *VolumeManager::SEC_ASECDIR_INT = "/data/app-asec";
78
79/*
80 * Path to where secure containers are mounted
81 */
82const char *VolumeManager::ASECDIR = "/mnt/asec";
83
84/*
85 * Path to where OBBs are mounted
86 */
87const char *VolumeManager::LOOPDIR = "/mnt/obb";
88
Jeff Sharkey36801cc2015-03-13 16:09:20 -070089static const char* kUserMountPath = "/mnt/user";
90
91static const unsigned int kMajorBlockScsi = 8;
92static const unsigned int kMajorBlockMmc = 179;
93
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -070094/* writes superblock at end of file or device given by name */
95static int writeSuperBlock(const char* name, struct asec_superblock *sb, unsigned int numImgSectors) {
Jeff Sharkeyce6a9132015-04-08 21:07:21 -070096 int sbfd = open(name, O_RDWR | O_CLOEXEC);
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -070097 if (sbfd < 0) {
98 SLOGE("Failed to open %s for superblock write (%s)", name, strerror(errno));
99 return -1;
100 }
101
102 if (lseek(sbfd, (numImgSectors * 512), SEEK_SET) < 0) {
103 SLOGE("Failed to lseek for superblock (%s)", strerror(errno));
104 close(sbfd);
105 return -1;
106 }
107
108 if (write(sbfd, sb, sizeof(struct asec_superblock)) != sizeof(struct asec_superblock)) {
109 SLOGE("Failed to write superblock (%s)", strerror(errno));
110 close(sbfd);
111 return -1;
112 }
113 close(sbfd);
114 return 0;
115}
116
117static int adjustSectorNumExt4(unsigned numSectors) {
Daniel Rosenberge9196fe2014-06-10 17:16:03 -0700118 // Ext4 started to reserve 2% or 4096 clusters, whichever is smaller for
119 // preventing costly operations or unexpected ENOSPC error.
120 // Ext4::format() uses default block size without clustering.
121 unsigned clusterSectors = 4096 / 512;
122 unsigned reservedSectors = (numSectors * 2)/100 + (numSectors % 50 > 0);
123 numSectors += reservedSectors > (4096 * clusterSectors) ? (4096 * clusterSectors) : reservedSectors;
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -0700124 return ROUND_UP_POWER_OF_2(numSectors, 3);
125}
126
127static int adjustSectorNumFAT(unsigned numSectors) {
128 /*
129 * Add some headroom
130 */
131 unsigned fatSize = (((numSectors * 4) / 512) + 1) * 2;
132 numSectors += fatSize + 2;
133 /*
134 * FAT is aligned to 32 kb with 512b sectors.
135 */
136 return ROUND_UP_POWER_OF_2(numSectors, 6);
137}
138
139static int setupLoopDevice(char* buffer, size_t len, const char* asecFileName, const char* idHash, bool debug) {
140 if (Loop::lookupActive(idHash, buffer, len)) {
141 if (Loop::create(idHash, asecFileName, buffer, len)) {
142 SLOGE("ASEC loop device creation failed for %s (%s)", asecFileName, strerror(errno));
143 return -1;
144 }
145 if (debug) {
146 SLOGD("New loop device created at %s", buffer);
147 }
148 } else {
149 if (debug) {
150 SLOGD("Found active loopback for %s at %s", asecFileName, buffer);
151 }
152 }
153 return 0;
154}
155
156static 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) {
157 if (strcmp(key, "none")) {
158 if (Devmapper::lookupActive(idHash, buffer, len)) {
159 if (Devmapper::create(idHash, loopDevice, key, numImgSectors,
160 buffer, len)) {
161 SLOGE("ASEC device mapping failed for %s (%s)", asecFileName, strerror(errno));
162 return -1;
163 }
164 if (debug) {
165 SLOGD("New devmapper instance created at %s", buffer);
166 }
167 } else {
168 if (debug) {
169 SLOGD("Found active devmapper for %s at %s", asecFileName, buffer);
170 }
171 }
172 *createdDMDevice = true;
173 } else {
174 strcpy(buffer, loopDevice);
175 *createdDMDevice = false;
176 }
177 return 0;
178}
179
180static void waitForDevMapper(const char *dmDevice) {
181 /*
182 * Wait for the device mapper node to be created. Sometimes it takes a
183 * while. Wait for up to 1 second. We could also inspect incoming uevents,
184 * but that would take more effort.
185 */
186 int tries = 25;
187 while (tries--) {
188 if (!access(dmDevice, F_OK) || errno != ENOENT) {
189 break;
190 }
191 usleep(40 * 1000);
192 }
193}
194
San Mehatf1b736b2009-10-10 17:22:08 -0700195VolumeManager *VolumeManager::sInstance = NULL;
196
197VolumeManager *VolumeManager::Instance() {
198 if (!sInstance)
199 sInstance = new VolumeManager();
200 return sInstance;
201}
202
203VolumeManager::VolumeManager() {
San Mehatd9a4e352010-03-12 13:32:47 -0800204 mDebug = false;
San Mehat88705162010-01-15 09:26:28 -0800205 mActiveContainers = new AsecIdCollection();
San Mehatf1b736b2009-10-10 17:22:08 -0700206 mBroadcaster = NULL;
Mike Lockwooda28056b2010-10-28 15:21:24 -0400207 mUmsSharingCount = 0;
208 mSavedDirtyRatio = -1;
209 // set dirty ratio to 0 when UMS is active
210 mUmsDirtyRatio = 0;
San Mehatf1b736b2009-10-10 17:22:08 -0700211}
212
213VolumeManager::~VolumeManager() {
San Mehat88705162010-01-15 09:26:28 -0800214 delete mActiveContainers;
San Mehatf1b736b2009-10-10 17:22:08 -0700215}
216
Kenny Root7b18a7b2010-03-15 13:13:41 -0700217char *VolumeManager::asecHash(const char *id, char *buffer, size_t len) {
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700218 static const char* digits = "0123456789abcdef";
219
Kenny Root7b18a7b2010-03-15 13:13:41 -0700220 unsigned char sig[MD5_DIGEST_LENGTH];
221
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700222 if (buffer == NULL) {
223 SLOGE("Destination buffer is NULL");
224 errno = ESPIPE;
225 return NULL;
226 } else if (id == NULL) {
227 SLOGE("Source buffer is NULL");
228 errno = ESPIPE;
229 return NULL;
230 } else if (len < MD5_ASCII_LENGTH_PLUS_NULL) {
Colin Cross59846b62014-02-06 20:34:29 -0800231 SLOGE("Target hash buffer size < %d bytes (%zu)",
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700232 MD5_ASCII_LENGTH_PLUS_NULL, len);
San Mehatd9a4e352010-03-12 13:32:47 -0800233 errno = ESPIPE;
234 return NULL;
235 }
Kenny Root7b18a7b2010-03-15 13:13:41 -0700236
237 MD5(reinterpret_cast<const unsigned char*>(id), strlen(id), sig);
San Mehatd9a4e352010-03-12 13:32:47 -0800238
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700239 char *p = buffer;
Kenny Root7b18a7b2010-03-15 13:13:41 -0700240 for (int i = 0; i < MD5_DIGEST_LENGTH; i++) {
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700241 *p++ = digits[sig[i] >> 4];
242 *p++ = digits[sig[i] & 0x0F];
San Mehatd9a4e352010-03-12 13:32:47 -0800243 }
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700244 *p = '\0';
San Mehatd9a4e352010-03-12 13:32:47 -0800245
246 return buffer;
247}
248
Jeff Sharkeyf1b996d2015-04-17 17:35:20 -0700249int VolumeManager::setDebug(bool enable) {
San Mehatd9a4e352010-03-12 13:32:47 -0800250 mDebug = enable;
Jeff Sharkeyf1b996d2015-04-17 17:35:20 -0700251 return 0;
San Mehatd9a4e352010-03-12 13:32:47 -0800252}
253
San Mehatf1b736b2009-10-10 17:22:08 -0700254int VolumeManager::start() {
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700255 // Always start from a clean slate by unmounting everything in
256 // directories that we own, in case we crashed.
Jeff Sharkey9c484982015-03-31 10:35:33 -0700257 unmountAll();
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700258
259 // Assume that we always have an emulated volume on internal
260 // storage; the framework will decide if it should be mounted.
261 mInternalEmulated = std::shared_ptr<android::vold::VolumeBase>(
Jeff Sharkey3161fb32015-04-12 16:03:33 -0700262 new android::vold::EmulatedVolume("/data/media"));
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700263 mInternalEmulated->create();
264
San Mehatf1b736b2009-10-10 17:22:08 -0700265 return 0;
266}
267
268int VolumeManager::stop() {
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700269 mInternalEmulated->destroy();
270 mInternalEmulated = nullptr;
San Mehatf1b736b2009-10-10 17:22:08 -0700271 return 0;
272}
273
San Mehatfd7f5872009-10-12 11:32:47 -0700274void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
Jeff Sharkeyf1b996d2015-04-17 17:35:20 -0700275 if (mDebug) {
276 LOG(VERBOSE) << "----------------";
277 LOG(VERBOSE) << "handleBlockEvent with action " << (int) evt->getAction();
278 evt->dump();
279 }
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: {
Jeff Sharkey7d9d0112015-04-14 23:14:23 -0700313 LOG(DEBUG) << "Disk at " << major << ":" << minor << " changed";
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700314 for (auto disk : mDisks) {
315 if (disk->getDevice() == device) {
316 disk->readMetadata();
317 disk->readPartitions();
318 }
319 }
320 break;
321 }
322 case NetlinkEvent::Action::kRemove: {
323 auto i = mDisks.begin();
324 while (i != mDisks.end()) {
325 if ((*i)->getDevice() == device) {
326 (*i)->destroy();
327 i = mDisks.erase(i);
328 } else {
329 ++i;
330 }
331 }
332 break;
333 }
334 default: {
335 LOG(WARNING) << "Unexpected block event action " << (int) evt->getAction();
336 break;
337 }
338 }
339}
340
341void VolumeManager::addDiskSource(const std::shared_ptr<DiskSource>& diskSource) {
342 mDiskSources.push_back(diskSource);
343}
344
345std::shared_ptr<android::vold::Disk> VolumeManager::findDisk(const std::string& id) {
346 for (auto disk : mDisks) {
347 if (disk->getId() == id) {
348 return disk;
San Mehatf1b736b2009-10-10 17:22:08 -0700349 }
350 }
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700351 return nullptr;
352}
San Mehatf1b736b2009-10-10 17:22:08 -0700353
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700354std::shared_ptr<android::vold::VolumeBase> VolumeManager::findVolume(const std::string& id) {
355 if (mInternalEmulated->getId() == id) {
356 return mInternalEmulated;
San Mehatf1b736b2009-10-10 17:22:08 -0700357 }
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700358 for (auto disk : mDisks) {
359 auto vol = disk->findVolume(id);
360 if (vol != nullptr) {
361 return vol;
362 }
363 }
364 return nullptr;
365}
366
367int VolumeManager::linkPrimary(userid_t userId) {
368 std::string source(mPrimary->getPath());
369 if (mPrimary->getType() == android::vold::VolumeBase::Type::kEmulated) {
370 source = StringPrintf("%s/%d", source.c_str(), userId);
371 }
372
373 std::string target(StringPrintf("/mnt/user/%d/primary", userId));
374 if (TEMP_FAILURE_RETRY(unlink(target.c_str()))) {
375 if (errno != ENOENT) {
376 SLOGW("Failed to unlink %s: %s", target.c_str(), strerror(errno));
377 }
378 }
379 if (TEMP_FAILURE_RETRY(symlink(source.c_str(), target.c_str()))) {
380 SLOGW("Failed to link %s to %s: %s", source.c_str(), target.c_str(),
381 strerror(errno));
382 return -errno;
383 }
384 return 0;
385}
386
387int VolumeManager::startUser(userid_t userId) {
388 // Note that sometimes the system will spin up processes from Zygote
389 // before actually starting the user, so we're okay if Zygote
390 // already created this directory.
391 std::string path(StringPrintf("%s/%d", kUserMountPath, userId));
392 fs_prepare_dir(path.c_str(), 0755, AID_ROOT, AID_ROOT);
393
394 mUsers.push_back(userId);
395 if (mPrimary) {
396 linkPrimary(userId);
397 }
398 return 0;
399}
400
401int VolumeManager::cleanupUser(userid_t userId) {
402 mUsers.remove(userId);
403 return 0;
404}
405
406int VolumeManager::setPrimary(const std::shared_ptr<android::vold::VolumeBase>& vol) {
407 mPrimary = vol;
408 for (userid_t userId : mUsers) {
409 linkPrimary(userId);
410 }
411 return 0;
412}
413
414int VolumeManager::reset() {
415 // Tear down all existing disks/volumes and start from a blank slate so
416 // newly connected framework hears all events.
417 mInternalEmulated->destroy();
418 mInternalEmulated->create();
419 for (auto disk : mDisks) {
420 disk->destroy();
421 disk->create();
422 }
423 mUsers.clear();
424 return 0;
425}
426
427int VolumeManager::shutdown() {
Jeff Sharkey9c484982015-03-31 10:35:33 -0700428 mInternalEmulated->destroy();
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700429 for (auto disk : mDisks) {
430 disk->destroy();
431 }
432 mDisks.clear();
433 return 0;
San Mehatf1b736b2009-10-10 17:22:08 -0700434}
435
Jeff Sharkey9c484982015-03-31 10:35:33 -0700436int VolumeManager::unmountAll() {
437 // First, try gracefully unmounting all known devices
438 if (mInternalEmulated != nullptr) {
439 mInternalEmulated->unmount();
440 }
441 for (auto disk : mDisks) {
442 disk->unmountAll();
443 }
444
445 // Worst case we might have some stale mounts lurking around, so
446 // force unmount those just to be safe.
447 FILE* fp = setmntent("/proc/mounts", "r");
448 if (fp == NULL) {
449 SLOGE("Error opening /proc/mounts: %s", strerror(errno));
450 return -errno;
451 }
452
453 // Some volumes can be stacked on each other, so force unmount in
454 // reverse order to give us the best chance of success.
455 std::list<std::string> toUnmount;
456 mntent* mentry;
457 while ((mentry = getmntent(fp)) != NULL) {
458 if (strncmp(mentry->mnt_dir, "/mnt/", 5) == 0
459 || strncmp(mentry->mnt_dir, "/storage/", 9) == 0) {
460 toUnmount.push_front(std::string(mentry->mnt_dir));
461 }
462 }
463 endmntent(fp);
464
465 for (auto path : toUnmount) {
466 SLOGW("Tearing down stale mount %s", path.c_str());
467 android::vold::ForceUnmount(path);
468 }
469
470 return 0;
471}
472
Kenny Root508c0e12010-07-12 09:59:49 -0700473int VolumeManager::getObbMountPath(const char *sourceFile, char *mountPath, int mountPathLen) {
474 char idHash[33];
475 if (!asecHash(sourceFile, idHash, sizeof(idHash))) {
476 SLOGE("Hash of '%s' failed (%s)", sourceFile, strerror(errno));
477 return -1;
478 }
479
480 memset(mountPath, 0, mountPathLen);
Jeff Sharkey9f18fe72015-04-01 23:32:18 -0700481 int written = snprintf(mountPath, mountPathLen, "%s/%s", VolumeManager::LOOPDIR, idHash);
rpcraigd1c226f2012-10-09 06:58:16 -0400482 if ((written < 0) || (written >= mountPathLen)) {
483 errno = EINVAL;
484 return -1;
485 }
Kenny Root508c0e12010-07-12 09:59:49 -0700486
487 if (access(mountPath, F_OK)) {
488 errno = ENOENT;
489 return -1;
490 }
491
492 return 0;
493}
494
San Mehata19b2502010-01-06 10:33:53 -0800495int VolumeManager::getAsecMountPath(const char *id, char *buffer, int maxlen) {
San Mehat88ac2c02010-03-23 11:15:58 -0700496 char asecFileName[255];
Kenny Root344ca102012-04-03 17:23:01 -0700497
Nick Kralevich0de7c612014-01-27 14:58:06 -0800498 if (!isLegalAsecId(id)) {
499 SLOGE("getAsecMountPath: Invalid asec id \"%s\"", id);
500 errno = EINVAL;
501 return -1;
502 }
503
Kenny Root344ca102012-04-03 17:23:01 -0700504 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
505 SLOGE("Couldn't find ASEC %s", id);
506 return -1;
507 }
San Mehat88ac2c02010-03-23 11:15:58 -0700508
509 memset(buffer, 0, maxlen);
510 if (access(asecFileName, F_OK)) {
511 errno = ENOENT;
512 return -1;
513 }
San Mehata19b2502010-01-06 10:33:53 -0800514
Jeff Sharkey9f18fe72015-04-01 23:32:18 -0700515 int written = snprintf(buffer, maxlen, "%s/%s", VolumeManager::ASECDIR, id);
rpcraigd1c226f2012-10-09 06:58:16 -0400516 if ((written < 0) || (written >= maxlen)) {
517 SLOGE("getAsecMountPath failed for %s: couldn't construct path in buffer", id);
518 errno = EINVAL;
519 return -1;
520 }
521
San Mehata19b2502010-01-06 10:33:53 -0800522 return 0;
523}
524
Dianne Hackborn736910c2011-06-27 13:37:07 -0700525int VolumeManager::getAsecFilesystemPath(const char *id, char *buffer, int maxlen) {
526 char asecFileName[255];
Kenny Root344ca102012-04-03 17:23:01 -0700527
Nick Kralevich0de7c612014-01-27 14:58:06 -0800528 if (!isLegalAsecId(id)) {
529 SLOGE("getAsecFilesystemPath: Invalid asec id \"%s\"", id);
530 errno = EINVAL;
531 return -1;
532 }
533
Kenny Root344ca102012-04-03 17:23:01 -0700534 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
535 SLOGE("Couldn't find ASEC %s", id);
536 return -1;
537 }
Dianne Hackborn736910c2011-06-27 13:37:07 -0700538
539 memset(buffer, 0, maxlen);
540 if (access(asecFileName, F_OK)) {
541 errno = ENOENT;
542 return -1;
543 }
544
rpcraigd1c226f2012-10-09 06:58:16 -0400545 int written = snprintf(buffer, maxlen, "%s", asecFileName);
546 if ((written < 0) || (written >= maxlen)) {
547 errno = EINVAL;
548 return -1;
549 }
550
Dianne Hackborn736910c2011-06-27 13:37:07 -0700551 return 0;
552}
553
Kenny Root344ca102012-04-03 17:23:01 -0700554int VolumeManager::createAsec(const char *id, unsigned int numSectors, const char *fstype,
555 const char *key, const int ownerUid, bool isExternal) {
San Mehatfcf24fe2010-03-03 12:37:32 -0800556 struct asec_superblock sb;
557 memset(&sb, 0, sizeof(sb));
558
Nick Kralevich0de7c612014-01-27 14:58:06 -0800559 if (!isLegalAsecId(id)) {
560 SLOGE("createAsec: Invalid asec id \"%s\"", id);
561 errno = EINVAL;
562 return -1;
563 }
564
Kenny Root344ca102012-04-03 17:23:01 -0700565 const bool wantFilesystem = strcmp(fstype, "none");
566 bool usingExt4 = false;
567 if (wantFilesystem) {
568 usingExt4 = !strcmp(fstype, "ext4");
569 if (usingExt4) {
570 sb.c_opts |= ASEC_SB_C_OPTS_EXT4;
571 } else if (strcmp(fstype, "fat")) {
572 SLOGE("Invalid filesystem type %s", fstype);
573 errno = EINVAL;
574 return -1;
575 }
576 }
577
San Mehatfcf24fe2010-03-03 12:37:32 -0800578 sb.magic = ASEC_SB_MAGIC;
579 sb.ver = ASEC_SB_VER;
San Mehata19b2502010-01-06 10:33:53 -0800580
San Mehatd31e3802010-02-18 08:37:45 -0800581 if (numSectors < ((1024*1024)/512)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700582 SLOGE("Invalid container size specified (%d sectors)", numSectors);
San Mehatd31e3802010-02-18 08:37:45 -0800583 errno = EINVAL;
584 return -1;
585 }
586
San Mehata19b2502010-01-06 10:33:53 -0800587 char asecFileName[255];
Kenny Root344ca102012-04-03 17:23:01 -0700588
589 if (!findAsec(id, asecFileName, sizeof(asecFileName))) {
590 SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
591 asecFileName, strerror(errno));
592 errno = EADDRINUSE;
593 return -1;
594 }
595
Jeff Sharkey9f18fe72015-04-01 23:32:18 -0700596 const char *asecDir = isExternal ? VolumeManager::SEC_ASECDIR_EXT : VolumeManager::SEC_ASECDIR_INT;
Kenny Root344ca102012-04-03 17:23:01 -0700597
rpcraigd1c226f2012-10-09 06:58:16 -0400598 int written = snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", asecDir, id);
599 if ((written < 0) || (size_t(written) >= sizeof(asecFileName))) {
600 errno = EINVAL;
601 return -1;
602 }
San Mehata19b2502010-01-06 10:33:53 -0800603
604 if (!access(asecFileName, F_OK)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700605 SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
Kenny Root344ca102012-04-03 17:23:01 -0700606 asecFileName, strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800607 errno = EADDRINUSE;
608 return -1;
609 }
610
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -0700611 unsigned numImgSectors;
Daniel Rosenberg6a74dca2014-05-23 13:47:00 -0700612 if (usingExt4)
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -0700613 numImgSectors = adjustSectorNumExt4(numSectors);
Daniel Rosenberg6a74dca2014-05-23 13:47:00 -0700614 else
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -0700615 numImgSectors = adjustSectorNumFAT(numSectors);
San Mehatfcf24fe2010-03-03 12:37:32 -0800616
617 // Add +1 for our superblock which is at the end
618 if (Loop::createImageFile(asecFileName, numImgSectors + 1)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700619 SLOGE("ASEC image file creation failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800620 return -1;
621 }
622
San Mehatd9a4e352010-03-12 13:32:47 -0800623 char idHash[33];
624 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700625 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800626 unlink(asecFileName);
627 return -1;
628 }
629
San Mehata19b2502010-01-06 10:33:53 -0800630 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800631 if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700632 SLOGE("ASEC loop device creation failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800633 unlink(asecFileName);
634 return -1;
635 }
636
San Mehatb78a32c2010-01-10 13:02:12 -0800637 char dmDevice[255];
638 bool cleanupDm = false;
San Mehata19b2502010-01-06 10:33:53 -0800639
San Mehatb78a32c2010-01-10 13:02:12 -0800640 if (strcmp(key, "none")) {
San Mehatfcf24fe2010-03-03 12:37:32 -0800641 // XXX: This is all we support for now
642 sb.c_cipher = ASEC_SB_C_CIPHER_TWOFISH;
San Mehatd9a4e352010-03-12 13:32:47 -0800643 if (Devmapper::create(idHash, loopDevice, key, numImgSectors, dmDevice,
San Mehatb78a32c2010-01-10 13:02:12 -0800644 sizeof(dmDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700645 SLOGE("ASEC device mapping failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800646 Loop::destroyByDevice(loopDevice);
647 unlink(asecFileName);
648 return -1;
649 }
650 cleanupDm = true;
651 } else {
San Mehatfcf24fe2010-03-03 12:37:32 -0800652 sb.c_cipher = ASEC_SB_C_CIPHER_NONE;
San Mehatb78a32c2010-01-10 13:02:12 -0800653 strcpy(dmDevice, loopDevice);
654 }
655
San Mehatfcf24fe2010-03-03 12:37:32 -0800656 /*
657 * Drop down the superblock at the end of the file
658 */
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -0700659 if (writeSuperBlock(loopDevice, &sb, numImgSectors)) {
San Mehatfcf24fe2010-03-03 12:37:32 -0800660 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800661 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800662 }
663 Loop::destroyByDevice(loopDevice);
664 unlink(asecFileName);
665 return -1;
666 }
667
Kenny Root344ca102012-04-03 17:23:01 -0700668 if (wantFilesystem) {
669 int formatStatus;
rpcraiga54e13a2012-09-21 14:17:08 -0400670 char mountPoint[255];
671
Jeff Sharkey9f18fe72015-04-01 23:32:18 -0700672 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id);
rpcraigd1c226f2012-10-09 06:58:16 -0400673 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
674 SLOGE("ASEC fs format failed: couldn't construct mountPoint");
675 if (cleanupDm) {
676 Devmapper::destroy(idHash);
677 }
678 Loop::destroyByDevice(loopDevice);
679 unlink(asecFileName);
680 return -1;
681 }
rpcraiga54e13a2012-09-21 14:17:08 -0400682
Kenny Root344ca102012-04-03 17:23:01 -0700683 if (usingExt4) {
Daniel Rosenberg6a74dca2014-05-23 13:47:00 -0700684 formatStatus = Ext4::format(dmDevice, numImgSectors, mountPoint);
Kenny Root344ca102012-04-03 17:23:01 -0700685 } else {
Ken Sumrall9caab762013-06-11 19:10:20 -0700686 formatStatus = Fat::format(dmDevice, numImgSectors, 0);
San Mehatb78a32c2010-01-10 13:02:12 -0800687 }
San Mehata19b2502010-01-06 10:33:53 -0800688
Kenny Root344ca102012-04-03 17:23:01 -0700689 if (formatStatus < 0) {
690 SLOGE("ASEC fs format failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800691 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800692 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -0800693 }
San Mehateb13a902010-01-07 12:12:50 -0800694 Loop::destroyByDevice(loopDevice);
695 unlink(asecFileName);
696 return -1;
697 }
Kenny Root344ca102012-04-03 17:23:01 -0700698
Kenny Root344ca102012-04-03 17:23:01 -0700699 if (mkdir(mountPoint, 0000)) {
San Mehata1091cb2010-02-28 20:17:20 -0800700 if (errno != EEXIST) {
San Mehat97ac40e2010-03-24 10:24:19 -0700701 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
San Mehata1091cb2010-02-28 20:17:20 -0800702 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800703 Devmapper::destroy(idHash);
San Mehata1091cb2010-02-28 20:17:20 -0800704 }
705 Loop::destroyByDevice(loopDevice);
706 unlink(asecFileName);
707 return -1;
708 }
San Mehatb78a32c2010-01-10 13:02:12 -0800709 }
San Mehata1091cb2010-02-28 20:17:20 -0800710
Kenny Root344ca102012-04-03 17:23:01 -0700711 int mountStatus;
712 if (usingExt4) {
713 mountStatus = Ext4::doMount(dmDevice, mountPoint, false, false, false);
714 } else {
715 mountStatus = Fat::doMount(dmDevice, mountPoint, false, false, false, ownerUid, 0, 0000,
716 false);
717 }
718
719 if (mountStatus) {
San Mehat97ac40e2010-03-24 10:24:19 -0700720 SLOGE("ASEC FAT mount failed (%s)", strerror(errno));
San Mehata1091cb2010-02-28 20:17:20 -0800721 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800722 Devmapper::destroy(idHash);
San Mehata1091cb2010-02-28 20:17:20 -0800723 }
724 Loop::destroyByDevice(loopDevice);
725 unlink(asecFileName);
726 return -1;
727 }
Kenny Root344ca102012-04-03 17:23:01 -0700728
729 if (usingExt4) {
Jeff Sharkeyce6a9132015-04-08 21:07:21 -0700730 int dirfd = open(mountPoint, O_DIRECTORY | O_CLOEXEC);
Kenny Root344ca102012-04-03 17:23:01 -0700731 if (dirfd >= 0) {
732 if (fchown(dirfd, ownerUid, AID_SYSTEM)
733 || fchmod(dirfd, S_IRUSR | S_IWUSR | S_IXUSR | S_ISGID | S_IRGRP | S_IXGRP)) {
734 SLOGI("Cannot chown/chmod new ASEC mount point %s", mountPoint);
735 }
736 close(dirfd);
737 }
738 }
San Mehata1091cb2010-02-28 20:17:20 -0800739 } else {
San Mehat97ac40e2010-03-24 10:24:19 -0700740 SLOGI("Created raw secure container %s (no filesystem)", id);
San Mehata19b2502010-01-06 10:33:53 -0800741 }
San Mehat88705162010-01-15 09:26:28 -0800742
Kenny Rootcbacf782010-09-24 15:11:48 -0700743 mActiveContainers->push_back(new ContainerData(strdup(id), ASEC));
San Mehata19b2502010-01-06 10:33:53 -0800744 return 0;
745}
746
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -0700747int VolumeManager::resizeAsec(const char *id, unsigned numSectors, const char *key) {
748 char asecFileName[255];
749 char mountPoint[255];
750 bool cleanupDm = false;
751
752 if (!isLegalAsecId(id)) {
753 SLOGE("resizeAsec: Invalid asec id \"%s\"", id);
754 errno = EINVAL;
755 return -1;
756 }
757
758 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
759 SLOGE("Couldn't find ASEC %s", id);
760 return -1;
761 }
762
Jeff Sharkey9f18fe72015-04-01 23:32:18 -0700763 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id);
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -0700764 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
765 SLOGE("ASEC resize failed for %s: couldn't construct mountpoint", id);
766 return -1;
767 }
768
769 if (isMountpointMounted(mountPoint)) {
770 SLOGE("ASEC %s mounted. Unmount before resizing", id);
771 errno = EBUSY;
772 return -1;
773 }
774
775 struct asec_superblock sb;
776 int fd;
777 unsigned int oldNumSec = 0;
778
Jeff Sharkeyce6a9132015-04-08 21:07:21 -0700779 if ((fd = open(asecFileName, O_RDONLY | O_CLOEXEC)) < 0) {
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -0700780 SLOGE("Failed to open ASEC file (%s)", strerror(errno));
781 return -1;
782 }
783
784 struct stat info;
785 if (fstat(fd, &info) < 0) {
786 SLOGE("Failed to get file size (%s)", strerror(errno));
787 close(fd);
788 return -1;
789 }
790
791 oldNumSec = info.st_size / 512;
792
793 unsigned numImgSectors;
794 if (sb.c_opts & ASEC_SB_C_OPTS_EXT4)
795 numImgSectors = adjustSectorNumExt4(numSectors);
796 else
797 numImgSectors = adjustSectorNumFAT(numSectors);
798 /*
799 * add one block for the superblock
800 */
801 SLOGD("Resizing from %d sectors to %d sectors", oldNumSec, numImgSectors + 1);
Jeff Sharkey43ed1232014-08-22 12:29:05 -0700802 if (oldNumSec == numImgSectors + 1) {
803 SLOGW("Size unchanged; ignoring resize request");
804 return 0;
805 } else if (oldNumSec > numImgSectors + 1) {
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -0700806 SLOGE("Only growing is currently supported.");
807 close(fd);
808 return -1;
809 }
810
811 /*
812 * Try to read superblock.
813 */
814 memset(&sb, 0, sizeof(struct asec_superblock));
815 if (lseek(fd, ((oldNumSec - 1) * 512), SEEK_SET) < 0) {
816 SLOGE("lseek failed (%s)", strerror(errno));
817 close(fd);
818 return -1;
819 }
820 if (read(fd, &sb, sizeof(struct asec_superblock)) != sizeof(struct asec_superblock)) {
821 SLOGE("superblock read failed (%s)", strerror(errno));
822 close(fd);
823 return -1;
824 }
825 close(fd);
826
827 if (mDebug) {
828 SLOGD("Container sb magic/ver (%.8x/%.2x)", sb.magic, sb.ver);
829 }
830 if (sb.magic != ASEC_SB_MAGIC || sb.ver != ASEC_SB_VER) {
831 SLOGE("Bad container magic/version (%.8x/%.2x)", sb.magic, sb.ver);
832 errno = EMEDIUMTYPE;
833 return -1;
834 }
835
836 if (!(sb.c_opts & ASEC_SB_C_OPTS_EXT4)) {
837 SLOGE("Only ext4 partitions are supported for resize");
838 errno = EINVAL;
839 return -1;
840 }
841
842 if (Loop::resizeImageFile(asecFileName, numImgSectors + 1)) {
843 SLOGE("Resize of ASEC image file failed. Could not resize %s", id);
844 return -1;
845 }
846
847 /*
848 * Drop down a copy of the superblock at the end of the file
849 */
850 if (writeSuperBlock(asecFileName, &sb, numImgSectors))
851 goto fail;
852
853 char idHash[33];
854 if (!asecHash(id, idHash, sizeof(idHash))) {
855 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
856 goto fail;
857 }
858
859 char loopDevice[255];
860 if (setupLoopDevice(loopDevice, sizeof(loopDevice), asecFileName, idHash, mDebug))
861 goto fail;
862
863 char dmDevice[255];
864
865 if (setupDevMapperDevice(dmDevice, sizeof(dmDevice), loopDevice, asecFileName, key, idHash, numImgSectors, &cleanupDm, mDebug)) {
866 Loop::destroyByDevice(loopDevice);
867 goto fail;
868 }
869
870 /*
871 * Wait for the device mapper node to be created.
872 */
873 waitForDevMapper(dmDevice);
874
875 if (Ext4::resize(dmDevice, numImgSectors)) {
876 SLOGE("Unable to resize %s (%s)", id, strerror(errno));
877 if (cleanupDm) {
878 Devmapper::destroy(idHash);
879 }
880 Loop::destroyByDevice(loopDevice);
881 goto fail;
882 }
883
884 return 0;
885fail:
886 Loop::resizeImageFile(asecFileName, oldNumSec);
887 return -1;
888}
889
San Mehata19b2502010-01-06 10:33:53 -0800890int VolumeManager::finalizeAsec(const char *id) {
891 char asecFileName[255];
892 char loopDevice[255];
893 char mountPoint[255];
894
Nick Kralevich0de7c612014-01-27 14:58:06 -0800895 if (!isLegalAsecId(id)) {
896 SLOGE("finalizeAsec: Invalid asec id \"%s\"", id);
897 errno = EINVAL;
898 return -1;
899 }
900
Kenny Root344ca102012-04-03 17:23:01 -0700901 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
902 SLOGE("Couldn't find ASEC %s", id);
903 return -1;
904 }
San Mehata19b2502010-01-06 10:33:53 -0800905
San Mehatd9a4e352010-03-12 13:32:47 -0800906 char idHash[33];
907 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700908 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800909 return -1;
910 }
911
912 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700913 SLOGE("Unable to finalize %s (%s)", id, strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800914 return -1;
915 }
916
Hiroaki Miyazawa14eab552015-02-04 13:29:15 +0900917 unsigned long nr_sec = 0;
Kenny Root344ca102012-04-03 17:23:01 -0700918 struct asec_superblock sb;
919
920 if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) {
921 return -1;
922 }
923
Jeff Sharkey9f18fe72015-04-01 23:32:18 -0700924 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id);
rpcraigd1c226f2012-10-09 06:58:16 -0400925 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
926 SLOGE("ASEC finalize failed: couldn't construct mountPoint");
927 return -1;
928 }
Kenny Root344ca102012-04-03 17:23:01 -0700929
930 int result = 0;
931 if (sb.c_opts & ASEC_SB_C_OPTS_EXT4) {
932 result = Ext4::doMount(loopDevice, mountPoint, true, true, true);
933 } else {
934 result = Fat::doMount(loopDevice, mountPoint, true, true, true, 0, 0, 0227, false);
935 }
936
937 if (result) {
San Mehat97ac40e2010-03-24 10:24:19 -0700938 SLOGE("ASEC finalize mount failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800939 return -1;
940 }
941
San Mehatd9a4e352010-03-12 13:32:47 -0800942 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700943 SLOGD("ASEC %s finalized", id);
San Mehatd9a4e352010-03-12 13:32:47 -0800944 }
San Mehata19b2502010-01-06 10:33:53 -0800945 return 0;
946}
947
Kenny Root344ca102012-04-03 17:23:01 -0700948int VolumeManager::fixupAsecPermissions(const char *id, gid_t gid, const char* filename) {
949 char asecFileName[255];
950 char loopDevice[255];
951 char mountPoint[255];
952
953 if (gid < AID_APP) {
954 SLOGE("Group ID is not in application range");
955 return -1;
956 }
957
Nick Kralevich0de7c612014-01-27 14:58:06 -0800958 if (!isLegalAsecId(id)) {
959 SLOGE("fixupAsecPermissions: Invalid asec id \"%s\"", id);
960 errno = EINVAL;
961 return -1;
962 }
963
Kenny Root344ca102012-04-03 17:23:01 -0700964 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
965 SLOGE("Couldn't find ASEC %s", id);
966 return -1;
967 }
968
969 char idHash[33];
970 if (!asecHash(id, idHash, sizeof(idHash))) {
971 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
972 return -1;
973 }
974
975 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
976 SLOGE("Unable fix permissions during lookup on %s (%s)", id, strerror(errno));
977 return -1;
978 }
979
Hiroaki Miyazawa14eab552015-02-04 13:29:15 +0900980 unsigned long nr_sec = 0;
Kenny Root344ca102012-04-03 17:23:01 -0700981 struct asec_superblock sb;
982
983 if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) {
984 return -1;
985 }
986
Jeff Sharkey9f18fe72015-04-01 23:32:18 -0700987 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id);
rpcraigd1c226f2012-10-09 06:58:16 -0400988 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
989 SLOGE("Unable remount to fix permissions for %s: couldn't construct mountpoint", id);
990 return -1;
991 }
Kenny Root344ca102012-04-03 17:23:01 -0700992
993 int result = 0;
994 if ((sb.c_opts & ASEC_SB_C_OPTS_EXT4) == 0) {
995 return 0;
996 }
997
998 int ret = Ext4::doMount(loopDevice, mountPoint,
999 false /* read-only */,
1000 true /* remount */,
1001 false /* executable */);
1002 if (ret) {
1003 SLOGE("Unable remount to fix permissions for %s (%s)", id, strerror(errno));
1004 return -1;
1005 }
1006
1007 char *paths[] = { mountPoint, NULL };
1008
1009 FTS *fts = fts_open(paths, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL);
1010 if (fts) {
1011 // Traverse the entire hierarchy and chown to system UID.
1012 for (FTSENT *ftsent = fts_read(fts); ftsent != NULL; ftsent = fts_read(fts)) {
1013 // We don't care about the lost+found directory.
1014 if (!strcmp(ftsent->fts_name, "lost+found")) {
1015 continue;
1016 }
1017
1018 /*
1019 * There can only be one file marked as private right now.
1020 * This should be more robust, but it satisfies the requirements
1021 * we have for right now.
1022 */
1023 const bool privateFile = !strcmp(ftsent->fts_name, filename);
1024
Jeff Sharkeyce6a9132015-04-08 21:07:21 -07001025 int fd = open(ftsent->fts_accpath, O_NOFOLLOW | O_CLOEXEC);
Kenny Root344ca102012-04-03 17:23:01 -07001026 if (fd < 0) {
1027 SLOGE("Couldn't open file %s: %s", ftsent->fts_accpath, strerror(errno));
1028 result = -1;
1029 continue;
1030 }
1031
1032 result |= fchown(fd, AID_SYSTEM, privateFile? gid : AID_SYSTEM);
1033
1034 if (ftsent->fts_info & FTS_D) {
Kenny Root1a673c82012-05-10 16:45:29 -07001035 result |= fchmod(fd, 0755);
Kenny Root348c8ab2012-05-10 15:39:53 -07001036 } else if (ftsent->fts_info & FTS_F) {
Kenny Root344ca102012-04-03 17:23:01 -07001037 result |= fchmod(fd, privateFile ? 0640 : 0644);
1038 }
Robert Craigb9e3ba52014-02-04 10:53:00 -05001039
Stephen Smalley5093e612014-02-12 09:43:08 -05001040 if (selinux_android_restorecon(ftsent->fts_path, 0) < 0) {
Robert Craigb9e3ba52014-02-04 10:53:00 -05001041 SLOGE("restorecon failed for %s: %s\n", ftsent->fts_path, strerror(errno));
1042 result |= -1;
1043 }
1044
Kenny Root344ca102012-04-03 17:23:01 -07001045 close(fd);
1046 }
1047 fts_close(fts);
1048
1049 // Finally make the directory readable by everyone.
Jeff Sharkeyce6a9132015-04-08 21:07:21 -07001050 int dirfd = open(mountPoint, O_DIRECTORY | O_CLOEXEC);
Kenny Root344ca102012-04-03 17:23:01 -07001051 if (dirfd < 0 || fchmod(dirfd, 0755)) {
1052 SLOGE("Couldn't change owner of existing directory %s: %s", mountPoint, strerror(errno));
1053 result |= -1;
1054 }
1055 close(dirfd);
1056 } else {
1057 result |= -1;
1058 }
1059
1060 result |= Ext4::doMount(loopDevice, mountPoint,
1061 true /* read-only */,
1062 true /* remount */,
1063 true /* execute */);
1064
1065 if (result) {
1066 SLOGE("ASEC fix permissions failed (%s)", strerror(errno));
1067 return -1;
1068 }
1069
1070 if (mDebug) {
1071 SLOGD("ASEC %s permissions fixed", id);
1072 }
1073 return 0;
1074}
1075
San Mehat048b0802010-01-23 08:17:06 -08001076int VolumeManager::renameAsec(const char *id1, const char *id2) {
Kenny Root344ca102012-04-03 17:23:01 -07001077 char asecFilename1[255];
San Mehat048b0802010-01-23 08:17:06 -08001078 char *asecFilename2;
1079 char mountPoint[255];
1080
Kenny Root344ca102012-04-03 17:23:01 -07001081 const char *dir;
1082
Nick Kralevich0de7c612014-01-27 14:58:06 -08001083 if (!isLegalAsecId(id1)) {
1084 SLOGE("renameAsec: Invalid asec id1 \"%s\"", id1);
1085 errno = EINVAL;
1086 return -1;
1087 }
1088
1089 if (!isLegalAsecId(id2)) {
1090 SLOGE("renameAsec: Invalid asec id2 \"%s\"", id2);
1091 errno = EINVAL;
1092 return -1;
1093 }
1094
Kenny Root344ca102012-04-03 17:23:01 -07001095 if (findAsec(id1, asecFilename1, sizeof(asecFilename1), &dir)) {
1096 SLOGE("Couldn't find ASEC %s", id1);
1097 return -1;
1098 }
1099
1100 asprintf(&asecFilename2, "%s/%s.asec", dir, id2);
San Mehat048b0802010-01-23 08:17:06 -08001101
Jeff Sharkey9f18fe72015-04-01 23:32:18 -07001102 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id1);
rpcraigd1c226f2012-10-09 06:58:16 -04001103 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
1104 SLOGE("Rename failed: couldn't construct mountpoint");
1105 goto out_err;
1106 }
1107
San Mehat048b0802010-01-23 08:17:06 -08001108 if (isMountpointMounted(mountPoint)) {
San Mehat97ac40e2010-03-24 10:24:19 -07001109 SLOGW("Rename attempt when src mounted");
San Mehat048b0802010-01-23 08:17:06 -08001110 errno = EBUSY;
1111 goto out_err;
1112 }
1113
Jeff Sharkey9f18fe72015-04-01 23:32:18 -07001114 written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id2);
rpcraigd1c226f2012-10-09 06:58:16 -04001115 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
1116 SLOGE("Rename failed: couldn't construct mountpoint2");
1117 goto out_err;
1118 }
1119
San Mehat96956ed2010-02-24 08:42:51 -08001120 if (isMountpointMounted(mountPoint)) {
San Mehat97ac40e2010-03-24 10:24:19 -07001121 SLOGW("Rename attempt when dst mounted");
San Mehat96956ed2010-02-24 08:42:51 -08001122 errno = EBUSY;
1123 goto out_err;
1124 }
1125
San Mehat048b0802010-01-23 08:17:06 -08001126 if (!access(asecFilename2, F_OK)) {
San Mehat97ac40e2010-03-24 10:24:19 -07001127 SLOGE("Rename attempt when dst exists");
San Mehat048b0802010-01-23 08:17:06 -08001128 errno = EADDRINUSE;
1129 goto out_err;
1130 }
1131
1132 if (rename(asecFilename1, asecFilename2)) {
San Mehat97ac40e2010-03-24 10:24:19 -07001133 SLOGE("Rename of '%s' to '%s' failed (%s)", asecFilename1, asecFilename2, strerror(errno));
San Mehat048b0802010-01-23 08:17:06 -08001134 goto out_err;
1135 }
1136
San Mehat048b0802010-01-23 08:17:06 -08001137 free(asecFilename2);
1138 return 0;
1139
1140out_err:
San Mehat048b0802010-01-23 08:17:06 -08001141 free(asecFilename2);
1142 return -1;
1143}
1144
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001145#define UNMOUNT_RETRIES 5
1146#define UNMOUNT_SLEEP_BETWEEN_RETRY_MS (1000 * 1000)
San Mehat4ba89482010-02-18 09:00:18 -08001147int VolumeManager::unmountAsec(const char *id, bool force) {
San Mehata19b2502010-01-06 10:33:53 -08001148 char asecFileName[255];
1149 char mountPoint[255];
1150
Nick Kralevich0de7c612014-01-27 14:58:06 -08001151 if (!isLegalAsecId(id)) {
1152 SLOGE("unmountAsec: Invalid asec id \"%s\"", id);
1153 errno = EINVAL;
1154 return -1;
1155 }
1156
Kenny Root344ca102012-04-03 17:23:01 -07001157 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
1158 SLOGE("Couldn't find ASEC %s", id);
1159 return -1;
1160 }
1161
Jeff Sharkey9f18fe72015-04-01 23:32:18 -07001162 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id);
rpcraigd1c226f2012-10-09 06:58:16 -04001163 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
1164 SLOGE("ASEC unmount failed for %s: couldn't construct mountpoint", id);
1165 return -1;
1166 }
San Mehata19b2502010-01-06 10:33:53 -08001167
San Mehatd9a4e352010-03-12 13:32:47 -08001168 char idHash[33];
1169 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -07001170 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -08001171 return -1;
1172 }
1173
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001174 return unmountLoopImage(id, idHash, asecFileName, mountPoint, force);
1175}
1176
Kenny Root508c0e12010-07-12 09:59:49 -07001177int VolumeManager::unmountObb(const char *fileName, bool force) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001178 char mountPoint[255];
1179
1180 char idHash[33];
1181 if (!asecHash(fileName, idHash, sizeof(idHash))) {
1182 SLOGE("Hash of '%s' failed (%s)", fileName, strerror(errno));
1183 return -1;
1184 }
1185
Jeff Sharkey9f18fe72015-04-01 23:32:18 -07001186 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::LOOPDIR, idHash);
rpcraigd1c226f2012-10-09 06:58:16 -04001187 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
1188 SLOGE("OBB unmount failed for %s: couldn't construct mountpoint", fileName);
1189 return -1;
1190 }
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001191
1192 return unmountLoopImage(fileName, idHash, fileName, mountPoint, force);
1193}
1194
1195int VolumeManager::unmountLoopImage(const char *id, const char *idHash,
1196 const char *fileName, const char *mountPoint, bool force) {
San Mehat0586d542010-01-12 15:38:59 -08001197 if (!isMountpointMounted(mountPoint)) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001198 SLOGE("Unmount request for %s when not mounted", id);
Kenny Root918e5f92010-09-30 18:00:52 -07001199 errno = ENOENT;
San Mehatb78a32c2010-01-10 13:02:12 -08001200 return -1;
1201 }
San Mehat23969932010-01-09 07:08:06 -08001202
San Mehatb78a32c2010-01-10 13:02:12 -08001203 int i, rc;
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001204 for (i = 1; i <= UNMOUNT_RETRIES; i++) {
San Mehatb78a32c2010-01-10 13:02:12 -08001205 rc = umount(mountPoint);
1206 if (!rc) {
1207 break;
San Mehata19b2502010-01-06 10:33:53 -08001208 }
San Mehatb78a32c2010-01-10 13:02:12 -08001209 if (rc && (errno == EINVAL || errno == ENOENT)) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001210 SLOGI("Container %s unmounted OK", id);
San Mehatb78a32c2010-01-10 13:02:12 -08001211 rc = 0;
1212 break;
San Mehata19b2502010-01-06 10:33:53 -08001213 }
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001214 SLOGW("%s unmount attempt %d failed (%s)",
San Mehat8c940ef2010-02-13 14:19:53 -08001215 id, i, strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -08001216
Jeff Sharkey36801cc2015-03-13 16:09:20 -07001217 int signal = 0; // default is to just complain
San Mehat4ba89482010-02-18 09:00:18 -08001218
1219 if (force) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001220 if (i > (UNMOUNT_RETRIES - 2))
Jeff Sharkey36801cc2015-03-13 16:09:20 -07001221 signal = SIGKILL;
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001222 else if (i > (UNMOUNT_RETRIES - 3))
Jeff Sharkey36801cc2015-03-13 16:09:20 -07001223 signal = SIGTERM;
San Mehat4ba89482010-02-18 09:00:18 -08001224 }
San Mehat8c940ef2010-02-13 14:19:53 -08001225
Jeff Sharkey36801cc2015-03-13 16:09:20 -07001226 Process::killProcessesWithOpenFiles(mountPoint, signal);
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001227 usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
San Mehatb78a32c2010-01-10 13:02:12 -08001228 }
1229
1230 if (rc) {
San Mehat4ba89482010-02-18 09:00:18 -08001231 errno = EBUSY;
San Mehat97ac40e2010-03-24 10:24:19 -07001232 SLOGE("Failed to unmount container %s (%s)", id, strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -08001233 return -1;
1234 }
1235
San Mehat12f4b892010-02-24 11:43:22 -08001236 int retries = 10;
1237
1238 while(retries--) {
1239 if (!rmdir(mountPoint)) {
1240 break;
1241 }
1242
San Mehat97ac40e2010-03-24 10:24:19 -07001243 SLOGW("Failed to rmdir %s (%s)", mountPoint, strerror(errno));
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001244 usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
San Mehat12f4b892010-02-24 11:43:22 -08001245 }
1246
1247 if (!retries) {
San Mehat97ac40e2010-03-24 10:24:19 -07001248 SLOGE("Timed out trying to rmdir %s (%s)", mountPoint, strerror(errno));
San Mehatf5c61982010-02-03 11:04:46 -08001249 }
San Mehat88705162010-01-15 09:26:28 -08001250
Paul Lawrence60dec162014-09-02 10:52:15 -07001251 for (i=1; i <= UNMOUNT_RETRIES; i++) {
1252 if (Devmapper::destroy(idHash) && errno != ENXIO) {
1253 SLOGE("Failed to destroy devmapper instance (%s)", strerror(errno));
1254 usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
1255 continue;
1256 } else {
1257 break;
1258 }
San Mehata19b2502010-01-06 10:33:53 -08001259 }
1260
1261 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -08001262 if (!Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
San Mehata19b2502010-01-06 10:33:53 -08001263 Loop::destroyByDevice(loopDevice);
San Mehatd9a4e352010-03-12 13:32:47 -08001264 } else {
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001265 SLOGW("Failed to find loop device for {%s} (%s)", fileName, strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -08001266 }
San Mehat88705162010-01-15 09:26:28 -08001267
1268 AsecIdCollection::iterator it;
1269 for (it = mActiveContainers->begin(); it != mActiveContainers->end(); ++it) {
Kenny Rootcbacf782010-09-24 15:11:48 -07001270 ContainerData* cd = *it;
1271 if (!strcmp(cd->id, id)) {
San Mehat88705162010-01-15 09:26:28 -08001272 free(*it);
1273 mActiveContainers->erase(it);
1274 break;
1275 }
1276 }
1277 if (it == mActiveContainers->end()) {
San Mehat97ac40e2010-03-24 10:24:19 -07001278 SLOGW("mActiveContainers is inconsistent!");
San Mehat88705162010-01-15 09:26:28 -08001279 }
San Mehatb78a32c2010-01-10 13:02:12 -08001280 return 0;
1281}
1282
San Mehat4ba89482010-02-18 09:00:18 -08001283int VolumeManager::destroyAsec(const char *id, bool force) {
San Mehatb78a32c2010-01-10 13:02:12 -08001284 char asecFileName[255];
1285 char mountPoint[255];
1286
Nick Kralevich0de7c612014-01-27 14:58:06 -08001287 if (!isLegalAsecId(id)) {
1288 SLOGE("destroyAsec: Invalid asec id \"%s\"", id);
1289 errno = EINVAL;
1290 return -1;
1291 }
1292
Kenny Root344ca102012-04-03 17:23:01 -07001293 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
1294 SLOGE("Couldn't find ASEC %s", id);
1295 return -1;
1296 }
1297
Jeff Sharkey9f18fe72015-04-01 23:32:18 -07001298 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id);
rpcraigd1c226f2012-10-09 06:58:16 -04001299 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
1300 SLOGE("ASEC destroy failed for %s: couldn't construct mountpoint", id);
1301 return -1;
1302 }
San Mehatb78a32c2010-01-10 13:02:12 -08001303
San Mehat0586d542010-01-12 15:38:59 -08001304 if (isMountpointMounted(mountPoint)) {
San Mehatd9a4e352010-03-12 13:32:47 -08001305 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -07001306 SLOGD("Unmounting container before destroy");
San Mehatd9a4e352010-03-12 13:32:47 -08001307 }
San Mehat4ba89482010-02-18 09:00:18 -08001308 if (unmountAsec(id, force)) {
San Mehat97ac40e2010-03-24 10:24:19 -07001309 SLOGE("Failed to unmount asec %s for destroy (%s)", id, strerror(errno));
San Mehat0586d542010-01-12 15:38:59 -08001310 return -1;
1311 }
1312 }
San Mehata19b2502010-01-06 10:33:53 -08001313
San Mehat0586d542010-01-12 15:38:59 -08001314 if (unlink(asecFileName)) {
San Mehat97ac40e2010-03-24 10:24:19 -07001315 SLOGE("Failed to unlink asec '%s' (%s)", asecFileName, strerror(errno));
San Mehat0586d542010-01-12 15:38:59 -08001316 return -1;
1317 }
San Mehata19b2502010-01-06 10:33:53 -08001318
San Mehatd9a4e352010-03-12 13:32:47 -08001319 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -07001320 SLOGD("ASEC %s destroyed", id);
San Mehatd9a4e352010-03-12 13:32:47 -08001321 }
San Mehata19b2502010-01-06 10:33:53 -08001322 return 0;
1323}
1324
Nick Kralevich0de7c612014-01-27 14:58:06 -08001325/*
1326 * Legal ASEC ids consist of alphanumeric characters, '-',
1327 * '_', or '.'. ".." is not allowed. The first or last character
1328 * of the ASEC id cannot be '.' (dot).
1329 */
1330bool VolumeManager::isLegalAsecId(const char *id) const {
1331 size_t i;
1332 size_t len = strlen(id);
1333
1334 if (len == 0) {
1335 return false;
1336 }
1337 if ((id[0] == '.') || (id[len - 1] == '.')) {
1338 return false;
1339 }
1340
1341 for (i = 0; i < len; i++) {
1342 if (id[i] == '.') {
1343 // i=0 is guaranteed never to have a dot. See above.
1344 if (id[i-1] == '.') return false;
1345 continue;
1346 }
1347 if (id[i] == '_' || id[i] == '-') continue;
1348 if (id[i] >= 'a' && id[i] <= 'z') continue;
1349 if (id[i] >= 'A' && id[i] <= 'Z') continue;
1350 if (id[i] >= '0' && id[i] <= '9') continue;
1351 return false;
1352 }
1353
1354 return true;
1355}
1356
Kenny Root344ca102012-04-03 17:23:01 -07001357bool VolumeManager::isAsecInDirectory(const char *dir, const char *asecName) const {
Jeff Sharkeyce6a9132015-04-08 21:07:21 -07001358 int dirfd = open(dir, O_DIRECTORY | O_CLOEXEC);
Kenny Root344ca102012-04-03 17:23:01 -07001359 if (dirfd < 0) {
1360 SLOGE("Couldn't open internal ASEC dir (%s)", strerror(errno));
Nick Kralevich25e581a2015-02-06 08:55:08 -08001361 return false;
Kenny Root344ca102012-04-03 17:23:01 -07001362 }
1363
Nick Kralevich25e581a2015-02-06 08:55:08 -08001364 struct stat sb;
1365 bool ret = (fstatat(dirfd, asecName, &sb, AT_SYMLINK_NOFOLLOW) == 0)
1366 && S_ISREG(sb.st_mode);
Kenny Root344ca102012-04-03 17:23:01 -07001367
1368 close(dirfd);
1369
1370 return ret;
1371}
1372
1373int VolumeManager::findAsec(const char *id, char *asecPath, size_t asecPathLen,
1374 const char **directory) const {
Kenny Root344ca102012-04-03 17:23:01 -07001375 char *asecName;
1376
Nick Kralevich0de7c612014-01-27 14:58:06 -08001377 if (!isLegalAsecId(id)) {
1378 SLOGE("findAsec: Invalid asec id \"%s\"", id);
1379 errno = EINVAL;
1380 return -1;
1381 }
1382
Kenny Root344ca102012-04-03 17:23:01 -07001383 if (asprintf(&asecName, "%s.asec", id) < 0) {
1384 SLOGE("Couldn't allocate string to write ASEC name");
1385 return -1;
1386 }
1387
1388 const char *dir;
Jeff Sharkey9f18fe72015-04-01 23:32:18 -07001389 if (isAsecInDirectory(VolumeManager::SEC_ASECDIR_INT, asecName)) {
1390 dir = VolumeManager::SEC_ASECDIR_INT;
1391 } else if (isAsecInDirectory(VolumeManager::SEC_ASECDIR_EXT, asecName)) {
1392 dir = VolumeManager::SEC_ASECDIR_EXT;
Kenny Root344ca102012-04-03 17:23:01 -07001393 } else {
1394 free(asecName);
1395 return -1;
1396 }
1397
1398 if (directory != NULL) {
1399 *directory = dir;
1400 }
1401
1402 if (asecPath != NULL) {
1403 int written = snprintf(asecPath, asecPathLen, "%s/%s", dir, asecName);
rpcraigd1c226f2012-10-09 06:58:16 -04001404 if ((written < 0) || (size_t(written) >= asecPathLen)) {
1405 SLOGE("findAsec failed for %s: couldn't construct ASEC path", id);
Kenny Root344ca102012-04-03 17:23:01 -07001406 free(asecName);
1407 return -1;
1408 }
1409 }
1410
1411 free(asecName);
1412 return 0;
1413}
1414
Jeff Sharkey43ed1232014-08-22 12:29:05 -07001415int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid, bool readOnly) {
San Mehata19b2502010-01-06 10:33:53 -08001416 char asecFileName[255];
1417 char mountPoint[255];
1418
Nick Kralevich0de7c612014-01-27 14:58:06 -08001419 if (!isLegalAsecId(id)) {
1420 SLOGE("mountAsec: Invalid asec id \"%s\"", id);
1421 errno = EINVAL;
1422 return -1;
1423 }
1424
Kenny Root344ca102012-04-03 17:23:01 -07001425 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
1426 SLOGE("Couldn't find ASEC %s", id);
1427 return -1;
1428 }
1429
Jeff Sharkey9f18fe72015-04-01 23:32:18 -07001430 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id);
rpcraigd1c226f2012-10-09 06:58:16 -04001431 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
Colin Cross59846b62014-02-06 20:34:29 -08001432 SLOGE("ASEC mount failed for %s: couldn't construct mountpoint", id);
rpcraigd1c226f2012-10-09 06:58:16 -04001433 return -1;
1434 }
San Mehata19b2502010-01-06 10:33:53 -08001435
1436 if (isMountpointMounted(mountPoint)) {
San Mehat97ac40e2010-03-24 10:24:19 -07001437 SLOGE("ASEC %s already mounted", id);
San Mehata19b2502010-01-06 10:33:53 -08001438 errno = EBUSY;
1439 return -1;
1440 }
1441
San Mehatd9a4e352010-03-12 13:32:47 -08001442 char idHash[33];
1443 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -07001444 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -08001445 return -1;
1446 }
Kenny Root7b18a7b2010-03-15 13:13:41 -07001447
San Mehata19b2502010-01-06 10:33:53 -08001448 char loopDevice[255];
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -07001449 if (setupLoopDevice(loopDevice, sizeof(loopDevice), asecFileName, idHash, mDebug))
1450 return -1;
San Mehatb78a32c2010-01-10 13:02:12 -08001451
1452 char dmDevice[255];
1453 bool cleanupDm = false;
Tim Murray8439dc92014-12-15 11:56:11 -08001454
Hiroaki Miyazawa14eab552015-02-04 13:29:15 +09001455 unsigned long nr_sec = 0;
San Mehatfcf24fe2010-03-03 12:37:32 -08001456 struct asec_superblock sb;
San Mehatfcf24fe2010-03-03 12:37:32 -08001457
Kenny Root344ca102012-04-03 17:23:01 -07001458 if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) {
1459 return -1;
1460 }
San Mehatfcf24fe2010-03-03 12:37:32 -08001461
San Mehatd9a4e352010-03-12 13:32:47 -08001462 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -07001463 SLOGD("Container sb magic/ver (%.8x/%.2x)", sb.magic, sb.ver);
San Mehatd9a4e352010-03-12 13:32:47 -08001464 }
San Mehatfcf24fe2010-03-03 12:37:32 -08001465 if (sb.magic != ASEC_SB_MAGIC || sb.ver != ASEC_SB_VER) {
San Mehat97ac40e2010-03-24 10:24:19 -07001466 SLOGE("Bad container magic/version (%.8x/%.2x)", sb.magic, sb.ver);
San Mehatfcf24fe2010-03-03 12:37:32 -08001467 Loop::destroyByDevice(loopDevice);
1468 errno = EMEDIUMTYPE;
1469 return -1;
1470 }
1471 nr_sec--; // We don't want the devmapping to extend onto our superblock
1472
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -07001473 if (setupDevMapperDevice(dmDevice, sizeof(dmDevice), loopDevice, asecFileName, key, idHash , nr_sec, &cleanupDm, mDebug)) {
1474 Loop::destroyByDevice(loopDevice);
1475 return -1;
San Mehata19b2502010-01-06 10:33:53 -08001476 }
1477
Kenny Root344ca102012-04-03 17:23:01 -07001478 if (mkdir(mountPoint, 0000)) {
San Mehatb78a32c2010-01-10 13:02:12 -08001479 if (errno != EEXIST) {
San Mehat97ac40e2010-03-24 10:24:19 -07001480 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -08001481 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -08001482 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -08001483 }
1484 Loop::destroyByDevice(loopDevice);
1485 return -1;
1486 }
San Mehata19b2502010-01-06 10:33:53 -08001487 }
1488
Kenny Rootcdc2a1c2012-05-03 13:49:46 -07001489 /*
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -07001490 * Wait for the device mapper node to be created.
Kenny Rootcdc2a1c2012-05-03 13:49:46 -07001491 */
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -07001492 waitForDevMapper(dmDevice);
Kenny Rootcdc2a1c2012-05-03 13:49:46 -07001493
Kenny Root344ca102012-04-03 17:23:01 -07001494 int result;
1495 if (sb.c_opts & ASEC_SB_C_OPTS_EXT4) {
Jeff Sharkey43ed1232014-08-22 12:29:05 -07001496 result = Ext4::doMount(dmDevice, mountPoint, readOnly, false, readOnly);
Kenny Root344ca102012-04-03 17:23:01 -07001497 } else {
Jeff Sharkey43ed1232014-08-22 12:29:05 -07001498 result = Fat::doMount(dmDevice, mountPoint, readOnly, false, readOnly, ownerUid, 0, 0222, false);
Kenny Root344ca102012-04-03 17:23:01 -07001499 }
1500
1501 if (result) {
San Mehat97ac40e2010-03-24 10:24:19 -07001502 SLOGE("ASEC mount failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -08001503 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -08001504 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -08001505 }
1506 Loop::destroyByDevice(loopDevice);
San Mehata19b2502010-01-06 10:33:53 -08001507 return -1;
1508 }
1509
Kenny Rootcbacf782010-09-24 15:11:48 -07001510 mActiveContainers->push_back(new ContainerData(strdup(id), ASEC));
San Mehatd9a4e352010-03-12 13:32:47 -08001511 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -07001512 SLOGD("ASEC %s mounted", id);
San Mehatd9a4e352010-03-12 13:32:47 -08001513 }
San Mehata19b2502010-01-06 10:33:53 -08001514 return 0;
1515}
1516
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001517/**
1518 * Mounts an image file <code>img</code>.
1519 */
Jeff Sharkey69479042012-09-25 16:14:57 -07001520int VolumeManager::mountObb(const char *img, const char *key, int ownerGid) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001521 char mountPoint[255];
1522
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001523 char idHash[33];
1524 if (!asecHash(img, idHash, sizeof(idHash))) {
1525 SLOGE("Hash of '%s' failed (%s)", img, strerror(errno));
1526 return -1;
1527 }
1528
Jeff Sharkey9f18fe72015-04-01 23:32:18 -07001529 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::LOOPDIR, idHash);
rpcraigd1c226f2012-10-09 06:58:16 -04001530 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
Colin Cross59846b62014-02-06 20:34:29 -08001531 SLOGE("OBB mount failed for %s: couldn't construct mountpoint", img);
rpcraigd1c226f2012-10-09 06:58:16 -04001532 return -1;
1533 }
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001534
1535 if (isMountpointMounted(mountPoint)) {
1536 SLOGE("Image %s already mounted", img);
1537 errno = EBUSY;
1538 return -1;
1539 }
1540
1541 char loopDevice[255];
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -07001542 if (setupLoopDevice(loopDevice, sizeof(loopDevice), img, idHash, mDebug))
1543 return -1;
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001544
1545 char dmDevice[255];
1546 bool cleanupDm = false;
1547 int fd;
Hiroaki Miyazawa14eab552015-02-04 13:29:15 +09001548 unsigned long nr_sec = 0;
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001549
Jeff Sharkeyce6a9132015-04-08 21:07:21 -07001550 if ((fd = open(loopDevice, O_RDWR | O_CLOEXEC)) < 0) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001551 SLOGE("Failed to open loopdevice (%s)", strerror(errno));
1552 Loop::destroyByDevice(loopDevice);
1553 return -1;
1554 }
1555
Hiroaki Miyazawa14eab552015-02-04 13:29:15 +09001556 get_blkdev_size(fd, &nr_sec);
1557 if (nr_sec == 0) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001558 SLOGE("Failed to get loop size (%s)", strerror(errno));
1559 Loop::destroyByDevice(loopDevice);
1560 close(fd);
1561 return -1;
1562 }
1563
1564 close(fd);
1565
Hiroaki Miyazawa14eab552015-02-04 13:29:15 +09001566 if (setupDevMapperDevice(dmDevice, sizeof(loopDevice), loopDevice, img,key, idHash, nr_sec, &cleanupDm, mDebug)) {
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -07001567 Loop::destroyByDevice(loopDevice);
1568 return -1;
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001569 }
1570
1571 if (mkdir(mountPoint, 0755)) {
1572 if (errno != EEXIST) {
1573 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
1574 if (cleanupDm) {
1575 Devmapper::destroy(idHash);
1576 }
1577 Loop::destroyByDevice(loopDevice);
1578 return -1;
1579 }
1580 }
1581
Jeff Sharkey69479042012-09-25 16:14:57 -07001582 if (Fat::doMount(dmDevice, mountPoint, true, false, true, 0, ownerGid,
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001583 0227, false)) {
1584 SLOGE("Image mount failed (%s)", strerror(errno));
1585 if (cleanupDm) {
1586 Devmapper::destroy(idHash);
1587 }
1588 Loop::destroyByDevice(loopDevice);
1589 return -1;
1590 }
1591
Kenny Rootcbacf782010-09-24 15:11:48 -07001592 mActiveContainers->push_back(new ContainerData(strdup(img), OBB));
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001593 if (mDebug) {
1594 SLOGD("Image %s mounted", img);
1595 }
1596 return 0;
1597}
1598
Kenny Root508c0e12010-07-12 09:59:49 -07001599int VolumeManager::listMountedObbs(SocketClient* cli) {
Yabin Cuid1104f72015-01-02 13:28:28 -08001600 FILE *fp = setmntent("/proc/mounts", "r");
1601 if (fp == NULL) {
Kenny Root508c0e12010-07-12 09:59:49 -07001602 SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
1603 return -1;
1604 }
1605
1606 // Create a string to compare against that has a trailing slash
Jeff Sharkey9f18fe72015-04-01 23:32:18 -07001607 int loopDirLen = strlen(VolumeManager::LOOPDIR);
Kenny Root508c0e12010-07-12 09:59:49 -07001608 char loopDir[loopDirLen + 2];
Jeff Sharkey9f18fe72015-04-01 23:32:18 -07001609 strcpy(loopDir, VolumeManager::LOOPDIR);
Kenny Root508c0e12010-07-12 09:59:49 -07001610 loopDir[loopDirLen++] = '/';
1611 loopDir[loopDirLen] = '\0';
1612
Yabin Cuid1104f72015-01-02 13:28:28 -08001613 mntent* mentry;
1614 while ((mentry = getmntent(fp)) != NULL) {
1615 if (!strncmp(mentry->mnt_dir, loopDir, loopDirLen)) {
Jeff Sharkeyce6a9132015-04-08 21:07:21 -07001616 int fd = open(mentry->mnt_fsname, O_RDONLY | O_CLOEXEC);
Kenny Root508c0e12010-07-12 09:59:49 -07001617 if (fd >= 0) {
1618 struct loop_info64 li;
1619 if (ioctl(fd, LOOP_GET_STATUS64, &li) >= 0) {
1620 cli->sendMsg(ResponseCode::AsecListResult,
1621 (const char*) li.lo_file_name, false);
1622 }
1623 close(fd);
1624 }
1625 }
1626 }
Yabin Cuid1104f72015-01-02 13:28:28 -08001627 endmntent(fp);
Kenny Root508c0e12010-07-12 09:59:49 -07001628 return 0;
1629}
1630
Jeff Sharkey9c484982015-03-31 10:35:33 -07001631extern "C" int vold_unmountAll(void) {
Ken Sumrall425524d2012-06-14 20:55:28 -07001632 VolumeManager *vm = VolumeManager::Instance();
Jeff Sharkey9c484982015-03-31 10:35:33 -07001633 return vm->unmountAll();
Ken Sumrall425524d2012-06-14 20:55:28 -07001634}
1635
San Mehata19b2502010-01-06 10:33:53 -08001636bool VolumeManager::isMountpointMounted(const char *mp)
1637{
Yabin Cuid1104f72015-01-02 13:28:28 -08001638 FILE *fp = setmntent("/proc/mounts", "r");
1639 if (fp == NULL) {
San Mehat97ac40e2010-03-24 10:24:19 -07001640 SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -08001641 return false;
1642 }
1643
Yabin Cuid1104f72015-01-02 13:28:28 -08001644 bool found_mp = false;
1645 mntent* mentry;
1646 while ((mentry = getmntent(fp)) != NULL) {
1647 if (strcmp(mentry->mnt_dir, mp) == 0) {
1648 found_mp = true;
1649 break;
San Mehata19b2502010-01-06 10:33:53 -08001650 }
San Mehata19b2502010-01-06 10:33:53 -08001651 }
Yabin Cuid1104f72015-01-02 13:28:28 -08001652 endmntent(fp);
1653 return found_mp;
San Mehata19b2502010-01-06 10:33:53 -08001654}
1655
Jeff Sharkey71ebe152013-09-17 17:24:38 -07001656int VolumeManager::mkdirs(char* path) {
Jeff Sharkey36801cc2015-03-13 16:09:20 -07001657 // Only offer to create directories for paths managed by vold
1658 if (strncmp(path, "/storage/", 9) == 0) {
1659 // fs_mkdirs() does symlink checking and relative path enforcement
1660 return fs_mkdirs(path, 0700);
Jeff Sharkey71ebe152013-09-17 17:24:38 -07001661 } else {
Cylen Yao27cfee32014-05-02 19:23:42 +08001662 SLOGE("Failed to find mounted volume for %s", path);
Jeff Sharkey71ebe152013-09-17 17:24:38 -07001663 return -EINVAL;
1664 }
Jeff Sharkey71ebe152013-09-17 17:24:38 -07001665}