Home | History | Annotate | Download | only in vold
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <assert.h>
     18 #include <stdlib.h>
     19 #include <sys/socket.h>
     20 #include <sys/stat.h>
     21 #include <sys/types.h>
     22 #include <netinet/in.h>
     23 #include <arpa/inet.h>
     24 #include <dirent.h>
     25 #include <errno.h>
     26 #include <fcntl.h>
     27 #include <fs_mgr.h>
     28 #include <stdio.h>
     29 #include <string.h>
     30 #include <stdint.h>
     31 #include <inttypes.h>
     32 
     33 #include <algorithm>
     34 #include <thread>
     35 
     36 #define LOG_TAG "VoldCryptCmdListener"
     37 
     38 #include <android-base/logging.h>
     39 #include <android-base/stringprintf.h>
     40 
     41 #include <cutils/fs.h>
     42 #include <cutils/log.h>
     43 #include <cutils/sockets.h>
     44 
     45 #include <sysutils/SocketClient.h>
     46 #include <private/android_filesystem_config.h>
     47 
     48 #include "CryptCommandListener.h"
     49 #include "Process.h"
     50 #include "ResponseCode.h"
     51 #include "cryptfs.h"
     52 #include "Ext4Crypt.h"
     53 #include "MetadataCrypt.h"
     54 #include "Utils.h"
     55 
     56 #define DUMP_ARGS 0
     57 
     58 CryptCommandListener::CryptCommandListener() :
     59 FrameworkListener("cryptd", true) {
     60     registerCmd(new CryptfsCmd());
     61 }
     62 
     63 #if DUMP_ARGS
     64 void CryptCommandListener::dumpArgs(int argc, char **argv, int argObscure) {
     65     char buffer[4096];
     66     char *p = buffer;
     67 
     68     memset(buffer, 0, sizeof(buffer));
     69     int i;
     70     for (i = 0; i < argc; i++) {
     71         unsigned int len = strlen(argv[i]) + 1; // Account for space
     72         if (i == argObscure) {
     73             len += 2; // Account for {}
     74         }
     75         if (((p - buffer) + len) < (sizeof(buffer)-1)) {
     76             if (i == argObscure) {
     77                 *p++ = '{';
     78                 *p++ = '}';
     79                 *p++ = ' ';
     80                 continue;
     81             }
     82             strcpy(p, argv[i]);
     83             p+= strlen(argv[i]);
     84             if (i != (argc -1)) {
     85                 *p++ = ' ';
     86             }
     87         }
     88     }
     89     SLOGD("%s", buffer);
     90 }
     91 #else
     92 void CryptCommandListener::dumpArgs(int /*argc*/, char ** /*argv*/, int /*argObscure*/) { }
     93 #endif
     94 
     95 int CryptCommandListener::sendGenericOkFailOnBool(SocketClient *cli, bool success) {
     96     if (success) {
     97         return cli->sendMsg(ResponseCode::CommandOkay, "Command succeeded", false);
     98     } else {
     99         return cli->sendMsg(ResponseCode::OperationFailed, "Command failed", false);
    100     }
    101 }
    102 
    103 CryptCommandListener::CryptfsCmd::CryptfsCmd() :
    104                  VoldCommand("cryptfs") {
    105 }
    106 
    107 static int getType(const char* type)
    108 {
    109     if (!strcmp(type, "default")) {
    110         return CRYPT_TYPE_DEFAULT;
    111     } else if (!strcmp(type, "password")) {
    112         return CRYPT_TYPE_PASSWORD;
    113     } else if (!strcmp(type, "pin")) {
    114         return CRYPT_TYPE_PIN;
    115     } else if (!strcmp(type, "pattern")) {
    116         return CRYPT_TYPE_PATTERN;
    117     } else {
    118         return -1;
    119     }
    120 }
    121 
    122 static char* parseNull(char* arg) {
    123     if (strcmp(arg, "!") == 0) {
    124         return nullptr;
    125     } else {
    126         return arg;
    127     }
    128 }
    129 
    130 static bool check_argc(SocketClient *cli, const std::string &subcommand, int argc,
    131         int expected, std::string usage) {
    132     assert(expected >= 2);
    133     if (expected == 2) {
    134         assert(usage.empty());
    135     } else {
    136         assert(!usage.empty());
    137         assert(std::count(usage.begin(), usage.end(), ' ') + 3 == expected);
    138     }
    139     if (argc == expected) {
    140         return true;
    141     }
    142     auto message = std::string() + "Usage: cryptfs " + subcommand;
    143     if (!usage.empty()) {
    144         message += " " + usage;
    145     }
    146     cli->sendMsg(ResponseCode::CommandSyntaxError, message.c_str(), false);
    147     return false;
    148 }
    149 
    150 static int do_enablecrypto(char* arg2, char* arg4, int type, bool no_ui) {
    151     int rc;
    152     int tries;
    153     for (tries = 0; tries < 2; ++tries) {
    154         if (type == CRYPT_TYPE_DEFAULT) {
    155             rc = cryptfs_enable_default(arg2, no_ui);
    156         } else {
    157             rc = cryptfs_enable(arg2, type, arg4, no_ui);
    158         }
    159 
    160         if (rc == 0) {
    161             free(arg2);
    162             free(arg4);
    163             return 0;
    164         } else if (tries == 0) {
    165             Process::killProcessesWithOpenFiles(DATA_MNT_POINT, SIGKILL);
    166         }
    167     }
    168 
    169     free(arg2);
    170     free(arg4);
    171     return -1;
    172 }
    173 
    174 int CryptCommandListener::CryptfsCmd::runCommand(SocketClient *cli,
    175                                                  int argc, char **argv) {
    176     if ((cli->getUid() != 0) && (cli->getUid() != AID_SYSTEM)) {
    177         cli->sendMsg(ResponseCode::CommandNoPermission, "No permission to run cryptfs commands", false);
    178         return 0;
    179     }
    180 
    181     if (argc < 2) {
    182         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing subcommand", false);
    183         return 0;
    184     }
    185 
    186     int rc = 0;
    187 
    188     std::string subcommand(argv[1]);
    189     if (subcommand == "checkpw") {
    190         if (!check_argc(cli, subcommand, argc, 3, "<passwd>")) return 0;
    191         dumpArgs(argc, argv, 2);
    192         rc = cryptfs_check_passwd(argv[2]);
    193     } else if (subcommand == "restart") {
    194         if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
    195         dumpArgs(argc, argv, -1);
    196 
    197         // Spawn as thread so init can issue commands back to vold without
    198         // causing deadlock, usually as a result of prep_data_fs.
    199         std::thread(&cryptfs_restart).detach();
    200     } else if (subcommand == "cryptocomplete") {
    201         if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
    202         dumpArgs(argc, argv, -1);
    203         rc = cryptfs_crypto_complete();
    204     } else if (subcommand == "enablecrypto") {
    205         if (e4crypt_is_native()) {
    206             if (argc != 5 || strcmp(argv[2], "inplace") || strcmp(argv[3], "default")
    207                     || strcmp(argv[4], "noui")) {
    208                 cli->sendMsg(ResponseCode::CommandSyntaxError,
    209                         "Usage with ext4crypt: cryptfs enablecrypto inplace default noui", false);
    210                 return 0;
    211             }
    212             return sendGenericOkFailOnBool(cli, e4crypt_enable_crypto());
    213         }
    214         const char* syntax = "Usage: cryptfs enablecrypto <wipe|inplace> "
    215                              "default|password|pin|pattern [passwd] [noui]";
    216 
    217         // This should be replaced with a command line parser if more options
    218         // are added
    219         bool valid = true;
    220         bool no_ui = false;
    221         int type = CRYPT_TYPE_DEFAULT;
    222         int options = 4; // Optional parameters are at this offset
    223         if (argc < 4) {
    224             // Minimum 4 parameters
    225             valid = false;
    226         } else if (strcmp(argv[2], "wipe") && strcmp(argv[2], "inplace") ) {
    227             // Second parameter must be wipe or inplace
    228             valid = false;
    229         } else {
    230             // Third parameter must be valid type
    231             type = getType(argv[3]);
    232             if (type == -1) {
    233                 valid = false;
    234             } else if (type != CRYPT_TYPE_DEFAULT) {
    235                 options++;
    236             }
    237         }
    238 
    239         if (valid) {
    240             if(argc < options) {
    241                 // Too few parameters
    242                 valid = false;
    243             } else if (argc == options) {
    244                 // No more, done
    245             } else if (argc == options + 1) {
    246                 // One option, must be noui
    247                 if (!strcmp(argv[options], "noui")) {
    248                     no_ui = true;
    249                 } else {
    250                     valid = false;
    251                 }
    252             } else {
    253                 // Too many options
    254                 valid = false;
    255             }
    256         }
    257 
    258         if (!valid) {
    259             cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
    260             return 0;
    261         }
    262 
    263         dumpArgs(argc, argv, 4);
    264 
    265         // Spawn as thread so init can issue commands back to vold without
    266         // causing deadlock, usually as a result of prep_data_fs.
    267         char* arg2 = argc > 2 ? strdup(argv[2]) : NULL;
    268         char* arg4 = argc > 4 ? strdup(argv[4]) : NULL;
    269         std::thread(&do_enablecrypto, arg2, arg4, type, no_ui).detach();
    270     } else if (subcommand == "enablefilecrypto") {
    271         if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
    272         dumpArgs(argc, argv, -1);
    273         rc = e4crypt_initialize_global_de();
    274     } else if (subcommand == "changepw") {
    275         const char* syntax = "Usage: cryptfs changepw "
    276                              "default|password|pin|pattern [newpasswd]";
    277         const char* password;
    278         if (argc == 3) {
    279             password = "";
    280         } else if (argc == 4) {
    281             password = argv[3];
    282         } else {
    283             cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
    284             return 0;
    285         }
    286         int type = getType(argv[2]);
    287         if (type == -1) {
    288             cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
    289             return 0;
    290         }
    291         SLOGD("cryptfs changepw %s {}", argv[2]);
    292         rc = cryptfs_changepw(type, password);
    293     } else if (subcommand == "verifypw") {
    294         if (!check_argc(cli, subcommand, argc, 3, "<passwd>")) return 0;
    295         SLOGD("cryptfs verifypw {}");
    296         rc = cryptfs_verify_passwd(argv[2]);
    297     } else if (subcommand == "getfield") {
    298         if (!check_argc(cli, subcommand, argc, 3, "<fieldname>")) return 0;
    299         char *valbuf;
    300         int valbuf_len = PROPERTY_VALUE_MAX;
    301 
    302         dumpArgs(argc, argv, -1);
    303 
    304         // Increase the buffer size until it is big enough for the field value stored.
    305         while (1) {
    306             valbuf = (char*)malloc(valbuf_len);
    307             if (valbuf == NULL) {
    308                 cli->sendMsg(ResponseCode::OperationFailed, "Failed to allocate memory", false);
    309                 return 0;
    310             }
    311             rc = cryptfs_getfield(argv[2], valbuf, valbuf_len);
    312             if (rc != CRYPTO_GETFIELD_ERROR_BUF_TOO_SMALL) {
    313                 break;
    314             }
    315             free(valbuf);
    316             valbuf_len *= 2;
    317         }
    318         if (rc == CRYPTO_GETFIELD_OK) {
    319             cli->sendMsg(ResponseCode::CryptfsGetfieldResult, valbuf, false);
    320         }
    321         free(valbuf);
    322     } else if (subcommand == "setfield") {
    323         if (!check_argc(cli, subcommand, argc, 4, "<fieldname> <value>")) return 0;
    324         dumpArgs(argc, argv, -1);
    325         rc = cryptfs_setfield(argv[2], argv[3]);
    326     } else if (subcommand == "mountdefaultencrypted") {
    327         if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
    328         SLOGD("cryptfs mountdefaultencrypted");
    329         dumpArgs(argc, argv, -1);
    330 
    331         if (e4crypt_is_native()) {
    332             return sendGenericOkFailOnBool(cli, e4crypt_mount_metadata_encrypted());
    333         }
    334         // Spawn as thread so init can issue commands back to vold without
    335         // causing deadlock, usually as a result of prep_data_fs.
    336         std::thread(&cryptfs_mount_default_encrypted).detach();
    337     } else if (subcommand == "getpwtype") {
    338         if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
    339         SLOGD("cryptfs getpwtype");
    340         dumpArgs(argc, argv, -1);
    341         switch(cryptfs_get_password_type()) {
    342         case CRYPT_TYPE_PASSWORD:
    343             cli->sendMsg(ResponseCode::PasswordTypeResult, "password", false);
    344             return 0;
    345         case CRYPT_TYPE_PATTERN:
    346             cli->sendMsg(ResponseCode::PasswordTypeResult, "pattern", false);
    347             return 0;
    348         case CRYPT_TYPE_PIN:
    349             cli->sendMsg(ResponseCode::PasswordTypeResult, "pin", false);
    350             return 0;
    351         case CRYPT_TYPE_DEFAULT:
    352             cli->sendMsg(ResponseCode::PasswordTypeResult, "default", false);
    353             return 0;
    354         default:
    355           /** @TODO better error and make sure handled by callers */
    356             cli->sendMsg(ResponseCode::OpFailedStorageNotFound, "Error", false);
    357             return 0;
    358         }
    359     } else if (subcommand == "getpw") {
    360         if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
    361         SLOGD("cryptfs getpw");
    362         dumpArgs(argc, argv, -1);
    363         const char* password = cryptfs_get_password();
    364         if (password) {
    365             char* message = 0;
    366             int size = asprintf(&message, "{{sensitive}} %s", password);
    367             if (size != -1) {
    368                 cli->sendMsg(ResponseCode::CommandOkay, message, false);
    369                 memset(message, 0, size);
    370                 free (message);
    371                 return 0;
    372             }
    373         }
    374         rc = -1;
    375     } else if (subcommand == "clearpw") {
    376         if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
    377         SLOGD("cryptfs clearpw");
    378         dumpArgs(argc, argv, -1);
    379         cryptfs_clear_password();
    380         rc = 0;
    381 
    382     } else if (subcommand == "isConvertibleToFBE") {
    383         if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
    384         // ext4enc:TODO: send a CommandSyntaxError if argv[2] not an integer
    385         SLOGD("cryptfs isConvertibleToFBE");
    386         dumpArgs(argc, argv, -1);
    387         rc = cryptfs_isConvertibleToFBE();
    388 
    389     } else if (subcommand == "init_user0") {
    390         if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
    391         return sendGenericOkFailOnBool(cli, e4crypt_init_user0());
    392 
    393     } else if (subcommand == "create_user_key") {
    394         if (!check_argc(cli, subcommand, argc, 5, "<user> <serial> <ephemeral>")) return 0;
    395         return sendGenericOkFailOnBool(cli, e4crypt_vold_create_user_key(
    396             atoi(argv[2]), atoi(argv[3]), atoi(argv[4]) != 0));
    397 
    398     } else if (subcommand == "destroy_user_key") {
    399         if (!check_argc(cli, subcommand, argc, 3, "<user>")) return 0;
    400         return sendGenericOkFailOnBool(cli, e4crypt_destroy_user_key(atoi(argv[2])));
    401 
    402     } else if (subcommand == "add_user_key_auth") {
    403         if (!check_argc(cli, subcommand, argc, 6, "<user> <serial> <token> <secret>")) return 0;
    404         return sendGenericOkFailOnBool(cli, e4crypt_add_user_key_auth(
    405             atoi(argv[2]), atoi(argv[3]), argv[4], argv[5]));
    406 
    407     } else if (subcommand == "fixate_newest_user_key_auth") {
    408         if (!check_argc(cli, subcommand, argc, 3, "<user>")) return 0;
    409         return sendGenericOkFailOnBool(cli, e4crypt_fixate_newest_user_key_auth(atoi(argv[2])));
    410 
    411     } else if (subcommand == "unlock_user_key") {
    412         if (!check_argc(cli, subcommand, argc, 6, "<user> <serial> <token> <secret>")) return 0;
    413         return sendGenericOkFailOnBool(cli, e4crypt_unlock_user_key(
    414             atoi(argv[2]), atoi(argv[3]), argv[4], argv[5]));
    415 
    416     } else if (subcommand == "lock_user_key") {
    417         if (!check_argc(cli, subcommand, argc, 3, "<user>")) return 0;
    418         return sendGenericOkFailOnBool(cli, e4crypt_lock_user_key(atoi(argv[2])));
    419 
    420     } else if (subcommand == "prepare_user_storage") {
    421         if (!check_argc(cli, subcommand, argc, 6, "<uuid> <user> <serial> <flags>")) return 0;
    422         return sendGenericOkFailOnBool(cli, e4crypt_prepare_user_storage(
    423             parseNull(argv[2]), atoi(argv[3]), atoi(argv[4]), atoi(argv[5])));
    424 
    425     } else if (subcommand == "destroy_user_storage") {
    426         if (!check_argc(cli, subcommand, argc, 5, "<uuid> <user> <flags>")) return 0;
    427         return sendGenericOkFailOnBool(cli,
    428                 e4crypt_destroy_user_storage(parseNull(argv[2]), atoi(argv[3]), atoi(argv[4])));
    429 
    430     } else if (subcommand == "secdiscard") {
    431         if (!check_argc(cli, subcommand, argc, 3, "<path>")) return 0;
    432         return sendGenericOkFailOnBool(cli,
    433                 e4crypt_secdiscard(parseNull(argv[2])));
    434 
    435     } else {
    436         dumpArgs(argc, argv, -1);
    437         cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown cryptfs subcommand", false);
    438         return 0;
    439     }
    440 
    441     // Always report that the command succeeded and return the error code.
    442     // The caller will check the return value to see what the error was.
    443     char msg[255];
    444     snprintf(msg, sizeof(msg), "%d", rc);
    445     cli->sendMsg(ResponseCode::CommandOkay, msg, false);
    446 
    447     return 0;
    448 }
    449