From 886e572009bd09c3f2cc59d7b0e1683d76ef303c Mon Sep 17 00:00:00 2001 From: Paul Crowley Date: Fri, 7 Feb 2020 12:51:56 -0800 Subject: [PATCH] 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 --- Android.bp | 1 + MetadataCrypt.cpp | 38 ++++++++++++--- MetadataCrypt.h | 9 ++++ model/Disk.cpp | 6 +-- model/PrivateVolume.cpp | 7 ++- model/VolumeEncryption.cpp | 94 ++++++++++++++++++++++++++++++++++++++ model/VolumeEncryption.h | 32 +++++++++++++ 7 files changed, 172 insertions(+), 15 deletions(-) create mode 100644 model/VolumeEncryption.cpp create mode 100644 model/VolumeEncryption.h diff --git a/Android.bp b/Android.bp index dae0859..9d87f68 100644 --- a/Android.bp +++ b/Android.bp @@ -144,6 +144,7 @@ cc_library_static { "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 get_number_of_sectors(const std::string& real_blkdev, uint64_t* nr_s 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 @@ static bool create_crypto_blk_dev(const std::string& dm_name, const std::string& } std::string hex_key(hex_key_buffer.data(), hex_key_buffer.size()); - auto target = std::make_unique(0, nr_sec, options.cipher.get_kernel_name(), + auto target = std::make_unique(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 @@ bool fscrypt_mount_metadata_encrypted(const std::string& blk_device, const std:: 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 @@ bool fscrypt_mount_metadata_encrypted(const std::string& blk_device, const std:: 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 +#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 @@ -31,8 +31,6 @@ #include #include -#include "cryptfs.h" - #include #include #include @@ -507,7 +505,7 @@ status_t Disk::partitionMixed(int8_t ratio) { } 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 @@ status_t PrivateVolume::doCreate() { // 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 + +#include +#include + +#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("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 + +#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