summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk1
-rw-r--r--Disk.cpp125
-rw-r--r--Disk.h4
-rw-r--r--EmulatedVolume.cpp6
-rw-r--r--Ext4.cpp112
-rw-r--r--Ext4.h1
-rw-r--r--PrivateVolume.cpp145
-rw-r--r--PrivateVolume.h78
-rw-r--r--PublicVolume.cpp73
-rw-r--r--PublicVolume.h2
-rw-r--r--Utils.cpp143
-rw-r--r--Utils.h13
-rw-r--r--Volume.cpp12
-rw-r--r--VolumeBase.cpp13
-rw-r--r--VolumeBase.h3
-rw-r--r--VolumeManager.cpp102
-rw-r--r--VolumeManager.h7
-rw-r--r--cryptfs.c143
-rw-r--r--cryptfs.h8
19 files changed, 719 insertions, 272 deletions
diff --git a/Android.mk b/Android.mk
index d087216..3aa12a5 100644
--- a/Android.mk
+++ b/Android.mk
@@ -21,6 +21,7 @@ common_src_files := \
Disk.cpp \
VolumeBase.cpp \
PublicVolume.cpp \
+ PrivateVolume.cpp \
EmulatedVolume.cpp \
Utils.cpp \
diff --git a/Disk.cpp b/Disk.cpp
index 084f95e..3bf9333 100644
--- a/Disk.cpp
+++ b/Disk.cpp
@@ -16,6 +16,7 @@
#include "Disk.h"
#include "PublicVolume.h"
+#include "PrivateVolume.h"
#include "Utils.h"
#include "VolumeBase.h"
#include "VolumeManager.h"
@@ -26,6 +27,7 @@
#include <base/logging.h>
#include <diskconfig/diskconfig.h>
+#include <vector>
#include <fcntl.h>
#include <inttypes.h>
#include <stdio.h>
@@ -35,6 +37,7 @@
#include <sys/mount.h>
using android::base::ReadFileToString;
+using android::base::WriteStringToFile;
using android::base::StringPrintf;
namespace android {
@@ -52,6 +55,8 @@ static const char* kGptBasicData = "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7";
static const char* kGptAndroidMeta = "19A710A2-B3CA-11E4-B026-10604B889DCF";
static const char* kGptAndroidExt = "193D1EA4-B3CA-11E4-B075-10604B889DCF";
+static const char* kKeyPath = "/data/misc/vold";
+
enum class Table {
kUnknown,
kMbr,
@@ -105,18 +110,44 @@ status_t Disk::destroy() {
return OK;
}
+static std::string BuildKeyPath(const std::string& partGuid) {
+ return StringPrintf("%s/ext_%s.key", kKeyPath, partGuid.c_str());
+}
+
void Disk::createPublicVolume(dev_t device) {
- auto vol = new PublicVolume(device);
+ auto vol = std::shared_ptr<VolumeBase>(new PublicVolume(device));
vol->create();
- mVolumes.push_back(std::shared_ptr<VolumeBase>(vol));
+ mVolumes.push_back(vol);
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(
ResponseCode::DiskVolumeCreated,
StringPrintf("%s %s", getId().c_str(), vol->getId().c_str()).c_str(), false);
}
-void Disk::createPrivateVolume(dev_t device) {
- // TODO: create and add
+void Disk::createPrivateVolume(dev_t device, const std::string& partGuid) {
+ std::string tmp;
+ std::string normalizedGuid;
+ if (HexToStr(partGuid, tmp)) {
+ LOG(WARNING) << "Invalid GUID " << partGuid;
+ return;
+ }
+ StrToHex(tmp, normalizedGuid);
+
+ std::string keyRaw;
+ if (!ReadFileToString(BuildKeyPath(normalizedGuid), &keyRaw)) {
+ PLOG(ERROR) << "Failed to load key for GUID " << normalizedGuid;
+ return;
+ }
+
+ LOG(DEBUG) << "Found key for GUID " << normalizedGuid;
+
+ auto vol = std::shared_ptr<VolumeBase>(new PrivateVolume(device, keyRaw));
+ vol->create();
+
+ mVolumes.push_back(vol);
+ VolumeManager::Instance()->getBroadcaster()->sendBroadcast(
+ ResponseCode::DiskVolumeCreated,
+ StringPrintf("%s %s", getId().c_str(), vol->getId().c_str()).c_str(), false);
}
void Disk::destroyAllVolumes() {
@@ -246,7 +277,7 @@ status_t Disk::readPartitions() {
if (!strcasecmp(typeGuid, kGptBasicData)) {
createPublicVolume(partDevice);
} else if (!strcasecmp(typeGuid, kGptAndroidExt)) {
- createPrivateVolume(partDevice);
+ createPrivateVolume(partDevice, partGuid);
}
}
}
@@ -262,6 +293,13 @@ status_t Disk::readPartitions() {
return OK;
}
+status_t Disk::unmountAll() {
+ for (auto vol : mVolumes) {
+ vol->unmount();
+ }
+ return OK;
+}
+
status_t Disk::partitionPublic() {
// TODO: improve this code
destroyAllVolumes();
@@ -304,13 +342,84 @@ out:
}
status_t Disk::partitionPrivate() {
- destroyAllVolumes();
- return -ENOTSUP;
+ return partitionMixed(0);
}
status_t Disk::partitionMixed(int8_t ratio) {
+ int status = 0;
+
destroyAllVolumes();
- return -ENOTSUP;
+
+ // First nuke any existing partition table
+ std::vector<std::string> cmd;
+ cmd.push_back(kSgdiskPath);
+ cmd.push_back("--zap-all");
+ cmd.push_back(mDevPath);
+
+ if (ForkExecvp(cmd, &status, false, true)) {
+ LOG(ERROR) << "Failed to zap; status " << status;
+ return -EIO;
+ }
+
+ // We've had some success above, so generate both the private partition
+ // GUID and encryption key and persist them.
+ std::string partGuidRaw;
+ std::string keyRaw;
+ if (ReadRandomBytes(16, partGuidRaw) || ReadRandomBytes(16, keyRaw)) {
+ LOG(ERROR) << "Failed to generate GUID or key";
+ return -EIO;
+ }
+
+ std::string partGuid;
+ StrToHex(partGuidRaw, partGuid);
+
+ if (!WriteStringToFile(keyRaw, BuildKeyPath(partGuid))) {
+ LOG(ERROR) << "Failed to persist key";
+ return -EIO;
+ } else {
+ LOG(DEBUG) << "Persisted key for GUID " << partGuid;
+ }
+
+ // Now let's build the new GPT table. We heavily rely on sgdisk to
+ // force optimal alignment on the created partitions.
+ cmd.clear();
+ cmd.push_back(kSgdiskPath);
+
+ // If requested, create a public partition first. Mixed-mode partitioning
+ // like this is an experimental feature.
+ if (ratio > 0) {
+ if (ratio < 10 || ratio > 90) {
+ LOG(ERROR) << "Mixed partition ratio must be between 10-90%";
+ return -EINVAL;
+ }
+
+ uint64_t splitMb = ((mSize / 100) * ratio) / 1024 / 1024;
+ cmd.push_back(StringPrintf("--new=0:0:+%" PRId64 "M", splitMb));
+ cmd.push_back(StringPrintf("--typecode=0:%s", kGptBasicData));
+ cmd.push_back("--change-name=0:shared");
+ }
+
+ // Define a metadata partition which is designed for future use; there
+ // should only be one of these per physical device, even if there are
+ // multiple private volumes.
+ cmd.push_back("--new=0:0:+16M");
+ cmd.push_back(StringPrintf("--typecode=0:%s", kGptAndroidMeta));
+ cmd.push_back("--change-name=0:android_meta");
+
+ // Define a single private partition filling the rest of disk.
+ cmd.push_back("--new=0:0:-0");
+ cmd.push_back(StringPrintf("--typecode=0:%s", kGptAndroidExt));
+ cmd.push_back(StringPrintf("--partition-guid=0:%s", partGuid.c_str()));
+ cmd.push_back("--change-name=0:android_ext");
+
+ cmd.push_back(mDevPath);
+
+ if (ForkExecvp(cmd, &status, false, true)) {
+ LOG(ERROR) << "Failed to partition; status " << status;
+ return -EIO;
+ }
+
+ return OK;
}
int Disk::getMaxMinors() {
diff --git a/Disk.h b/Disk.h
index f3825fe..82ef1f5 100644
--- a/Disk.h
+++ b/Disk.h
@@ -68,6 +68,8 @@ public:
status_t readMetadata();
status_t readPartitions();
+ status_t unmountAll();
+
status_t partitionPublic();
status_t partitionPrivate();
status_t partitionMixed(int8_t ratio);
@@ -97,7 +99,7 @@ private:
bool mCreated;
void createPublicVolume(dev_t device);
- void createPrivateVolume(dev_t device);
+ void createPrivateVolume(dev_t device, const std::string& partGuid);
void destroyAllVolumes();
diff --git a/EmulatedVolume.cpp b/EmulatedVolume.cpp
index 0a1418b..5dcab72 100644
--- a/EmulatedVolume.cpp
+++ b/EmulatedVolume.cpp
@@ -53,7 +53,7 @@ EmulatedVolume::~EmulatedVolume() {
status_t EmulatedVolume::doMount() {
if (fs_prepare_dir(mFusePath.c_str(), 0700, AID_ROOT, AID_ROOT)) {
- PLOG(ERROR) << "Failed to create mount point " << mFusePath;
+ PLOG(ERROR) << getId() << " failed to create mount point " << mFusePath;
return -errno;
}
@@ -75,7 +75,7 @@ status_t EmulatedVolume::doMount() {
}
if (mFusePid == -1) {
- PLOG(ERROR) << "Failed to fork";
+ PLOG(ERROR) << getId() << " failed to fork";
return -errno;
}
@@ -93,7 +93,7 @@ status_t EmulatedVolume::doUnmount() {
ForceUnmount(mRawPath);
if (TEMP_FAILURE_RETRY(rmdir(mFusePath.c_str()))) {
- PLOG(ERROR) << "Failed to rmdir mount point " << mFusePath;
+ PLOG(ERROR) << getId() << " failed to rmdir mount point " << mFusePath;
return -errno;
}
diff --git a/Ext4.cpp b/Ext4.cpp
index f5a964a..42d6cd3 100644
--- a/Ext4.cpp
+++ b/Ext4.cpp
@@ -23,6 +23,8 @@
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
+#include <vector>
+#include <string>
#include <sys/types.h>
#include <sys/stat.h>
@@ -35,17 +37,92 @@
#define LOG_TAG "Vold"
+#include <base/stringprintf.h>
#include <cutils/log.h>
#include <cutils/properties.h>
-
#include <logwrap/logwrap.h>
#include "Ext4.h"
+#include "Utils.h"
#include "VoldUtil.h"
-#define MKEXT4FS_PATH "/system/bin/make_ext4fs"
#define RESIZE2FS_PATH "/system/bin/resize2fs"
+using android::base::StringPrintf;
+
+static const char* kMkfsPath = "/system/bin/make_ext4fs";
+
+static const char* kFsckPath = "/system/bin/e2fsck";
+static const char* kFsckLogFile = "/dev/fscklogs/log";
+
+int Ext4::check(const char *fsPath, const char *mountPoint) {
+ // The following is shamelessly borrowed from fs_mgr.c, so it should be
+ // kept in sync with any changes over there.
+
+ char* blk_device = (char*) fsPath;
+ char* target = (char*) mountPoint;
+
+ int status;
+ int ret;
+ long tmpmnt_flags = MS_NOATIME | MS_NOEXEC | MS_NOSUID;
+ char *tmpmnt_opts = (char*) "nomblk_io_submit,errors=remount-ro";
+ char *e2fsck_argv[] = {
+ (char*) kFsckPath,
+ (char*) "-y",
+ blk_device
+ };
+
+ /*
+ * First try to mount and unmount the filesystem. We do this because
+ * the kernel is more efficient than e2fsck in running the journal and
+ * processing orphaned inodes, and on at least one device with a
+ * performance issue in the emmc firmware, it can take e2fsck 2.5 minutes
+ * to do what the kernel does in about a second.
+ *
+ * After mounting and unmounting the filesystem, run e2fsck, and if an
+ * error is recorded in the filesystem superblock, e2fsck will do a full
+ * check. Otherwise, it does nothing. If the kernel cannot mount the
+ * filesytsem due to an error, e2fsck is still run to do a full check
+ * fix the filesystem.
+ */
+ ret = mount(blk_device, target, "ext4", tmpmnt_flags, tmpmnt_opts);
+ if (!ret) {
+ int i;
+ for (i = 0; i < 5; i++) {
+ // Try to umount 5 times before continuing on.
+ // Should we try rebooting if all attempts fail?
+ int result = umount(target);
+ if (result == 0) {
+ break;
+ }
+ ALOGW("%s(): umount(%s)=%d: %s\n", __func__, target, result, strerror(errno));
+ sleep(1);
+ }
+ }
+
+ /*
+ * Some system images do not have e2fsck for licensing reasons
+ * (e.g. recent SDK system images). Detect these and skip the check.
+ */
+ if (access(kFsckPath, X_OK)) {
+ ALOGD("Not running %s on %s (executable not in system image)\n",
+ kFsckPath, blk_device);
+ } else {
+ ALOGD("Running %s on %s\n", kFsckPath, blk_device);
+
+ ret = android_fork_execvp(ARRAY_SIZE(e2fsck_argv), e2fsck_argv,
+ &status, false, true);
+
+ if (ret < 0) {
+ /* No need to check for error in fork, we can't really handle it now */
+ ALOGW("Failed trying to run %s\n", kFsckPath);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
int Ext4::doMount(const char *fsPath, const char *mountPoint, bool ro, bool remount,
bool executable) {
int rc;
@@ -112,28 +189,23 @@ int Ext4::resize(const char *fspath, unsigned int numSectors) {
}
int Ext4::format(const char *fsPath, unsigned int numSectors, const char *mountpoint) {
- const char *args[7];
- int rc;
int status;
- args[0] = MKEXT4FS_PATH;
- args[1] = "-J";
- args[2] = "-a";
- args[3] = mountpoint;
+ std::vector<std::string> cmd;
+ cmd.push_back(kMkfsPath);
+ cmd.push_back("-J");
+
+ cmd.push_back("-a");
+ cmd.push_back(mountpoint);
+
if (numSectors) {
- char tmp[32];
- snprintf(tmp, sizeof(tmp), "%u", numSectors * 512);
- const char *size = tmp;
- args[4] = "-l";
- args[5] = size;
- args[6] = fsPath;
- rc = android_fork_execvp(ARRAY_SIZE(args), (char **)args, &status, false, true);
- } else {
- args[4] = fsPath;
- rc = android_fork_execvp(5, (char **)args, &status, false, true);
+ cmd.push_back("-l");
+ cmd.push_back(StringPrintf("%u", numSectors * 512));
}
- rc = android_fork_execvp(ARRAY_SIZE(args), (char **)args, &status, false,
- true);
+
+ cmd.push_back(fsPath);
+
+ int rc = android::vold::ForkExecvp(cmd, &status, false, true);
if (rc != 0) {
SLOGE("Filesystem (ext4) format failed due to logwrap error");
errno = EIO;
diff --git a/Ext4.h b/Ext4.h
index c768f5a..55672af 100644
--- a/Ext4.h
+++ b/Ext4.h
@@ -21,6 +21,7 @@
class Ext4 {
public:
+ static int check(const char *fsPath, const char *mountPoint);
static int doMount(const char *fsPath, const char *mountPoint, bool ro, bool remount,
bool executable);
static int format(const char *fsPath, unsigned int numSectors, const char *mountpoint);
diff --git a/PrivateVolume.cpp b/PrivateVolume.cpp
new file mode 100644
index 0000000..42eea64
--- /dev/null
+++ b/PrivateVolume.cpp
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Ext4.h"
+#include "PrivateVolume.h"
+#include "Utils.h"
+#include "VolumeManager.h"
+#include "ResponseCode.h"
+#include "cryptfs.h"
+
+#include <base/stringprintf.h>
+#include <base/logging.h>
+#include <cutils/fs.h>
+#include <private/android_filesystem_config.h>
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/param.h>
+
+using android::base::StringPrintf;
+
+namespace android {
+namespace vold {
+
+PrivateVolume::PrivateVolume(dev_t device, const std::string& keyRaw) :
+ VolumeBase(Type::kPrivate), mRawDevice(device), mKeyRaw(keyRaw) {
+ setId(StringPrintf("private:%u,%u", major(device), minor(device)));
+ mRawDevPath = StringPrintf("/dev/block/vold/%s", getId().c_str());
+ mPath = StringPrintf("/mnt/secure/%s", getId().c_str());
+}
+
+PrivateVolume::~PrivateVolume() {
+}
+
+status_t PrivateVolume::readMetadata() {
+ status_t res = ReadMetadata(mDmDevPath, mFsType, mFsUuid, mFsLabel);
+
+ VolumeManager::Instance()->getBroadcaster()->sendBroadcast(
+ ResponseCode::VolumeFsTypeChanged,
+ StringPrintf("%s %s", getId().c_str(), mFsType.c_str()).c_str(), false);
+ VolumeManager::Instance()->getBroadcaster()->sendBroadcast(
+ ResponseCode::VolumeFsUuidChanged,
+ StringPrintf("%s %s", getId().c_str(), mFsUuid.c_str()).c_str(), false);
+ VolumeManager::Instance()->getBroadcaster()->sendBroadcast(
+ ResponseCode::VolumeFsLabelChanged,
+ StringPrintf("%s %s", getId().c_str(), mFsLabel.c_str()).c_str(), false);
+
+ return res;
+}
+
+status_t PrivateVolume::doCreate() {
+ if (CreateDeviceNode(mRawDevPath, mRawDevice)) {
+ return -EIO;
+ }
+
+ // Recover from stale vold by tearing down any old mappings
+ cryptfs_revert_ext_volume(getId().c_str());
+
+ // TODO: figure out better SELinux labels for private volumes
+
+ unsigned char* key = (unsigned char*) mKeyRaw.data();
+ char crypto_blkdev[MAXPATHLEN];
+ int res = cryptfs_setup_ext_volume(getId().c_str(), mRawDevPath.c_str(),
+ key, mKeyRaw.size(), crypto_blkdev);
+ mDmDevPath = crypto_blkdev;
+ if (res != 0) {
+ PLOG(ERROR) << getId() << " failed to setup cryptfs";
+ return -EIO;
+ }
+
+ return OK;
+}
+
+status_t PrivateVolume::doDestroy() {
+ if (cryptfs_revert_ext_volume(getId().c_str())) {
+ LOG(ERROR) << getId() << " failed to revert cryptfs";
+ }
+ return DestroyDeviceNode(mRawDevPath);
+}
+
+status_t PrivateVolume::doMount() {
+ if (readMetadata()) {
+ LOG(ERROR) << getId() << " failed to read metadata";
+ return -EIO;
+ }
+
+ if (Ext4::check(mDmDevPath.c_str(), mPath.c_str())) {
+ PLOG(ERROR) << getId() << " failed filesystem check";
+ return -EIO;
+ }
+
+ setPath(mPath);
+
+ if (fs_prepare_dir(mPath.c_str(), 0700, AID_ROOT, AID_ROOT)) {
+ PLOG(ERROR) << getId() << " failed to create mount point " << mPath;
+ return -errno;
+ }
+
+ if (Ext4::doMount(mDmDevPath.c_str(), mPath.c_str(), false, false, true)) {
+ PLOG(ERROR) << getId() << " failed to mount";
+ return -EIO;
+ }
+
+ return OK;
+}
+
+status_t PrivateVolume::doUnmount() {
+ ForceUnmount(mPath);
+
+ if (TEMP_FAILURE_RETRY(rmdir(mPath.c_str()))) {
+ PLOG(ERROR) << getId() << " failed to rmdir mount point " << mPath;
+ }
+
+ return OK;
+}
+
+status_t PrivateVolume::doFormat() {
+ // TODO: change mountpoint once we have selinux labels
+ if (Ext4::format(mDmDevPath.c_str(), 0, "/data")) {
+ PLOG(ERROR) << getId() << " failed to format";
+ return -EIO;
+ }
+
+ return OK;
+}
+
+} // namespace vold
+} // namespace android
diff --git a/PrivateVolume.h b/PrivateVolume.h
new file mode 100644
index 0000000..bd464e6
--- /dev/null
+++ b/PrivateVolume.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_VOLD_PRIVATE_VOLUME_H
+#define ANDROID_VOLD_PRIVATE_VOLUME_H
+
+#include "VolumeBase.h"
+
+#include <cutils/multiuser.h>
+
+namespace android {
+namespace vold {
+
+/*
+ * Private storage provided by an encrypted partition.
+ *
+ * Given a raw block device, it knows how to wrap it in dm-crypt and
+ * format as ext4/f2fs. EmulatedVolume can be stacked above it.
+ *
+ * This volume is designed to behave much like the internal /data
+ * partition, both in layout and function. For example, apps and
+ * private app data can be safely stored on this volume because the
+ * keys are tightly tied to this device.
+ */
+class PrivateVolume : public VolumeBase {
+public:
+ PrivateVolume(dev_t device, const std::string& keyRaw);
+ virtual ~PrivateVolume();
+
+protected:
+ status_t doCreate() override;
+ status_t doDestroy() override;
+ status_t doMount() override;
+ status_t doUnmount() override;
+ status_t doFormat() override;
+
+ status_t readMetadata();
+
+private:
+ /* Kernel device of raw, encrypted partition */
+ dev_t mRawDevice;
+ /* Path to raw, encrypted block device */
+ std::string mRawDevPath;
+ /* Path to decrypted block device */
+ std::string mDmDevPath;
+ /* Path where decrypted device is mounted */
+ std::string mPath;
+
+ /* Encryption key as raw bytes */
+ std::string mKeyRaw;
+
+ /* Filesystem type */
+ std::string mFsType;
+ /* Filesystem UUID */
+ std::string mFsUuid;
+ /* User-visible filesystem label */
+ std::string mFsLabel;
+
+ DISALLOW_COPY_AND_ASSIGN(PrivateVolume);
+};
+
+} // namespace vold
+} // namespace android
+
+#endif
diff --git a/PublicVolume.cpp b/PublicVolume.cpp
index e4ed9c1..f3bd905 100644
--- a/PublicVolume.cpp
+++ b/PublicVolume.cpp
@@ -37,7 +37,6 @@ using android::base::StringPrintf;
namespace android {
namespace vold {
-static const char* kBlkidPath = "/system/bin/blkid";
static const char* kFusePath = "/system/bin/sdcard";
static const char* kAsecPath = "/mnt/secure/asec";
@@ -46,51 +45,13 @@ PublicVolume::PublicVolume(dev_t device) :
VolumeBase(Type::kPublic), mDevice(device), mFusePid(0) {
setId(StringPrintf("public:%u,%u", major(device), minor(device)));
mDevPath = StringPrintf("/dev/block/vold/%s", getId().c_str());
- CreateDeviceNode(mDevPath, mDevice);
}
PublicVolume::~PublicVolume() {
- DestroyDeviceNode(mDevPath);
}
status_t PublicVolume::readMetadata() {
- mFsType.clear();
- mFsUuid.clear();
- mFsLabel.clear();
-
- std::string path(StringPrintf("%s -c /dev/null %s", kBlkidPath, mDevPath.c_str()));
- FILE* fp = popen(path.c_str(), "r");
- if (!fp) {
- PLOG(ERROR) << "Failed to run " << path;
- return -errno;
- }
-
- status_t res = OK;
- char line[1024];
- char value[128];
- if (fgets(line, sizeof(line), fp) != nullptr) {
- LOG(DEBUG) << "blkid identified as " << line;
-
- char* start = strstr(line, "TYPE=");
- if (start != nullptr && sscanf(start + 5, "\"%127[^\"]\"", value) == 1) {
- mFsType = value;
- }
-
- start = strstr(line, "UUID=");
- if (start != nullptr && sscanf(start + 5, "\"%127[^\"]\"", value) == 1) {
- mFsUuid = value;
- }
-
- start = strstr(line, "LABEL=");
- if (start != nullptr && sscanf(start + 6, "\"%127[^\"]\"", value) == 1) {
- mFsLabel = value;
- }
- } else {
- LOG(WARNING) << "blkid failed to identify " << mDevPath;
- res = -ENODATA;
- }
-
- pclose(fp);
+ status_t res = ReadMetadata(mDevPath, mFsType, mFsUuid, mFsLabel);
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(
ResponseCode::VolumeFsTypeChanged,
@@ -113,13 +74,13 @@ status_t PublicVolume::initAsecStage() {
if (!access(legacyPath.c_str(), R_OK | X_OK)
&& access(securePath.c_str(), R_OK | X_OK)) {
if (rename(legacyPath.c_str(), securePath.c_str())) {
- PLOG(WARNING) << "Failed to rename legacy ASEC dir";
+ PLOG(WARNING) << getId() << " failed to rename legacy ASEC dir";
}
}
if (TEMP_FAILURE_RETRY(mkdir(securePath.c_str(), 0700))) {
if (errno != EEXIST) {
- PLOG(WARNING) << "Creating ASEC stage failed";
+ PLOG(WARNING) << getId() << " creating ASEC stage failed";
return -errno;
}
}
@@ -129,15 +90,23 @@ status_t PublicVolume::initAsecStage() {
return OK;
}
+status_t PublicVolume::doCreate() {
+ return CreateDeviceNode(mDevPath, mDevice);
+}
+
+status_t PublicVolume::doDestroy() {
+ return DestroyDeviceNode(mDevPath);
+}
+
status_t PublicVolume::doMount() {
// TODO: expand to support mounting other filesystems
+ readMetadata();
+
if (Fat::check(mDevPath.c_str())) {
- LOG(ERROR) << "Failed filesystem check; not mounting";
+ LOG(ERROR) << getId() << " failed filesystem check";
return -EIO;
}
- readMetadata();
-
// Use UUID as stable name, if available
std::string stableName = getId();
if (!mFsUuid.empty()) {
@@ -149,17 +118,17 @@ status_t PublicVolume::doMount() {
setPath(mFusePath);
if (fs_prepare_dir(mRawPath.c_str(), 0700, AID_ROOT, AID_ROOT)) {
- PLOG(ERROR) << "Failed to create mount point " << mRawPath;
+ PLOG(ERROR) << getId() << " failed to create mount point " << mRawPath;
return -errno;
}
if (fs_prepare_dir(mFusePath.c_str(), 0700, AID_ROOT, AID_ROOT)) {
- PLOG(ERROR) << "Failed to create mount point " << mFusePath;
+ PLOG(ERROR) << getId() << " failed to create mount point " << mFusePath;
return -errno;
}
if (Fat::doMount(mDevPath.c_str(), mRawPath.c_str(), false, false, false,
AID_MEDIA_RW, AID_MEDIA_RW, 0007, true)) {
- PLOG(ERROR) << "Failed to mount " << mDevPath;
+ PLOG(ERROR) << getId() << " failed to mount " << mDevPath;
return -EIO;
}
@@ -202,7 +171,7 @@ status_t PublicVolume::doMount() {
}
if (mFusePid == -1) {
- PLOG(ERROR) << "Failed to fork";
+ PLOG(ERROR) << getId() << " failed to fork";
return -errno;
}
@@ -220,10 +189,10 @@ status_t PublicVolume::doUnmount() {
ForceUnmount(mRawPath);
if (TEMP_FAILURE_RETRY(rmdir(mRawPath.c_str()))) {
- PLOG(ERROR) << "Failed to rmdir mount point " << mRawPath;
+ PLOG(ERROR) << getId() << " failed to rmdir mount point " << mRawPath;
}
if (TEMP_FAILURE_RETRY(rmdir(mFusePath.c_str()))) {
- PLOG(ERROR) << "Failed to rmdir mount point " << mFusePath;
+ PLOG(ERROR) << getId() << " failed to rmdir mount point " << mFusePath;
}
mFusePath.clear();
@@ -234,7 +203,7 @@ status_t PublicVolume::doUnmount() {
status_t PublicVolume::doFormat() {
if (Fat::format(mDevPath.c_str(), 0, true)) {
- LOG(ERROR) << "Failed to format";
+ LOG(ERROR) << getId() << " failed to format";
return -errno;
}
return OK;
diff --git a/PublicVolume.h b/PublicVolume.h
index 2d2ec6b..45313ec 100644
--- a/PublicVolume.h
+++ b/PublicVolume.h
@@ -43,6 +43,8 @@ public:
virtual ~PublicVolume();
protected:
+ status_t doCreate() override;
+ status_t doDestroy() override;
status_t doMount() override;
status_t doUnmount() override;
status_t doFormat() override;
diff --git a/Utils.cpp b/Utils.cpp
index b5d037a..7d32590 100644
--- a/Utils.cpp
+++ b/Utils.cpp
@@ -19,8 +19,10 @@
#include "Process.h"
#include <base/logging.h>
+#include <base/stringprintf.h>
#include <cutils/fs.h>
#include <private/android_filesystem_config.h>
+#include <logwrap/logwrap.h>
#include <fcntl.h>
#include <linux/fs.h>
@@ -34,9 +36,13 @@
#define UMOUNT_NOFOLLOW 0x00000008 /* Don't follow symlink on umount */
#endif
+using android::base::StringPrintf;
+
namespace android {
namespace vold {
+static const char* kBlkidPath = "/system/bin/blkid";
+
status_t CreateDeviceNode(const std::string& path, dev_t dev) {
const char* cpath = path.c_str();
status_t res = 0;
@@ -81,14 +87,14 @@ status_t ForceUnmount(const std::string& path) {
}
PLOG(WARNING) << "Failed to unmount " << path << "; sending SIGTERM";
Process::killProcessesWithOpenFiles(cpath, SIGTERM);
- sleep(1);
+ sleep(5);
if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) {
return OK;
}
PLOG(WARNING) << "Failed to unmount " << path << "; sending SIGKILL";
Process::killProcessesWithOpenFiles(cpath, SIGKILL);
- sleep(1);
+ sleep(5);
if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) {
return OK;
@@ -105,5 +111,138 @@ status_t BindMount(const std::string& source, const std::string& target) {
return OK;
}
+status_t ReadMetadata(const std::string& path, std::string& fsType,
+ std::string& fsUuid, std::string& fsLabel) {
+ fsType.clear();
+ fsUuid.clear();
+ fsLabel.clear();
+
+ std::string cmd(StringPrintf("%s -c /dev/null %s", kBlkidPath, path.c_str()));
+ FILE* fp = popen(cmd.c_str(), "r");
+ if (!fp) {
+ PLOG(ERROR) << "Failed to run " << cmd;
+ return -errno;
+ }
+
+ status_t res = OK;
+ char line[1024];
+ char value[128];
+ if (fgets(line, sizeof(line), fp) != nullptr) {
+ LOG(DEBUG) << "blkid identified " << path << " as " << line;
+
+ // Extract values from blkid output, if defined
+ char* start = strstr(line, "TYPE=");
+ if (start != nullptr && sscanf(start + 5, "\"%127[^\"]\"", value) == 1) {
+ fsType = value;
+ }
+
+ start = strstr(line, "UUID=");
+ if (start != nullptr && sscanf(start + 5, "\"%127[^\"]\"", value) == 1) {
+ fsUuid = value;
+ }
+
+ start = strstr(line, "LABEL=");
+ if (start != nullptr && sscanf(start + 6, "\"%127[^\"]\"", value) == 1) {
+ fsLabel = value;
+ }
+ } else {
+ LOG(WARNING) << "blkid failed to identify " << path;
+ res = -ENODATA;
+ }
+
+ pclose(fp);
+ return res;
+}
+
+status_t ForkExecvp(const std::vector<std::string>& args, int* status,
+ bool ignore_int_quit, bool logwrap) {
+ int argc = args.size();
+ char** argv = (char**) calloc(argc, sizeof(char*));
+ for (int i = 0; i < argc; i++) {
+ argv[i] = (char*) args[i].c_str();
+ if (i == 0) {
+ LOG(VERBOSE) << args[i];
+ } else {
+ LOG(VERBOSE) << " " << args[i];
+ }
+ }
+ int res = android_fork_execvp(argc, argv, status, ignore_int_quit, logwrap);
+ free(argv);
+ return res;
+}
+
+status_t ReadRandomBytes(size_t bytes, std::string& out) {
+ out.clear();
+
+ int fd = TEMP_FAILURE_RETRY(open("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
+ if (fd == -1) {
+ return -errno;
+ }
+
+ char buf[BUFSIZ];
+ size_t n;
+ while ((n = TEMP_FAILURE_RETRY(read(fd, &buf[0], std::min(sizeof(buf), bytes)))) > 0) {
+ out.append(buf, n);
+ bytes -= n;
+ }
+ TEMP_FAILURE_RETRY(close(fd));
+
+ if (bytes == 0) {
+ return OK;
+ } else {
+ return -EIO;
+ }
+}
+
+status_t HexToStr(const std::string& hex, std::string& str) {
+ str.clear();
+ bool even = true;
+ char cur = 0;
+ for (size_t i = 0; i < hex.size(); i++) {
+ int val = 0;
+ switch (hex[i]) {
+ case ' ': case '-': case ':': continue;
+ case 'f': case 'F': val = 15; break;
+ case 'e': case 'E': val = 14; break;
+ case 'd': case 'D': val = 13; break;
+ case 'c': case 'C': val = 12; break;
+ case 'b': case 'B': val = 11; break;
+ case 'a': case 'A': val = 10; break;
+ case '9': val = 9; break;
+ case '8': val = 8; break;
+ case '7': val = 7; break;
+ case '6': val = 6; break;
+ case '5': val = 5; break;
+ case '4': val = 4; break;
+ case '3': val = 3; break;
+ case '2': val = 2; break;
+ case '1': val = 1; break;
+ case '0': val = 0; break;
+ default: return -EINVAL;
+ }
+
+ if (even) {
+ cur = val << 4;
+ } else {
+ cur += val;
+ str.push_back(cur);
+ cur = 0;
+ }
+ even = !even;
+ }
+ return even ? OK : -EINVAL;
+}
+
+static const char* kLookup = "0123456789abcdef";
+
+status_t StrToHex(const std::string& str, std::string& hex) {
+ hex.clear();
+ for (size_t i = 0; i < str.size(); i++) {
+ hex.push_back(kLookup[str[i] >> 4]);
+ hex.push_back(kLookup[str[i] & 0x0F]);
+ }
+ return OK;
+}
+
} // namespace vold
} // namespace android
diff --git a/Utils.h b/Utils.h
index 660ef19..0e0904e 100644
--- a/Utils.h
+++ b/Utils.h
@@ -19,6 +19,7 @@
#include <utils/Errors.h>
+#include <vector>
#include <string>
// DISALLOW_COPY_AND_ASSIGN disallows the copy and operator= functions. It goes in the private:
@@ -41,6 +42,18 @@ status_t ForceUnmount(const std::string& path);
/* Creates bind mount from source to target */
status_t BindMount(const std::string& source, const std::string& target);
+/* Reads filesystem metadata from device at path */
+status_t ReadMetadata(const std::string& path, std::string& fsType,
+ std::string& fsUuid, std::string& fsLabel);
+
+status_t ForkExecvp(const std::vector<std::string>& args, int* status,
+ bool ignore_int_quit, bool logwrap);
+
+status_t ReadRandomBytes(size_t bytes, std::string& out);
+
+status_t HexToStr(const std::string& hex, std::string& str);
+status_t StrToHex(const std::string& str, std::string& hex);
+
} // namespace vold
} // namespace android
diff --git a/Volume.cpp b/Volume.cpp
index 497a7be..625e94d 100644
--- a/Volume.cpp
+++ b/Volume.cpp
@@ -395,12 +395,12 @@ int Volume::mountVol() {
return -1;
}
- if (cryptfs_setup_volume(getLabel(), MAJOR(deviceNodes[0]), MINOR(deviceNodes[0]),
- new_sys_path, sizeof(new_sys_path),
- &new_major, &new_minor)) {
+// if (cryptfs_setup_volume(getLabel(), MAJOR(deviceNodes[0]), MINOR(deviceNodes[0]),
+// new_sys_path, sizeof(new_sys_path),
+// &new_major, &new_minor)) {
SLOGE("Cannot setup encryption mapping for %s\n", getMountpoint());
return -1;
- }
+// }
/* We now have the new sysfs path for the decrypted block device, and the
* majore and minor numbers for it. So, create the device, update the
* path to the new sysfs path, and continue.
@@ -587,8 +587,8 @@ int Volume::unmountVol(bool force, bool revert) {
* the device info to the original values.
*/
if (revert && isDecrypted()) {
- cryptfs_revert_volume(getLabel());
- revertDeviceInfo();
+// cryptfs_revert_volume(getLabel());
+// revertDeviceInfo();
SLOGI("Encrypted volume %s reverted successfully", getMountpoint());
}
diff --git a/VolumeBase.cpp b/VolumeBase.cpp
index 8d160ae..292a4cd 100644
--- a/VolumeBase.cpp
+++ b/VolumeBase.cpp
@@ -113,10 +113,16 @@ std::shared_ptr<VolumeBase> VolumeBase::findVolume(const std::string& id) {
status_t VolumeBase::create() {
CHECK(!mCreated);
+
mCreated = true;
+ status_t res = doCreate();
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(
ResponseCode::VolumeCreated,
StringPrintf("%s %d", getId().c_str(), mType).c_str(), false);
+ return res;
+}
+
+status_t VolumeBase::doCreate() {
return OK;
}
@@ -127,9 +133,14 @@ status_t VolumeBase::destroy() {
unmount();
}
- mCreated = false;
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(
ResponseCode::VolumeDestroyed, getId().c_str(), false);
+ status_t res = doDestroy();
+ mCreated = false;
+ return res;
+}
+
+status_t VolumeBase::doDestroy() {
return OK;
}
diff --git a/VolumeBase.h b/VolumeBase.h
index e7be8fb..e3d91ff 100644
--- a/VolumeBase.h
+++ b/VolumeBase.h
@@ -87,7 +87,6 @@ public:
status_t create();
status_t destroy();
-
status_t mount();
status_t unmount();
status_t format();
@@ -95,6 +94,8 @@ public:
protected:
explicit VolumeBase(Type type);
+ virtual status_t doCreate();
+ virtual status_t doDestroy();
virtual status_t doMount() = 0;
virtual status_t doUnmount() = 0;
virtual status_t doFormat();
diff --git a/VolumeManager.cpp b/VolumeManager.cpp
index 0404ce7..5296114 100644
--- a/VolumeManager.cpp
+++ b/VolumeManager.cpp
@@ -243,30 +243,7 @@ void VolumeManager::setDebug(bool enable) {
int VolumeManager::start() {
// Always start from a clean slate by unmounting everything in
// directories that we own, in case we crashed.
- FILE* fp = setmntent("/proc/mounts", "r");
- if (fp == NULL) {
- SLOGE("Error opening /proc/mounts: %s", strerror(errno));
- return -errno;
- }
-
- // Some volumes can be stacked on each other, so force unmount in
- // reverse order to give us the best chance of success.
- std::list<std::string> toUnmount;
- mntent* mentry;
- while ((mentry = getmntent(fp)) != NULL) {
- if (strncmp(mentry->mnt_dir, "/mnt/", 5) == 0
- || strncmp(mentry->mnt_dir, "/storage/", 9) == 0) {
- toUnmount.push_front(std::string(mentry->mnt_dir));
- }
- }
- endmntent(fp);
-
- for (auto path : toUnmount) {
- SLOGW("Tearing down stale mount %s", path.c_str());
- android::vold::ForceUnmount(path);
- }
-
- // TODO: nuke all files under mnt and storage tmpfs too?
+ unmountAll();
// Assume that we always have an emulated volume on internal
// storage; the framework will decide if it should be mounted.
@@ -440,6 +417,7 @@ int VolumeManager::reset() {
}
int VolumeManager::shutdown() {
+ mInternalEmulated->destroy();
for (auto disk : mDisks) {
disk->destroy();
}
@@ -447,6 +425,43 @@ int VolumeManager::shutdown() {
return 0;
}
+int VolumeManager::unmountAll() {
+ // First, try gracefully unmounting all known devices
+ if (mInternalEmulated != nullptr) {
+ mInternalEmulated->unmount();
+ }
+ for (auto disk : mDisks) {
+ disk->unmountAll();
+ }
+
+ // Worst case we might have some stale mounts lurking around, so
+ // force unmount those just to be safe.
+ FILE* fp = setmntent("/proc/mounts", "r");
+ if (fp == NULL) {
+ SLOGE("Error opening /proc/mounts: %s", strerror(errno));
+ return -errno;
+ }
+
+ // Some volumes can be stacked on each other, so force unmount in
+ // reverse order to give us the best chance of success.
+ std::list<std::string> toUnmount;
+ mntent* mentry;
+ while ((mentry = getmntent(fp)) != NULL) {
+ if (strncmp(mentry->mnt_dir, "/mnt/", 5) == 0
+ || strncmp(mentry->mnt_dir, "/storage/", 9) == 0) {
+ toUnmount.push_front(std::string(mentry->mnt_dir));
+ }
+ }
+ endmntent(fp);
+
+ for (auto path : toUnmount) {
+ SLOGW("Tearing down stale mount %s", path.c_str());
+ android::vold::ForceUnmount(path);
+ }
+
+ return 0;
+}
+
int VolumeManager::listVolumes(SocketClient *cli, bool broadcast) {
VolumeCollection::iterator i;
char msg[256];
@@ -1831,35 +1846,6 @@ int VolumeManager::unshareVolume(const char *label, const char *method) {
return 0;
}
-extern "C" int vold_disableVol(const char *label) {
- VolumeManager *vm = VolumeManager::Instance();
- vm->disableVolumeManager();
- vm->unshareVolume(label, "ums");
- return vm->unmountVolume(label, true, false);
-}
-
-extern "C" int vold_getNumDirectVolumes(void) {
- VolumeManager *vm = VolumeManager::Instance();
- return vm->getNumDirectVolumes();
-}
-
-int VolumeManager::getNumDirectVolumes(void) {
- VolumeCollection::iterator i;
- int n=0;
-
- for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
- if ((*i)->getShareDevice() != (dev_t)0) {
- n++;
- }
- }
- return n;
-}
-
-extern "C" int vold_getDirectVolumeList(struct volume_info *vol_list) {
- VolumeManager *vm = VolumeManager::Instance();
- return vm->getDirectVolumeList(vol_list);
-}
-
int VolumeManager::getDirectVolumeList(struct volume_info *vol_list) {
VolumeCollection::iterator i;
int n=0;
@@ -1902,15 +1888,9 @@ int VolumeManager::unmountVolume(const char *label, bool force, bool revert) {
return v->unmountVol(force, revert);
}
-extern "C" int vold_unmountAllAsecs(void) {
- int rc;
-
+extern "C" int vold_unmountAll(void) {
VolumeManager *vm = VolumeManager::Instance();
- rc = vm->unmountAllAsecsInDir(Volume::SEC_ASECDIR_EXT);
- if (vm->unmountAllAsecsInDir(Volume::SEC_ASECDIR_INT)) {
- rc = -1;
- }
- return rc;
+ return vm->unmountAll();
}
#define ID_BUF_LEN 256
diff --git a/VolumeManager.h b/VolumeManager.h
index 5b3fbf6..f36561c 100644
--- a/VolumeManager.h
+++ b/VolumeManager.h
@@ -118,6 +118,8 @@ public:
int reset();
/* Prepare for device shutdown, safely unmounting all devices */
int shutdown();
+ /* Unmount all volumes, usually for encryption */
+ int unmountAll();
int listVolumes(SocketClient *cli, bool broadcast);
int mountVolume(const char *label);
@@ -213,10 +215,7 @@ private:
extern "C" {
#endif /* __cplusplus */
#define UNMOUNT_NOT_MOUNTED_ERR -2
- int vold_disableVol(const char *label);
- int vold_getNumDirectVolumes(void);
- int vold_getDirectVolumeList(struct volume_info *v);
- int vold_unmountAllAsecs(void);
+ int vold_unmountAll(void);
#ifdef __cplusplus
}
#endif
diff --git a/cryptfs.c b/cryptfs.c
index 7d2b872..ebce6e8 100644
--- a/cryptfs.c
+++ b/cryptfs.c
@@ -945,9 +945,8 @@ static unsigned char* convert_hex_ascii_to_key(const char* master_key_ascii,
/* Convert a binary key of specified length into an ascii hex string equivalent,
* without the leading 0x and with null termination
*/
-static void convert_key_to_hex_ascii(unsigned char *master_key, unsigned int keysize,
- char *master_key_ascii)
-{
+static void convert_key_to_hex_ascii(const unsigned char *master_key,
+ unsigned int keysize, char *master_key_ascii) {
unsigned int i, a;
unsigned char nibble;
@@ -965,10 +964,9 @@ static void convert_key_to_hex_ascii(unsigned char *master_key, unsigned int key
}
-static int load_crypto_mapping_table(struct crypt_mnt_ftr *crypt_ftr, unsigned char *master_key,
- char *real_blk_name, const char *name, int fd,
- char *extra_params)
-{
+static int load_crypto_mapping_table(struct crypt_mnt_ftr *crypt_ftr,
+ const unsigned char *master_key, const char *real_blk_name,
+ const char *name, int fd, const char *extra_params) {
_Alignas(struct dm_ioctl) char buffer[DM_CRYPT_BUF_SIZE];
struct dm_ioctl *io;
struct dm_target_spec *tgt;
@@ -1057,9 +1055,9 @@ static int get_dm_crypt_version(int fd, const char *name, int *version)
return -1;
}
-static int create_crypto_blk_dev(struct crypt_mnt_ftr *crypt_ftr, unsigned char *master_key,
- char *real_blk_name, char *crypto_blk_name, const char *name)
-{
+static int create_crypto_blk_dev(struct crypt_mnt_ftr *crypt_ftr,
+ const unsigned char *master_key, const char *real_blk_name,
+ char *crypto_blk_name, const char *name) {
char buffer[DM_CRYPT_BUF_SIZE];
struct dm_ioctl *io;
unsigned int minor;
@@ -1885,36 +1883,18 @@ static int test_mount_encrypted_fs(struct crypt_mnt_ftr* crypt_ftr,
return rc;
}
-/* Called by vold when it wants to undo the crypto mapping of a volume it
- * manages. This is usually in response to a factory reset, when we want
- * to undo the crypto mapping so the volume is formatted in the clear.
- */
-int cryptfs_revert_volume(const char *label)
-{
- return delete_crypto_blk_dev((char *)label);
-}
-
/*
- * Called by vold when it's asked to mount an encrypted, nonremovable volume.
- * Setup a dm-crypt mapping, use the saved master key from
- * setting up the /data mapping, and return the new device path.
+ * Called by vold when it's asked to mount an encrypted external
+ * storage volume. The incoming partition has no crypto header/footer,
+ * as any metadata is been stored in a separate, small partition.
+ *
+ * out_crypto_blkdev must be MAXPATHLEN.
*/
-int cryptfs_setup_volume(const char *label, int major, int minor,
- char *crypto_sys_path, unsigned int max_path,
- int *new_major, int *new_minor)
-{
- char real_blkdev[MAXPATHLEN], crypto_blkdev[MAXPATHLEN];
- struct crypt_mnt_ftr sd_crypt_ftr;
- struct stat statbuf;
-
- sprintf(real_blkdev, "/dev/block/vold/%d:%d", major, minor);
-
- get_crypt_ftr_and_key(&sd_crypt_ftr);
-
- /* Update the fs_size field to be the size of the volume */
+int cryptfs_setup_ext_volume(const char* label, const char* real_blkdev,
+ const unsigned char* key, int keysize, char* out_crypto_blkdev) {
int fd = open(real_blkdev, O_RDONLY);
if (fd == -1) {
- SLOGE("Cannot open volume %s\n", real_blkdev);
+ SLOGE("Failed to open %s: %s", real_blkdev, strerror(errno));
return -1;
}
@@ -1923,25 +1903,26 @@ int cryptfs_setup_volume(const char *label, int major, int minor,
close(fd);
if (nr_sec == 0) {
- SLOGE("Cannot get size of volume %s\n", real_blkdev);
+ SLOGE("Failed to get size of %s: %s", real_blkdev, strerror(errno));
return -1;
}
- sd_crypt_ftr.fs_size = nr_sec;
- create_crypto_blk_dev(&sd_crypt_ftr, saved_master_key, real_blkdev,
- crypto_blkdev, label);
-
- if (stat(crypto_blkdev, &statbuf) < 0) {
- SLOGE("Error get stat for crypto_blkdev %s. err=%d(%s)\n",
- crypto_blkdev, errno, strerror(errno));
- }
- *new_major = MAJOR(statbuf.st_rdev);
- *new_minor = MINOR(statbuf.st_rdev);
+ struct crypt_mnt_ftr ext_crypt_ftr;
+ memset(&ext_crypt_ftr, 0, sizeof(ext_crypt_ftr));
+ ext_crypt_ftr.fs_size = nr_sec;
+ ext_crypt_ftr.keysize = keysize;
+ strcpy((char*) ext_crypt_ftr.crypto_type_name, "aes-cbc-essiv:sha256");
- /* Create path to sys entry for this block device */
- snprintf(crypto_sys_path, max_path, "/devices/virtual/block/%s", strrchr(crypto_blkdev, '/')+1);
+ return create_crypto_blk_dev(&ext_crypt_ftr, key, real_blkdev,
+ out_crypto_blkdev, label);
+}
- return 0;
+/*
+ * Called by vold when it's asked to unmount an encrypted external
+ * storage volume.
+ */
+int cryptfs_revert_ext_volume(const char* label) {
+ return delete_crypto_blk_dev((char*) label);
}
int cryptfs_crypto_complete(void)
@@ -2836,12 +2817,6 @@ static int cryptfs_enable_inplace(char *crypto_blkdev, char *real_blkdev,
#define FRAMEWORK_BOOT_WAIT 60
-static inline int should_encrypt(struct volume_info *volume)
-{
- return (volume->flags & (VOL_ENCRYPTABLE | VOL_NONREMOVABLE)) ==
- (VOL_ENCRYPTABLE | VOL_NONREMOVABLE);
-}
-
static int cryptfs_SHA256_fileblock(const char* filename, __le8* buf)
{
int fd = open(filename, O_RDONLY);
@@ -2944,10 +2919,7 @@ int cryptfs_enable_internal(char *howarg, int crypt_type, char *passwd,
char encrypted_state[PROPERTY_VALUE_MAX];
char lockid[32] = { 0 };
char key_loc[PROPERTY_VALUE_MAX];
- char fuse_sdcard[PROPERTY_VALUE_MAX];
- char *sd_mnt_point;
int num_vols;
- struct volume_info *vol_list = 0;
off64_t previously_encrypted_upto = 0;
if (!strcmp(howarg, "wipe")) {
@@ -3022,58 +2994,15 @@ int cryptfs_enable_internal(char *howarg, int crypt_type, char *passwd,
snprintf(lockid, sizeof(lockid), "enablecrypto%d", (int) getpid());
acquire_wake_lock(PARTIAL_WAKE_LOCK, lockid);
- /* Get the sdcard mount point */
- sd_mnt_point = getenv("EMULATED_STORAGE_SOURCE");
- if (!sd_mnt_point) {
- sd_mnt_point = getenv("EXTERNAL_STORAGE");
- }
- if (!sd_mnt_point) {
- sd_mnt_point = "/mnt/sdcard";
- }
-
- /* TODO
- * Currently do not have test devices with multiple encryptable volumes.
- * When we acquire some, re-add support.
- */
- num_vols=vold_getNumDirectVolumes();
- vol_list = malloc(sizeof(struct volume_info) * num_vols);
- vold_getDirectVolumeList(vol_list);
-
- for (i=0; i<num_vols; i++) {
- if (should_encrypt(&vol_list[i])) {
- SLOGE("Cannot encrypt if there are multiple encryptable volumes"
- "%s\n", vol_list[i].label);
- goto error_unencrypted;
- }
- }
-
/* The init files are setup to stop the class main and late start when
* vold sets trigger_shutdown_framework.
*/
property_set("vold.decrypt", "trigger_shutdown_framework");
SLOGD("Just asked init to shut down class main\n");
- if (vold_unmountAllAsecs()) {
- /* Just report the error. If any are left mounted,
- * umounting /data below will fail and handle the error.
- */
- SLOGE("Error unmounting internal asecs");
- }
-
- property_get("ro.crypto.fuse_sdcard", fuse_sdcard, "");
- if (!strcmp(fuse_sdcard, "true")) {
- // STOPSHIP: UNMOUNT ALL STORAGE BEFORE REACHING HERE, SINCE VOLD NOW MANAGES FUSE
- // "ro.crypto.fuse_sdcard" is now deprecated
-
- /* This is a device using the fuse layer to emulate the sdcard semantics
- * on top of the userdata partition. vold does not manage it, it is managed
- * by the sdcard service. The sdcard service was killed by the property trigger
- * above, so just unmount it now. We must do this _AFTER_ killing the framework,
- * unlike the case for vold managed devices above.
- */
- if (wait_and_unmount(sd_mnt_point, false)) {
- goto error_shutting_down;
- }
+ /* Ask vold to unmount all devices that it manages */
+ if (vold_unmountAll()) {
+ SLOGE("Failed to unmount all vold managed devices");
}
/* Now unmount the /data partition. */
@@ -3221,8 +3150,6 @@ int cryptfs_enable_internal(char *howarg, int crypt_type, char *passwd,
/* Undo the dm-crypt mapping whether we succeed or not */
delete_crypto_blk_dev("userdata");
- free(vol_list);
-
if (! rc) {
/* Success */
crypt_ftr.flags &= ~CRYPT_INCONSISTENT_STATE;
@@ -3289,7 +3216,6 @@ int cryptfs_enable_internal(char *howarg, int crypt_type, char *passwd,
return rc;
error_unencrypted:
- free(vol_list);
property_set("vold.encrypt_progress", "error_not_encrypted");
if (lockid[0]) {
release_wake_lock(lockid);
@@ -3306,7 +3232,6 @@ error_shutting_down:
/* shouldn't get here */
property_set("vold.encrypt_progress", "error_shutting_down");
- free(vol_list);
if (lockid[0]) {
release_wake_lock(lockid);
}
diff --git a/cryptfs.h b/cryptfs.h
index c34410a..d630479 100644
--- a/cryptfs.h
+++ b/cryptfs.h
@@ -172,6 +172,7 @@ struct crypt_persist_data {
struct crypt_persist_entry persist_entry[0];
};
+// TODO: remove this deprecated struct
struct volume_info {
unsigned int size;
unsigned int flags;
@@ -232,10 +233,9 @@ extern "C" {
int cryptfs_enable(char *flag, int type, char *passwd, int allow_reboot);
int cryptfs_changepw(int type, const char *newpw);
int cryptfs_enable_default(char *flag, int allow_reboot);
- int cryptfs_setup_volume(const char *label, int major, int minor,
- char *crypto_dev_path, unsigned int max_pathlen,
- int *new_major, int *new_minor);
- int cryptfs_revert_volume(const char *label);
+ int cryptfs_setup_ext_volume(const char* label, const char* real_blkdev,
+ const unsigned char* key, int keysize, char* out_crypto_blkdev);
+ int cryptfs_revert_ext_volume(const char* label);
int cryptfs_getfield(const char *fieldname, char *value, int len);
int cryptfs_setfield(const char *fieldname, const char *value);
int cryptfs_mount_default_encrypted(void);