Add the ability to revert a crypto mapping when unmounting a volume
Add the force_and_revert option to the unmount command which will force
the unmount, and revert a crypto mapping. This is used during factory
reset so that when the internal sdcard volume is formatted, it formats
the raw device, not the encrypted mapping.
Change-Id: I36b6ff9bb54863b121de635472a303bf4a2334a9
diff --git a/CommandListener.cpp b/CommandListener.cpp
index 1672fcc..3a83d2a 100644
--- a/CommandListener.cpp
+++ b/CommandListener.cpp
@@ -138,16 +138,22 @@
}
rc = vm->mountVolume(argv[2]);
} else if (!strcmp(argv[1], "unmount")) {
- if (argc < 3 || argc > 4 || (argc == 4 && strcmp(argv[3], "force"))) {
- cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume unmount <path> [force]", false);
+ if (argc < 3 || argc > 4 ||
+ ((argc == 4 && strcmp(argv[3], "force")) &&
+ (argc == 4 && strcmp(argv[3], "force_and_revert")))) {
+ cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume unmount <path> [force|force_and_revert]", false);
return 0;
}
bool force = false;
+ bool revert = false;
if (argc >= 4 && !strcmp(argv[3], "force")) {
force = true;
+ } else if (argc >= 4 && !strcmp(argv[3], "force_and_revert")) {
+ force = true;
+ revert = true;
}
- rc = vm->unmountVolume(argv[2], force);
+ rc = vm->unmountVolume(argv[2], force, revert);
} else if (!strcmp(argv[1], "format")) {
if (argc != 3) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume format <path>", false);
diff --git a/DirectVolume.cpp b/DirectVolume.cpp
index 2ddd5ab..4acee76 100644
--- a/DirectVolume.cpp
+++ b/DirectVolume.cpp
@@ -317,7 +317,7 @@
SLOGE("Failed to cleanup ASEC - unmount will probably fail!");
}
- if (Volume::unmountVol(true)) {
+ if (Volume::unmountVol(true, false)) {
SLOGE("Failed to unmount volume on bad removal (%s)",
strerror(errno));
// XXX: At this point we're screwed for now
@@ -392,6 +392,16 @@
mPaths->erase(it); /* Remove it from the list */
addPath(new_path); /* Put the new path on the list */
+ /* Save away original info so we can restore it when doing factory reset.
+ * Then, when doing the format, it will format the original device in the
+ * clear, otherwise it just formats the encrypted device which is not
+ * readable when the device boots unencrypted after the reset.
+ */
+ mOrigDiskMajor = mDiskMajor;
+ mOrigDiskMinor = mDiskMinor;
+ mOrigPartIdx = mPartIdx;
+ memcpy(mOrigPartMinors, mPartMinors, sizeof(mPartMinors));
+
mDiskMajor = new_major;
mDiskMinor = new_minor;
/* Ugh, virual block devices don't use minor 0 for whole disk and minor > 0 for
@@ -410,6 +420,24 @@
}
/*
+ * Called from base to revert device info to the way it was before a
+ * crypto mapping was created for it.
+ */
+void DirectVolume::revertDeviceInfo(void)
+{
+ if (mIsDecrypted) {
+ mDiskMajor = mOrigDiskMajor;
+ mDiskMinor = mOrigDiskMinor;
+ mPartIdx = mOrigPartIdx;
+ memcpy(mPartMinors, mOrigPartMinors, sizeof(mPartMinors));
+
+ mIsDecrypted = 0;
+ }
+
+ return;
+}
+
+/*
* Called from base to give cryptfs all the info it needs to encrypt eligible volumes
*/
int DirectVolume::getVolInfo(struct volume_info *v)
diff --git a/DirectVolume.h b/DirectVolume.h
index ad1b386..de1ed8b 100644
--- a/DirectVolume.h
+++ b/DirectVolume.h
@@ -33,6 +33,9 @@
int mDiskMajor;
int mDiskMinor;
int mPartMinors[MAX_PARTITIONS];
+ int mOrigDiskMajor;
+ int mOrigDiskMinor;
+ int mOrigPartMinors[MAX_PARTITIONS];
int mDiskNumParts;
unsigned char mPendingPartMap;
int mIsDecrypted;
@@ -55,6 +58,7 @@
protected:
int getDeviceNodes(dev_t *devs, int max);
int updateDeviceInfo(char *new_path, int new_major, int new_minor);
+ virtual void revertDeviceInfo(void);
int isDecrypted() { return mIsDecrypted; }
int getFlags() { return mFlags; }
diff --git a/Volume.cpp b/Volume.cpp
index 45db27e..e70a590 100644
--- a/Volume.cpp
+++ b/Volume.cpp
@@ -591,7 +591,7 @@
return -1;
}
-int Volume::unmountVol(bool force) {
+int Volume::unmountVol(bool force, bool revert) {
int i, rc;
if (getState() != Volume::State_Mounted) {
@@ -645,6 +645,16 @@
SLOGI("%s unmounted sucessfully", getMountpoint());
+ /* If this is an encrypted volume, and we've been asked to undo
+ * the crypto mapping, then revert the dm-crypt mapping, and revert
+ * the device info to the original values.
+ */
+ if (revert && isDecrypted()) {
+ cryptfs_revert_volume(getLabel());
+ revertDeviceInfo();
+ SLOGI("Encrypted volume %s reverted successfully", getMountpoint());
+ }
+
setState(Volume::State_Idle);
mCurrentlyMountedKdev = -1;
return 0;
diff --git a/Volume.h b/Volume.h
index f57ff91..274fb54 100644
--- a/Volume.h
+++ b/Volume.h
@@ -52,6 +52,7 @@
VolumeManager *mVm;
bool mDebug;
int mPartIdx;
+ int mOrigPartIdx;
bool mRetryMount;
/*
@@ -64,7 +65,7 @@
virtual ~Volume();
int mountVol();
- int unmountVol(bool force);
+ int unmountVol(bool force, bool revert);
int formatVol();
const char *getLabel() { return mLabel; }
@@ -85,6 +86,7 @@
virtual int getDeviceNodes(dev_t *devs, int max) = 0;
virtual int updateDeviceInfo(char *new_path, int new_major, int new_minor) = 0;
+ virtual void revertDeviceInfo(void) = 0;
virtual int isDecrypted(void) = 0;
virtual int getFlags(void) = 0;
diff --git a/VolumeManager.cpp b/VolumeManager.cpp
index 0f04a06..0eb72a1 100644
--- a/VolumeManager.cpp
+++ b/VolumeManager.cpp
@@ -1045,7 +1045,7 @@
VolumeManager *vm = VolumeManager::Instance();
vm->disableVolumeManager();
vm->unshareVolume(label, "ums");
- return vm->unmountVolume(label, true);
+ return vm->unmountVolume(label, true, false);
}
extern "C" int vold_getNumDirectVolumes(void) {
@@ -1087,7 +1087,7 @@
return 0;
}
-int VolumeManager::unmountVolume(const char *label, bool force) {
+int VolumeManager::unmountVolume(const char *label, bool force, bool revert) {
Volume *v = lookupVolume(label);
if (!v) {
@@ -1109,7 +1109,7 @@
cleanupAsec(v, force);
- return v->unmountVol(force);
+ return v->unmountVol(force, revert);
}
/*
diff --git a/VolumeManager.h b/VolumeManager.h
index caa0b62..a000556 100644
--- a/VolumeManager.h
+++ b/VolumeManager.h
@@ -79,7 +79,7 @@
int listVolumes(SocketClient *cli);
int mountVolume(const char *label);
- int unmountVolume(const char *label, bool force);
+ int unmountVolume(const char *label, bool force, bool revert);
int shareVolume(const char *label, const char *method);
int unshareVolume(const char *label, const char *method);
int shareEnabled(const char *path, const char *method, bool *enabled);
diff --git a/cryptfs.c b/cryptfs.c
index 50c3e64..3107e3e 100644
--- a/cryptfs.c
+++ b/cryptfs.c
@@ -845,6 +845,15 @@
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
diff --git a/cryptfs.h b/cryptfs.h
index 8b4c37b..a0693d3 100644
--- a/cryptfs.h
+++ b/cryptfs.h
@@ -81,6 +81,7 @@
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);
#ifdef __cplusplus
}
#endif