On newer devices, use dm-default-key to encrypt SD cards
The dm-crypt solution requires a kernel patch that won't be present in
the GKI kernel, while the new metadata encryption system in the GKI
kernel solves this problem in a much cleaner way.
Test: create private volume on Cuttlefish, setting property both ways.
Bug: 147814592
Change-Id: Ie02bd647c38d8101af2bbc47637f65845d312cea
diff --git a/Android.bp b/Android.bp
index dae0859..9d87f68 100644
--- a/Android.bp
+++ b/Android.bp
@@ -144,6 +144,7 @@
"model/PublicVolume.cpp",
"model/StubVolume.cpp",
"model/VolumeBase.cpp",
+ "model/VolumeEncryption.cpp",
],
product_variables: {
arc: {
diff --git a/MetadataCrypt.cpp b/MetadataCrypt.cpp
index 29ce7c4..7891bee 100644
--- a/MetadataCrypt.cpp
+++ b/MetadataCrypt.cpp
@@ -186,9 +186,11 @@
static bool create_crypto_blk_dev(const std::string& dm_name, const std::string& blk_device,
const KeyBuffer& key, const CryptoOptions& options,
- std::string* crypto_blkdev) {
- uint64_t nr_sec;
- if (!get_number_of_sectors(blk_device, &nr_sec)) return false;
+ std::string* crypto_blkdev, uint64_t* nr_sec) {
+ if (!get_number_of_sectors(blk_device, nr_sec)) return false;
+ // TODO(paulcrowley): don't hardcode that DmTargetDefaultKey uses 4096-byte
+ // sectors
+ *nr_sec &= ~7;
KeyBuffer module_key;
if (options.use_hw_wrapped_key) {
@@ -207,7 +209,7 @@
}
std::string hex_key(hex_key_buffer.data(), hex_key_buffer.size());
- auto target = std::make_unique<DmTargetDefaultKey>(0, nr_sec, options.cipher.get_kernel_name(),
+ auto target = std::make_unique<DmTargetDefaultKey>(0, *nr_sec, options.cipher.get_kernel_name(),
hex_key, blk_device, 0);
if (options.is_legacy) target->SetIsLegacy();
if (options.set_dun) target->SetSetDun();
@@ -316,13 +318,13 @@
if (!read_key(data_rec->metadata_key_dir, gen, &key)) return false;
std::string crypto_blkdev;
- if (!create_crypto_blk_dev(kDmNameUserdata, data_rec->blk_device, key, options, &crypto_blkdev))
+ uint64_t nr_sec;
+ if (!create_crypto_blk_dev(kDmNameUserdata, data_rec->blk_device, key, options, &crypto_blkdev,
+ &nr_sec))
return false;
// FIXME handle the corrupt case
if (needs_encrypt) {
- uint64_t nr_sec;
- if (!get_number_of_sectors(data_rec->blk_device, &nr_sec)) return false;
LOG(INFO) << "Beginning inplace encryption, nr_sec: " << nr_sec;
off64_t size_already_done = 0;
auto rc = cryptfs_enable_inplace(crypto_blkdev.data(), blk_device.data(), nr_sec,
@@ -343,5 +345,27 @@
return true;
}
+static bool get_volume_options(CryptoOptions* options) {
+ return parse_options(android::base::GetProperty("ro.crypto.volume.metadata.encryption", ""),
+ options);
+}
+
+bool defaultkey_volume_keygen(KeyGeneration* gen) {
+ CryptoOptions options;
+ if (!get_volume_options(&options)) return false;
+ *gen = makeGen(options);
+ return true;
+}
+
+bool defaultkey_setup_ext_volume(const std::string& label, const std::string& blk_device,
+ const KeyBuffer& key, std::string* out_crypto_blkdev) {
+ LOG(DEBUG) << "defaultkey_setup_ext_volume: " << label << " " << blk_device;
+
+ CryptoOptions options;
+ if (!get_volume_options(&options)) return false;
+ uint64_t nr_sec;
+ return create_crypto_blk_dev(label, blk_device, key, options, out_crypto_blkdev, &nr_sec);
+}
+
} // namespace vold
} // namespace android
diff --git a/MetadataCrypt.h b/MetadataCrypt.h
index a1ce7d8..dc68e7c 100644
--- a/MetadataCrypt.h
+++ b/MetadataCrypt.h
@@ -19,12 +19,21 @@
#include <string>
+#include "KeyBuffer.h"
+#include "KeyUtil.h"
+
namespace android {
namespace vold {
bool fscrypt_mount_metadata_encrypted(const std::string& block_device,
const std::string& mount_point, bool needs_encrypt);
+bool defaultkey_volume_keygen(KeyGeneration* gen);
+
+bool defaultkey_setup_ext_volume(const std::string& label, const std::string& blk_device,
+ const android::vold::KeyBuffer& key,
+ std::string* out_crypto_blkdev);
+
} // namespace vold
} // namespace android
#endif
diff --git a/model/Disk.cpp b/model/Disk.cpp
index f92435d..6a6585e 100644
--- a/model/Disk.cpp
+++ b/model/Disk.cpp
@@ -16,11 +16,11 @@
#include "Disk.h"
#include "FsCrypt.h"
-#include "KeyUtil.h"
#include "PrivateVolume.h"
#include "PublicVolume.h"
#include "Utils.h"
#include "VolumeBase.h"
+#include "VolumeEncryption.h"
#include "VolumeManager.h"
#include <android-base/file.h>
@@ -31,8 +31,6 @@
#include <android-base/strings.h>
#include <fscrypt/fscrypt.h>
-#include "cryptfs.h"
-
#include <fcntl.h>
#include <inttypes.h>
#include <stdio.h>
@@ -507,7 +505,7 @@
}
KeyBuffer key;
- if (!generateStorageKey(cryptfs_get_keygen(), &key)) {
+ if (!generate_volume_key(&key)) {
LOG(ERROR) << "Failed to generate key";
return -EIO;
}
diff --git a/model/PrivateVolume.cpp b/model/PrivateVolume.cpp
index 4a0b250..fd3daea 100644
--- a/model/PrivateVolume.cpp
+++ b/model/PrivateVolume.cpp
@@ -17,8 +17,8 @@
#include "PrivateVolume.h"
#include "EmulatedVolume.h"
#include "Utils.h"
+#include "VolumeEncryption.h"
#include "VolumeManager.h"
-#include "cryptfs.h"
#include "fs/Ext4.h"
#include "fs/F2fs.h"
@@ -75,9 +75,8 @@
// TODO: figure out better SELinux labels for private volumes
- int res = cryptfs_setup_ext_volume(getId().c_str(), mRawDevPath.c_str(), mKeyRaw, &mDmDevPath);
- if (res != 0) {
- PLOG(ERROR) << getId() << " failed to setup cryptfs";
+ if (!setup_ext_volume(getId(), mRawDevPath, mKeyRaw, &mDmDevPath)) {
+ LOG(ERROR) << getId() << " failed to setup metadata encryption";
return -EIO;
}
diff --git a/model/VolumeEncryption.cpp b/model/VolumeEncryption.cpp
new file mode 100644
index 0000000..5b0e73d
--- /dev/null
+++ b/model/VolumeEncryption.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2020 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 "VolumeEncryption.h"
+
+#include <string>
+
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+
+#include "KeyBuffer.h"
+#include "KeyUtil.h"
+#include "MetadataCrypt.h"
+#include "cryptfs.h"
+
+namespace android {
+namespace vold {
+
+enum class VolumeMethod { kFailed, kCrypt, kDefaultKey };
+
+static VolumeMethod lookup_volume_method() {
+ constexpr uint64_t pre_gki_level = 29;
+ auto first_api_level =
+ android::base::GetUintProperty<uint64_t>("ro.product.first_api_level", 0);
+ auto method = android::base::GetProperty("ro.crypto.volume.metadata.method", "default");
+ if (method == "default") {
+ return first_api_level > pre_gki_level ? VolumeMethod::kDefaultKey : VolumeMethod::kCrypt;
+ } else if (method == "dm-default-key") {
+ return VolumeMethod::kDefaultKey;
+ } else if (method == "dm-crypt") {
+ if (first_api_level > pre_gki_level) {
+ LOG(ERROR) << "volume encryption method dm-crypt cannot be used, "
+ "ro.product.first_api_level = "
+ << first_api_level;
+ return VolumeMethod::kFailed;
+ }
+ return VolumeMethod::kCrypt;
+ } else {
+ LOG(ERROR) << "Unknown volume encryption method: " << method;
+ return VolumeMethod::kFailed;
+ }
+}
+
+static VolumeMethod volume_method() {
+ static VolumeMethod method = lookup_volume_method();
+ return method;
+}
+
+bool generate_volume_key(android::vold::KeyBuffer* key) {
+ KeyGeneration gen;
+ switch (volume_method()) {
+ case VolumeMethod::kFailed:
+ LOG(ERROR) << "Volume encryption setup failed";
+ return false;
+ case VolumeMethod::kCrypt:
+ gen = cryptfs_get_keygen();
+ break;
+ case VolumeMethod::kDefaultKey:
+ if (!defaultkey_volume_keygen(&gen)) return false;
+ break;
+ }
+ if (!generateStorageKey(gen, key)) return false;
+ return true;
+}
+
+bool setup_ext_volume(const std::string& label, const std::string& blk_device,
+ const android::vold::KeyBuffer& key, std::string* out_crypto_blkdev) {
+ switch (volume_method()) {
+ case VolumeMethod::kFailed:
+ LOG(ERROR) << "Volume encryption setup failed";
+ return false;
+ case VolumeMethod::kCrypt:
+ return cryptfs_setup_ext_volume(label.c_str(), blk_device.c_str(), key,
+ out_crypto_blkdev) == 0;
+ case VolumeMethod::kDefaultKey:
+ return defaultkey_setup_ext_volume(label, blk_device, key, out_crypto_blkdev);
+ }
+}
+
+} // namespace vold
+} // namespace android
diff --git a/model/VolumeEncryption.h b/model/VolumeEncryption.h
new file mode 100644
index 0000000..d06c12b
--- /dev/null
+++ b/model/VolumeEncryption.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+#include <string>
+
+#include "KeyBuffer.h"
+
+namespace android {
+namespace vold {
+
+bool generate_volume_key(android::vold::KeyBuffer* key);
+
+bool setup_ext_volume(const std::string& label, const std::string& blk_device,
+ const android::vold::KeyBuffer& key, std::string* out_crypto_blkdev);
+
+} // namespace vold
+} // namespace android