OSDN Git Service

Progress towards FBE and adoptable storage.
[android-x86/system-vold.git] / CryptCommandListener.cpp
index 93f953f..779338f 100644 (file)
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <assert.h>
 #include <stdlib.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
@@ -29,6 +30,9 @@
 #include <stdint.h>
 #include <inttypes.h>
 
+#include <algorithm>
+#include <thread>
+
 #define LOG_TAG "VoldCryptCmdListener"
 
 #include <android-base/logging.h>
@@ -46,6 +50,7 @@
 #include "ResponseCode.h"
 #include "cryptfs.h"
 #include "Ext4Crypt.h"
+#include "MetadataCrypt.h"
 #include "Utils.h"
 
 #define DUMP_ARGS 0
@@ -87,8 +92,8 @@ void CryptCommandListener::dumpArgs(int argc, char **argv, int argObscure) {
 void CryptCommandListener::dumpArgs(int /*argc*/, char ** /*argv*/, int /*argObscure*/) { }
 #endif
 
-int CryptCommandListener::sendGenericOkFail(SocketClient *cli, int cond) {
-    if (!cond) {
+int CryptCommandListener::sendGenericOkFailOnBool(SocketClient *cli, bool success) {
+    if (success) {
         return cli->sendMsg(ResponseCode::CommandOkay, "Command succeeded", false);
     } else {
         return cli->sendMsg(ResponseCode::OperationFailed, "Command failed", false);
@@ -122,13 +127,49 @@ static char* parseNull(char* arg) {
     }
 }
 
-#define CHECK_ARGC(expected, error) \
-    do { \
-        if (argc != (expected)) { \
-            cli->sendMsg(ResponseCode::CommandSyntaxError, ("Usage: cryptfs " error), false); \
-            return 0; \
-        } \
-    } while (0)
+static bool check_argc(SocketClient *cli, const std::string &subcommand, int argc,
+        int expected, std::string usage) {
+    assert(expected >= 2);
+    if (expected == 2) {
+        assert(usage.empty());
+    } else {
+        assert(!usage.empty());
+        assert(std::count(usage.begin(), usage.end(), ' ') + 3 == expected);
+    }
+    if (argc == expected) {
+        return true;
+    }
+    auto message = std::string() + "Usage: cryptfs " + subcommand;
+    if (!usage.empty()) {
+        message += " " + usage;
+    }
+    cli->sendMsg(ResponseCode::CommandSyntaxError, message.c_str(), false);
+    return false;
+}
+
+static int do_enablecrypto(char* arg2, char* arg4, int type, bool no_ui) {
+    int rc;
+    int tries;
+    for (tries = 0; tries < 2; ++tries) {
+        if (type == CRYPT_TYPE_DEFAULT) {
+            rc = cryptfs_enable_default(arg2, no_ui);
+        } else {
+            rc = cryptfs_enable(arg2, type, arg4, no_ui);
+        }
+
+        if (rc == 0) {
+            free(arg2);
+            free(arg4);
+            return 0;
+        } else if (tries == 0) {
+            Process::killProcessesWithOpenFiles(DATA_MNT_POINT, SIGKILL);
+        }
+    }
+
+    free(arg2);
+    free(arg4);
+    return -1;
+}
 
 int CryptCommandListener::CryptfsCmd::runCommand(SocketClient *cli,
                                                  int argc, char **argv) {
@@ -138,7 +179,7 @@ int CryptCommandListener::CryptfsCmd::runCommand(SocketClient *cli,
     }
 
     if (argc < 2) {
-        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
+        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing subcommand", false);
         return 0;
     }
 
@@ -146,18 +187,30 @@ int CryptCommandListener::CryptfsCmd::runCommand(SocketClient *cli,
 
     std::string subcommand(argv[1]);
     if (subcommand == "checkpw") {
-        CHECK_ARGC(3, "checkpw <passwd>");
+        if (!check_argc(cli, subcommand, argc, 3, "<passwd>")) return 0;
         dumpArgs(argc, argv, 2);
         rc = cryptfs_check_passwd(argv[2]);
     } else if (subcommand == "restart") {
-        CHECK_ARGC(2, "restart");
+        if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
         dumpArgs(argc, argv, -1);
-        rc = cryptfs_restart();
+
+        // 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();
     } else if (subcommand == "cryptocomplete") {
-        CHECK_ARGC(2, "cryptocomplete");
+        if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
         dumpArgs(argc, argv, -1);
         rc = cryptfs_crypto_complete();
     } else if (subcommand == "enablecrypto") {
+        if (e4crypt_is_native()) {
+            if (argc != 5 || strcmp(argv[2], "inplace") || strcmp(argv[3], "default")
+                    || strcmp(argv[4], "noui")) {
+                cli->sendMsg(ResponseCode::CommandSyntaxError,
+                        "Usage with ext4crypt: cryptfs enablecrypto inplace default noui", false);
+                return 0;
+            }
+            return sendGenericOkFailOnBool(cli, e4crypt_enable_crypto());
+        }
         const char* syntax = "Usage: cryptfs enablecrypto <wipe|inplace> "
                              "default|password|pin|pattern [passwd] [noui]";
 
@@ -202,35 +255,22 @@ int CryptCommandListener::CryptfsCmd::runCommand(SocketClient *cli,
             }
         }
 
-        if (!valid ) {
+        if (!valid) {
             cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
             return 0;
         }
 
         dumpArgs(argc, argv, 4);
 
-        int tries;
-        for (tries = 0; tries < 2; ++tries) {
-            if (type == -1) {
-                cli->sendMsg(ResponseCode::CommandSyntaxError, syntax,
-                             false);
-                return 0;
-            } else if (type == CRYPT_TYPE_DEFAULT) {
-              rc = cryptfs_enable_default(argv[2], no_ui);
-            } else {
-                rc = cryptfs_enable(argv[2], type, argv[4], no_ui);
-            }
-
-            if (rc == 0) {
-                break;
-            } else if (tries == 0) {
-                Process::killProcessesWithOpenFiles(DATA_MNT_POINT, SIGKILL);
-            }
-        }
+        // Spawn as thread so init can issue commands back to vold without
+        // causing deadlock, usually as a result of prep_data_fs.
+        char* arg2 = argc > 2 ? strdup(argv[2]) : NULL;
+        char* arg4 = argc > 4 ? strdup(argv[4]) : NULL;
+        std::thread(&do_enablecrypto, arg2, arg4, type, no_ui).detach();
     } else if (subcommand == "enablefilecrypto") {
-        CHECK_ARGC(2, "enablefilecrypto");
+        if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
         dumpArgs(argc, argv, -1);
-        rc = cryptfs_enable_file();
+        rc = e4crypt_initialize_global_de();
     } else if (subcommand == "changepw") {
         const char* syntax = "Usage: cryptfs changepw "
                              "default|password|pin|pattern [newpasswd]";
@@ -251,11 +291,11 @@ int CryptCommandListener::CryptfsCmd::runCommand(SocketClient *cli,
         SLOGD("cryptfs changepw %s {}", argv[2]);
         rc = cryptfs_changepw(type, password);
     } else if (subcommand == "verifypw") {
-        CHECK_ARGC(3, "verifypw <passwd>");
+        if (!check_argc(cli, subcommand, argc, 3, "<passwd>")) return 0;
         SLOGD("cryptfs verifypw {}");
         rc = cryptfs_verify_passwd(argv[2]);
     } else if (subcommand == "getfield") {
-        CHECK_ARGC(3, "getfield <fieldname>");
+        if (!check_argc(cli, subcommand, argc, 3, "<fieldname>")) return 0;
         char *valbuf;
         int valbuf_len = PROPERTY_VALUE_MAX;
 
@@ -280,16 +320,22 @@ int CryptCommandListener::CryptfsCmd::runCommand(SocketClient *cli,
         }
         free(valbuf);
     } else if (subcommand == "setfield") {
-        CHECK_ARGC(4, "setfield <fieldname> <value>");
+        if (!check_argc(cli, subcommand, argc, 4, "<fieldname> <value>")) return 0;
         dumpArgs(argc, argv, -1);
         rc = cryptfs_setfield(argv[2], argv[3]);
     } else if (subcommand == "mountdefaultencrypted") {
-        CHECK_ARGC(2, "mountdefaultencrypted");
+        if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
         SLOGD("cryptfs mountdefaultencrypted");
         dumpArgs(argc, argv, -1);
-        rc = cryptfs_mount_default_encrypted();
+
+        if (e4crypt_is_native()) {
+            return sendGenericOkFailOnBool(cli, e4crypt_mount_metadata_encrypted());
+        }
+        // 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();
     } else if (subcommand == "getpwtype") {
-        CHECK_ARGC(2, "getpwtype");
+        if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
         SLOGD("cryptfs getpwtype");
         dumpArgs(argc, argv, -1);
         switch(cryptfs_get_password_type()) {
@@ -311,7 +357,7 @@ int CryptCommandListener::CryptfsCmd::runCommand(SocketClient *cli,
             return 0;
         }
     } else if (subcommand == "getpw") {
-        CHECK_ARGC(2, "getpw");
+        if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
         SLOGD("cryptfs getpw");
         dumpArgs(argc, argv, -1);
         const char* password = cryptfs_get_password();
@@ -327,47 +373,64 @@ int CryptCommandListener::CryptfsCmd::runCommand(SocketClient *cli,
         }
         rc = -1;
     } else if (subcommand == "clearpw") {
-        CHECK_ARGC(2, "clearpw");
+        if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
         SLOGD("cryptfs clearpw");
         dumpArgs(argc, argv, -1);
         cryptfs_clear_password();
         rc = 0;
-    } else if (subcommand == "setusercryptopolicies") {
-        CHECK_ARGC(3, "setusercryptopolicies <path>");
-        SLOGD("cryptfs setusercryptopolicies");
-        dumpArgs(argc, argv, -1);
-        rc = e4crypt_vold_set_user_crypto_policies(argv[2]);
 
     } else if (subcommand == "isConvertibleToFBE") {
-        CHECK_ARGC(2, "isConvertibleToFBE");
+        if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
         // ext4enc:TODO: send a CommandSyntaxError if argv[2] not an integer
         SLOGD("cryptfs isConvertibleToFBE");
         dumpArgs(argc, argv, -1);
         rc = cryptfs_isConvertibleToFBE();
 
+    } else if (subcommand == "init_user0") {
+        if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
+        return sendGenericOkFailOnBool(cli, e4crypt_init_user0());
+
     } else if (subcommand == "create_user_key") {
-        CHECK_ARGC(5, "create_user_key <user> <serial> <ephemeral>");
-        return sendGenericOkFail(cli,
-                                 e4crypt_vold_create_user_key(atoi(argv[2]),
-                                                              atoi(argv[3]),
-                                                              atoi(argv[4]) != 0));
+        if (!check_argc(cli, subcommand, argc, 5, "<user> <serial> <ephemeral>")) return 0;
+        return sendGenericOkFailOnBool(cli, e4crypt_vold_create_user_key(
+            atoi(argv[2]), atoi(argv[3]), atoi(argv[4]) != 0));
 
     } else if (subcommand == "destroy_user_key") {
-        CHECK_ARGC(3, "destroy_user_key <user>");
-        return sendGenericOkFail(cli, e4crypt_destroy_user_key(atoi(argv[2])));
+        if (!check_argc(cli, subcommand, argc, 3, "<user>")) return 0;
+        return sendGenericOkFailOnBool(cli, e4crypt_destroy_user_key(atoi(argv[2])));
+
+    } else if (subcommand == "add_user_key_auth") {
+        if (!check_argc(cli, subcommand, argc, 6, "<user> <serial> <token> <secret>")) return 0;
+        return sendGenericOkFailOnBool(cli, e4crypt_add_user_key_auth(
+            atoi(argv[2]), atoi(argv[3]), argv[4], argv[5]));
+
+    } else if (subcommand == "fixate_newest_user_key_auth") {
+        if (!check_argc(cli, subcommand, argc, 3, "<user>")) return 0;
+        return sendGenericOkFailOnBool(cli, e4crypt_fixate_newest_user_key_auth(atoi(argv[2])));
 
     } else if (subcommand == "unlock_user_key") {
-        CHECK_ARGC(5, "unlock_user_key <user> <serial> <token>");
-        return sendGenericOkFail(cli, e4crypt_unlock_user_key(atoi(argv[2]), parseNull(argv[4])));
+        if (!check_argc(cli, subcommand, argc, 6, "<user> <serial> <token> <secret>")) return 0;
+        return sendGenericOkFailOnBool(cli, e4crypt_unlock_user_key(
+            atoi(argv[2]), atoi(argv[3]), argv[4], argv[5]));
 
     } else if (subcommand == "lock_user_key") {
-        CHECK_ARGC(3, "lock_user_key <user>");
-        return sendGenericOkFail(cli, e4crypt_lock_user_key(atoi(argv[2])));
+        if (!check_argc(cli, subcommand, argc, 3, "<user>")) return 0;
+        return sendGenericOkFailOnBool(cli, e4crypt_lock_user_key(atoi(argv[2])));
 
     } else if (subcommand == "prepare_user_storage") {
-        CHECK_ARGC(6, "prepare_user_storage <uuid> <user> <serial> <ephemeral>");
-        return sendGenericOkFail(cli, e4crypt_prepare_user_storage(
-                parseNull(argv[2]), atoi(argv[3]), atoi(argv[4]) != 0));
+        if (!check_argc(cli, subcommand, argc, 6, "<uuid> <user> <serial> <flags>")) return 0;
+        return sendGenericOkFailOnBool(cli, e4crypt_prepare_user_storage(
+            parseNull(argv[2]), atoi(argv[3]), atoi(argv[4]), atoi(argv[5])));
+
+    } else if (subcommand == "destroy_user_storage") {
+        if (!check_argc(cli, subcommand, argc, 5, "<uuid> <user> <flags>")) return 0;
+        return sendGenericOkFailOnBool(cli,
+                e4crypt_destroy_user_storage(parseNull(argv[2]), atoi(argv[3]), atoi(argv[4])));
+
+    } else if (subcommand == "secdiscard") {
+        if (!check_argc(cli, subcommand, argc, 3, "<path>")) return 0;
+        return sendGenericOkFailOnBool(cli,
+                e4crypt_secdiscard(parseNull(argv[2])));
 
     } else {
         dumpArgs(argc, argv, -1);