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
diff --git a/Android.mk b/Android.mk
index 7263a5b..49d58c2 100644
--- a/Android.mk
+++ b/Android.mk
@@ -80,6 +80,7 @@
 
 # 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 @@
 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 @@
 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 @@
 
 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 @@
 
 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 <fstream>
 
 #include <android-base/logging.h>
@@ -54,7 +59,7 @@
     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 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 @@
     }                                                       \
 }
 
-#define ACQUIRE_LOCK std::lock_guard<std::mutex> lock(VolumeManager::Instance()->getLock());
+#define ACQUIRE_LOCK \
+    std::lock_guard<std::mutex> lock(VolumeManager::Instance()->getLock());
+
+#define ACQUIRE_CRYPT_LOCK \
+    std::lock_guard<std::mutex> lock(VolumeManager::Instance()->getCryptLock());
 
 }  // namespace
 
@@ -277,7 +294,7 @@
     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 @@
     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<std::string>& 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<std::string>& 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 @@
     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<std::string>& uuid,
+            int32_t userId, int32_t userSerial, int32_t flags);
+    binder::Status destroyUserStorage(const std::unique_ptr<std::string>& 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 @@
 
     // 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 @@
     int linkPrimary(userid_t userId);
 
     std::mutex mLock;
+    std::mutex mCryptLock;
 
     std::list<std::shared_ptr<DiskSource>> mDiskSources;
     std::list<std::shared_ptr<android::vold::Disk>> 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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
 
   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);