When we forget a volume, forget per-volume key

Protect all per-volume-per-user keys with a per-volume key, which is
forgotten when the volume is forgotten. This means that the user's key
is securely lost even when their storage is encrypted at forgetting
time.

Bug: 25861755
Test: create a volume, forget it, check logs and filesystem.
Change-Id: I8df77bc91bbfa2258e082ddd54d6160dbf39b378
diff --git a/Ext4Crypt.cpp b/Ext4Crypt.cpp
index 495a0fa..85ace4a 100644
--- a/Ext4Crypt.cpp
+++ b/Ext4Crypt.cpp
@@ -79,6 +79,9 @@
 const std::string user_key_temp = user_key_dir + "/temp";
 const std::string prepare_subdirs_path = "/system/bin/vold_prepare_subdirs";
 
+const std::string systemwide_volume_key_dir =
+    std::string() + DATA_MNT_POINT + "/misc/vold/volume_keys";
+
 bool s_global_de_initialized = false;
 
 // Some users are ephemeral, don't try to wipe their keys from disk
@@ -336,8 +339,8 @@
     }
 
     PolicyKeyRef device_ref;
-    if (!android::vold::retrieveAndInstallKey(true, device_key_path, device_key_temp,
-                                              &device_ref.key_raw_ref))
+    if (!android::vold::retrieveAndInstallKey(true, kEmptyAuthentication, device_key_path,
+                                              device_key_temp, &device_ref.key_raw_ref))
         return false;
     get_data_file_encryption_modes(&device_ref);
 
@@ -503,14 +506,32 @@
     return misc_path + "/vold/volume_keys/" + volume_uuid + "/default";
 }
 
+static std::string volume_secdiscardable_path(const std::string& volume_uuid) {
+    return systemwide_volume_key_dir + "/" + volume_uuid + "/secdiscardable";
+}
+
 static bool read_or_create_volkey(const std::string& misc_path, const std::string& volume_uuid,
                                   PolicyKeyRef* key_ref) {
+    auto secdiscardable_path = volume_secdiscardable_path(volume_uuid);
+    std::string secdiscardable_hash;
+    if (android::vold::pathExists(secdiscardable_path)) {
+        if (!android::vold::readSecdiscardable(secdiscardable_path, &secdiscardable_hash))
+            return false;
+    } else {
+        if (fs_mkdirs(secdiscardable_path.c_str(), 0700) != 0) {
+            PLOG(ERROR) << "Creating directories for: " << secdiscardable_path;
+            return false;
+        }
+        if (!android::vold::createSecdiscardable(secdiscardable_path, &secdiscardable_hash))
+            return false;
+    }
     auto key_path = volkey_path(misc_path, volume_uuid);
     if (fs_mkdirs(key_path.c_str(), 0700) != 0) {
         PLOG(ERROR) << "Creating directories for: " << key_path;
         return false;
     }
-    if (!android::vold::retrieveAndInstallKey(true, key_path, key_path + "_tmp",
+    android::vold::KeyAuthentication auth("", secdiscardable_hash);
+    if (!android::vold::retrieveAndInstallKey(true, auth, key_path, key_path + "_tmp",
                                               &key_ref->key_raw_ref))
         return false;
     key_ref->contents_mode =
@@ -798,6 +819,8 @@
 bool e4crypt_destroy_volume_keys(const std::string& volume_uuid) {
     bool res = true;
     LOG(DEBUG) << "e4crypt_destroy_volume_keys for volume " << escape_empty(volume_uuid);
+    auto secdiscardable_path = volume_secdiscardable_path(volume_uuid);
+    res &= android::vold::runSecdiscardSingle(secdiscardable_path);
     res &= destroy_volume_keys("/data/misc_ce", volume_uuid);
     res &= destroy_volume_keys("/data/misc_de", volume_uuid);
     return res;