From 83b559ced41c1be0d7a65ba99e179efd79d8d257 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 12 Sep 2017 16:30:52 -0600 Subject: [PATCH] Move all crypto commands over to Binder. Prefix FDE related commands with "fde" to make it clear which devices they apply to. This will also make it easier to remove once FDE is fully deprecated in a future release. To emulate the single-threaded nature of the old socket, introduce a lock that is acquired for all encryption related methods. Sprinkle some "const" around older files to make C++ happy. Test: cts-tradefed run commandAndExit cts-dev -m CtsAppSecurityHostTestCases -t android.appsecurity.cts.DirectBootHostTest Test: cts-tradefed run commandAndExit cts-dev -m CtsAppSecurityHostTestCases -t android.appsecurity.cts.AdoptableHostTest Test: cts-tradefed run commandAndExit cts-dev -m CtsOsTestCases -t android.os.storage.cts.StorageManagerTest Bug: 13758960 Change-Id: I0a6ec6e3660bbddc61424c344ff6ac6da953ccf0 --- Android.mk | 9 +- VoldNativeService.cpp | 271 ++++++++++++++++++++++++++++++++++- VoldNativeService.h | 38 +++++ VolumeManager.h | 2 + binder/android/os/IVold.aidl | 51 +++++++ cryptfs.cpp | 8 +- cryptfs.h | 6 +- 7 files changed, 371 insertions(+), 14 deletions(-) diff --git a/Android.mk b/Android.mk index 7263a5b..49d58c2 100644 --- a/Android.mk +++ b/Android.mk @@ -80,6 +80,7 @@ common_static_libraries := \ # TODO: include "cert-err34-c" once we move to Binder # TODO: include "cert-err58-cpp" once 36656327 is fixed +common_local_tidy_enabled := true common_local_tidy_flags := -warnings-as-errors=clang-analyzer-security*,cert-* common_local_tidy_checks := -*,clang-analyzer-security*,cert-*,-cert-err34-c,-cert-err58-cpp @@ -96,7 +97,7 @@ include $(CLEAR_VARS) LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_MODULE := libvold LOCAL_CLANG := true -LOCAL_TIDY := true +LOCAL_TIDY := $(common_local_tidy_enabled) LOCAL_TIDY_FLAGS := $(common_local_tidy_flags) LOCAL_TIDY_CHECKS := $(common_local_tidy_checks) LOCAL_SRC_FILES := $(common_src_files) @@ -115,7 +116,7 @@ include $(CLEAR_VARS) LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_MODULE := vold LOCAL_CLANG := true -LOCAL_TIDY := true +LOCAL_TIDY := $(common_local_tidy_enabled) LOCAL_TIDY_FLAGS := $(common_local_tidy_flags) LOCAL_TIDY_CHECKS := $(common_local_tidy_checks) LOCAL_SRC_FILES := \ @@ -140,7 +141,7 @@ include $(CLEAR_VARS) LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_CLANG := true -LOCAL_TIDY := true +LOCAL_TIDY := $(common_local_tidy_enabled) LOCAL_TIDY_FLAGS := $(common_local_tidy_flags) LOCAL_TIDY_CHECKS := $(common_local_tidy_checks) LOCAL_SRC_FILES := vdc.cpp @@ -156,7 +157,7 @@ include $(CLEAR_VARS) LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_CLANG := true -LOCAL_TIDY := true +LOCAL_TIDY := $(common_local_tidy_enabled) LOCAL_TIDY_FLAGS := $(common_local_tidy_flags) LOCAL_TIDY_CHECKS := $(common_local_tidy_checks) LOCAL_SRC_FILES:= \ diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index 7cf45d9..374cb4c 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -17,8 +17,13 @@ #include "VoldNativeService.h" #include "VolumeManager.h" #include "MoveTask.h" +#include "Process.h" #include "TrimTask.h" +#include "cryptfs.h" +#include "Ext4Crypt.h" +#include "MetadataCrypt.h" + #include #include @@ -54,7 +59,7 @@ static binder::Status error(const std::string& msg) { return binder::Status::fromServiceSpecificError(errno, String8(msg.c_str())); } -static binder::Status translate(uint32_t status) { +static binder::Status translate(int status) { if (status == 0) { return binder::Status::ok(); } else { @@ -62,6 +67,14 @@ static binder::Status translate(uint32_t status) { } } +static binder::Status translateBool(bool status) { + if (status) { + return binder::Status::ok(); + } else { + return binder::Status::fromServiceSpecificError(status); + } +} + binder::Status checkPermission(const char* permission) { pid_t pid; uid_t uid; @@ -154,7 +167,11 @@ binder::Status checkArgumentHex(const std::string& hex) { } \ } -#define ACQUIRE_LOCK std::lock_guard lock(VolumeManager::Instance()->getLock()); +#define ACQUIRE_LOCK \ + std::lock_guard lock(VolumeManager::Instance()->getLock()); + +#define ACQUIRE_CRYPT_LOCK \ + std::lock_guard lock(VolumeManager::Instance()->getCryptLock()); } // namespace @@ -277,7 +294,7 @@ binder::Status VoldNativeService::mount(const std::string& volId, int32_t mountF vol->setMountUserId(mountUserId); int res = vol->mount(); - if (mountFlags & MOUNT_FLAG_PRIMARY) { + if ((mountFlags & MOUNT_FLAG_PRIMARY) != 0) { VolumeManager::Instance()->setPrimary(vol); } return translate(res); @@ -399,5 +416,253 @@ binder::Status VoldNativeService::unmountAppFuse(int32_t uid, int32_t pid, int32 return translate(VolumeManager::Instance()->unmountAppFuse(uid, pid, mountId)); } +binder::Status VoldNativeService::fdeCheckPassword(const std::string& password) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + return translate(cryptfs_check_passwd(password.c_str())); +} + +binder::Status VoldNativeService::fdeRestart() { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + // Spawn as thread so init can issue commands back to vold without + // causing deadlock, usually as a result of prep_data_fs. + std::thread(&cryptfs_restart).detach(); + return ok(); +} + +binder::Status VoldNativeService::fdeComplete(int32_t* _aidl_return) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + *_aidl_return = cryptfs_crypto_complete(); + return ok(); +} + +static int fdeEnableInternal(int32_t passwordType, const std::string& password, + int32_t encryptionFlags) { + bool noUi = (encryptionFlags & VoldNativeService::ENCRYPTION_FLAG_NO_UI) != 0; + + std::string how; + if ((encryptionFlags & VoldNativeService::ENCRYPTION_FLAG_IN_PLACE) != 0) { + how = "inplace"; + } else if ((encryptionFlags & VoldNativeService::ENCRYPTION_FLAG_WIPE) != 0) { + how = "wipe"; + } else { + LOG(ERROR) << "Missing encryption flag"; + return -1; + } + + for (int tries = 0; tries < 2; ++tries) { + int rc; + if (passwordType == VoldNativeService::PASSWORD_TYPE_DEFAULT) { + rc = cryptfs_enable_default(how.c_str(), noUi); + } else { + rc = cryptfs_enable(how.c_str(), passwordType, password.c_str(), noUi); + } + + if (rc == 0) { + return 0; + } else if (tries == 0) { + Process::killProcessesWithOpenFiles(DATA_MNT_POINT, SIGKILL); + } + } + + return -1; +} + +binder::Status VoldNativeService::fdeEnable(int32_t passwordType, + const std::string& password, int32_t encryptionFlags) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + if (e4crypt_is_native()) { + if (passwordType != PASSWORD_TYPE_DEFAULT) { + return error("Unexpected password type"); + } + if (encryptionFlags != (ENCRYPTION_FLAG_IN_PLACE | ENCRYPTION_FLAG_NO_UI)) { + return error("Unexpected flags"); + } + return translateBool(e4crypt_enable_crypto()); + } + + // Spawn as thread so init can issue commands back to vold without + // causing deadlock, usually as a result of prep_data_fs. + std::thread(&fdeEnableInternal, passwordType, password, encryptionFlags).detach(); + return ok(); +} + +binder::Status VoldNativeService::fdeChangePassword(int32_t passwordType, + const std::string& password) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + return translate(cryptfs_changepw(passwordType, password.c_str())); +} + +binder::Status VoldNativeService::fdeVerifyPassword(const std::string& password) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + return translate(cryptfs_verify_passwd(password.c_str())); +} + +binder::Status VoldNativeService::fdeGetField(const std::string& key, + std::string* _aidl_return) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + char buf[PROPERTY_VALUE_MAX]; + if (cryptfs_getfield(key.c_str(), buf, sizeof(buf)) != CRYPTO_GETFIELD_OK) { + return error(StringPrintf("Failed to read field %s", key.c_str())); + } else { + *_aidl_return = buf; + return ok(); + } +} + +binder::Status VoldNativeService::fdeSetField(const std::string& key, + const std::string& value) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + return translate(cryptfs_setfield(key.c_str(), value.c_str())); +} + +binder::Status VoldNativeService::fdeGetPasswordType(int32_t* _aidl_return) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + *_aidl_return = cryptfs_get_password_type(); + return ok(); +} + +binder::Status VoldNativeService::fdeGetPassword(std::string* _aidl_return) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + const char* res = cryptfs_get_password(); + if (res != nullptr) { + *_aidl_return = res; + } + return ok(); +} + +binder::Status VoldNativeService::fdeClearPassword() { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + cryptfs_clear_password(); + return ok(); +} + +binder::Status VoldNativeService::fbeEnable() { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + return translateBool(e4crypt_initialize_global_de()); +} + +binder::Status VoldNativeService::mountDefaultEncrypted() { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + if (e4crypt_is_native()) { + return translateBool(e4crypt_mount_metadata_encrypted()); + } else { + // Spawn as thread so init can issue commands back to vold without + // causing deadlock, usually as a result of prep_data_fs. + std::thread(&cryptfs_mount_default_encrypted).detach(); + return ok(); + } +} + +binder::Status VoldNativeService::initUser0() { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + return translateBool(e4crypt_init_user0()); +} + +binder::Status VoldNativeService::isConvertibleToFbe(bool* _aidl_return) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + *_aidl_return = cryptfs_isConvertibleToFBE() != 0; + return ok(); +} + +binder::Status VoldNativeService::createUserKey(int32_t userId, int32_t userSerial, + bool ephemeral) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + return translateBool(e4crypt_vold_create_user_key(userId, userSerial, ephemeral)); +} + +binder::Status VoldNativeService::destroyUserKey(int32_t userId) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + return translateBool(e4crypt_destroy_user_key(userId)); +} + +binder::Status VoldNativeService::addUserKeyAuth(int32_t userId, int32_t userSerial, + const std::string& token, const std::string& secret) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + return translateBool(e4crypt_add_user_key_auth(userId, userSerial, token.c_str(), secret.c_str())); +} + +binder::Status VoldNativeService::fixateNewestUserKeyAuth(int32_t userId) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + return translateBool(e4crypt_fixate_newest_user_key_auth(userId)); +} + +binder::Status VoldNativeService::unlockUserKey(int32_t userId, int32_t userSerial, + const std::string& token, const std::string& secret) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + return translateBool(e4crypt_unlock_user_key(userId, userSerial, token.c_str(), secret.c_str())); +} + +binder::Status VoldNativeService::lockUserKey(int32_t userId) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + return translateBool(e4crypt_lock_user_key(userId)); +} + +binder::Status VoldNativeService::prepareUserStorage(const std::unique_ptr& uuid, + int32_t userId, int32_t userSerial, int32_t flags) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + const char* uuid_ = uuid ? uuid->c_str() : nullptr; + return translateBool(e4crypt_prepare_user_storage(uuid_, userId, userSerial, flags)); +} + +binder::Status VoldNativeService::destroyUserStorage(const std::unique_ptr& uuid, + int32_t userId, int32_t flags) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + const char* uuid_ = uuid ? uuid->c_str() : nullptr; + return translateBool(e4crypt_destroy_user_storage(uuid_, userId, flags)); +} + +binder::Status VoldNativeService::secdiscard(const std::string& path) { + ENFORCE_UID(AID_SYSTEM); + ACQUIRE_CRYPT_LOCK; + + return translateBool(e4crypt_secdiscard(path.c_str())); +} + } // namespace vold } // namespace android diff --git a/VoldNativeService.h b/VoldNativeService.h index f412bfc..50244d2 100644 --- a/VoldNativeService.h +++ b/VoldNativeService.h @@ -63,6 +63,44 @@ public: binder::Status mountAppFuse(int32_t uid, int32_t pid, int32_t mountId, android::base::unique_fd* _aidl_return); binder::Status unmountAppFuse(int32_t uid, int32_t pid, int32_t mountId); + + binder::Status fdeCheckPassword(const std::string& password); + binder::Status fdeRestart(); + binder::Status fdeComplete(int32_t* _aidl_return); + binder::Status fdeEnable(int32_t passwordType, + const std::string& password, int32_t encryptionFlags); + binder::Status fdeChangePassword(int32_t passwordType, + const std::string& password); + binder::Status fdeVerifyPassword(const std::string& password); + binder::Status fdeGetField(const std::string& key, std::string* _aidl_return); + binder::Status fdeSetField(const std::string& key, const std::string& value); + binder::Status fdeGetPasswordType(int32_t* _aidl_return); + binder::Status fdeGetPassword(std::string* _aidl_return); + binder::Status fdeClearPassword(); + + binder::Status fbeEnable(); + + binder::Status mountDefaultEncrypted(); + binder::Status initUser0(); + binder::Status isConvertibleToFbe(bool* _aidl_return); + + binder::Status createUserKey(int32_t userId, int32_t userSerial, bool ephemeral); + binder::Status destroyUserKey(int32_t userId); + + binder::Status addUserKeyAuth(int32_t userId, int32_t userSerial, + const std::string& token, const std::string& secret); + binder::Status fixateNewestUserKeyAuth(int32_t userId); + + binder::Status unlockUserKey(int32_t userId, int32_t userSerial, + const std::string& token, const std::string& secret); + binder::Status lockUserKey(int32_t userId); + + binder::Status prepareUserStorage(const std::unique_ptr& uuid, + int32_t userId, int32_t userSerial, int32_t flags); + binder::Status destroyUserStorage(const std::unique_ptr& uuid, + int32_t userId, int32_t flags); + + binder::Status secdiscard(const std::string& path); }; } // namespace vold diff --git a/VolumeManager.h b/VolumeManager.h index 097ce6a..7dc69f3 100644 --- a/VolumeManager.h +++ b/VolumeManager.h @@ -94,6 +94,7 @@ public: // TODO: pipe all requests through VM to avoid exposing this lock std::mutex& getLock() { return mLock; } + std::mutex& getCryptLock() { return mCryptLock; } int start(); int stop(); @@ -218,6 +219,7 @@ private: int linkPrimary(userid_t userId); std::mutex mLock; + std::mutex mCryptLock; std::list> mDiskSources; std::list> mDisks; diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl index d945357..e8a8f2a 100644 --- a/binder/android/os/IVold.aidl +++ b/binder/android/os/IVold.aidl @@ -50,6 +50,49 @@ interface IVold { FileDescriptor mountAppFuse(int uid, int pid, int mountId); void unmountAppFuse(int uid, int pid, int mountId); + void fdeCheckPassword(@utf8InCpp String password); + void fdeRestart(); + int fdeComplete(); + void fdeEnable(int passwordType, @utf8InCpp String password, int encryptionFlags); + void fdeChangePassword(int passwordType, @utf8InCpp String password); + void fdeVerifyPassword(@utf8InCpp String password); + @utf8InCpp String fdeGetField(@utf8InCpp String key); + void fdeSetField(@utf8InCpp String key, @utf8InCpp String value); + int fdeGetPasswordType(); + @utf8InCpp String fdeGetPassword(); + void fdeClearPassword(); + + void fbeEnable(); + + void mountDefaultEncrypted(); + void initUser0(); + boolean isConvertibleToFbe(); + + void createUserKey(int userId, int userSerial, boolean ephemeral); + void destroyUserKey(int userId); + + void addUserKeyAuth(int userId, int userSerial, @utf8InCpp String token, @utf8InCpp String secret); + void fixateNewestUserKeyAuth(int userId); + + void unlockUserKey(int userId, int userSerial, @utf8InCpp String token, @utf8InCpp String secret); + void lockUserKey(int userId); + + void prepareUserStorage(@nullable @utf8InCpp String uuid, int userId, int userSerial, int storageFlags); + void destroyUserStorage(@nullable @utf8InCpp String uuid, int userId, int storageFlags); + + void secdiscard(@utf8InCpp String path); + + const int ENCRYPTION_FLAG_WIPE = 1; + const int ENCRYPTION_FLAG_IN_PLACE = 2; + const int ENCRYPTION_FLAG_NO_UI = 4; + + const int ENCRYPTION_STATE_NONE = 1; + const int ENCRYPTION_STATE_OK = 0; + const int ENCRYPTION_STATE_ERROR_UNKNOWN = -1; + const int ENCRYPTION_STATE_ERROR_INCOMPLETE = -2; + const int ENCRYPTION_STATE_ERROR_INCONSISTENT = -3; + const int ENCRYPTION_STATE_ERROR_CORRUPT = -4; + const int FSTRIM_FLAG_DEEP_TRIM = 1; const int FSTRIM_FLAG_BENCHMARK_AFTER = 2; @@ -60,6 +103,14 @@ interface IVold { const int PARTITION_TYPE_PRIVATE = 1; const int PARTITION_TYPE_MIXED = 2; + const int PASSWORD_TYPE_PASSWORD = 0; + const int PASSWORD_TYPE_DEFAULT = 1; + const int PASSWORD_TYPE_PIN = 2; + const int PASSWORD_TYPE_PATTERN = 3; + + const int STORAGE_FLAG_DE = 1; + const int STORAGE_FLAG_CE = 2; + const int REMOUNT_MODE_NONE = 0; const int REMOUNT_MODE_DEFAULT = 1; const int REMOUNT_MODE_READ = 2; diff --git a/cryptfs.cpp b/cryptfs.cpp index 764d441..adfb284 100644 --- a/cryptfs.cpp +++ b/cryptfs.cpp @@ -1813,7 +1813,7 @@ int cryptfs_check_passwd(const char *passwd) return rc; } -int cryptfs_verify_passwd(char *passwd) +int cryptfs_verify_passwd(const char *passwd) { struct crypt_mnt_ftr crypt_ftr; /* Allocate enough space for a 256 bit key, but we may use less */ @@ -2058,7 +2058,7 @@ static int cryptfs_enable_all_volumes(struct crypt_mnt_ftr *crypt_ftr, int how, return rc; } -int cryptfs_enable_internal(char *howarg, int crypt_type, const char *passwd, +int cryptfs_enable_internal(const char *howarg, int crypt_type, const char *passwd, int no_ui) { int how = 0; @@ -2417,12 +2417,12 @@ error_shutting_down: return -1; } -int cryptfs_enable(char *howarg, int type, char *passwd, int no_ui) +int cryptfs_enable(const char *howarg, int type, const char *passwd, int no_ui) { return cryptfs_enable_internal(howarg, type, passwd, no_ui); } -int cryptfs_enable_default(char *howarg, int no_ui) +int cryptfs_enable_default(const char *howarg, int no_ui) { return cryptfs_enable_internal(howarg, CRYPT_TYPE_DEFAULT, DEFAULT_PASSWORD, no_ui); diff --git a/cryptfs.h b/cryptfs.h index d20d96d..a7b650f 100644 --- a/cryptfs.h +++ b/cryptfs.h @@ -229,11 +229,11 @@ extern "C" { int cryptfs_crypto_complete(void); int cryptfs_check_passwd(const char *pw); - int cryptfs_verify_passwd(char *newpw); + int cryptfs_verify_passwd(const char *pw); int cryptfs_restart(void); - int cryptfs_enable(char *flag, int type, char *passwd, int no_ui); + int cryptfs_enable(const char *flag, int type, const char *passwd, int no_ui); int cryptfs_changepw(int type, const char *newpw); - int cryptfs_enable_default(char *flag, int no_ui); + int cryptfs_enable_default(const char *flag, int no_ui); 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);