Ext4Crypt.cpp 29.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 * Copyright (C) 2015 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.
 */

17 18
#include "Ext4Crypt.h"

19
#include "KeyStorage.h"
20 21
#include "Utils.h"

22
#include <algorithm>
23
#include <iomanip>
24
#include <map>
25
#include <set>
26
#include <sstream>
27
#include <string>
28

29
#include <dirent.h>
30
#include <errno.h>
31
#include <fcntl.h>
32
#include <limits.h>
33
#include <openssl/sha.h>
34
#include <selinux/android.h>
35 36 37 38
#include <stdio.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/types.h>
39

40 41
#include <private/android_filesystem_config.h>

42
#include "cryptfs.h"
43
#include "ext4_crypt.h"
44
#include "key_control.h"
45

46
#define EMULATED_USES_SELINUX 0
47
#define MANAGE_MISC_DIRS 0
48

49 50
#include <cutils/fs.h>

51
#include <android-base/file.h>
52
#include <android-base/logging.h>
53
#include <android-base/stringprintf.h>
54

55
using android::base::StringPrintf;
56
using android::vold::kEmptyAuthentication;
57

58 59 60 61
// NOTE: keep in sync with StorageManager
static constexpr int FLAG_STORAGE_DE = 1 << 0;
static constexpr int FLAG_STORAGE_CE = 1 << 1;

62
namespace {
63
const std::string device_key_dir = std::string() + DATA_MNT_POINT + e4crypt_unencrypted_folder;
64 65
const std::string device_key_path = device_key_dir + "/key";
const std::string device_key_temp = device_key_dir + "/temp";
66

67 68
const std::string user_key_dir = std::string() + DATA_MNT_POINT + "/misc/vold/user_keys";
const std::string user_key_temp = user_key_dir + "/temp";
69

70
bool s_global_de_initialized = false;
71

72 73
// Some users are ephemeral, don't try to wipe their keys from disk
std::set<userid_t> s_ephemeral_users;
74

75 76 77 78 79 80
// Map user ids to key references
std::map<userid_t, std::string> s_de_key_raw_refs;
std::map<userid_t, std::string> s_ce_key_raw_refs;
// TODO abolish this map. Keys should not be long-lived in user memory, only kernel memory.
// See b/26948053
std::map<userid_t, std::string> s_ce_keys;
81

82 83
// ext4enc:TODO get this const from somewhere good
const int EXT4_KEY_DESCRIPTOR_SIZE = 8;
84

85 86 87 88 89 90 91 92 93 94
// ext4enc:TODO Include structure from somewhere sensible
// MUST be in sync with ext4_crypto.c in kernel
constexpr int EXT4_ENCRYPTION_MODE_AES_256_XTS = 1;
constexpr int EXT4_AES_256_XTS_KEY_SIZE = 64;
constexpr int EXT4_MAX_KEY_SIZE = 64;
struct ext4_encryption_key {
    uint32_t mode;
    char raw[EXT4_MAX_KEY_SIZE];
    uint32_t size;
};
95 96
}

97 98 99 100 101 102
static bool e4crypt_is_emulated() {
    return property_get_bool("persist.sys.emulate_fbe", false);
}

static const char* escape_null(const char* value) {
    return (value == nullptr) ? "null" : value;
103 104
}

105
// Get raw keyref - used to make keyname and to pass to ioctl
106
static std::string generate_key_ref(const char* key, int length) {
107 108 109 110
    SHA512_CTX c;

    SHA512_Init(&c);
    SHA512_Update(&c, key, length);
111
    unsigned char key_ref1[SHA512_DIGEST_LENGTH];
112 113 114
    SHA512_Final(key_ref1, &c);

    SHA512_Init(&c);
115 116
    SHA512_Update(&c, key_ref1, SHA512_DIGEST_LENGTH);
    unsigned char key_ref2[SHA512_DIGEST_LENGTH];
117 118
    SHA512_Final(key_ref2, &c);

119
    static_assert(EXT4_KEY_DESCRIPTOR_SIZE <= SHA512_DIGEST_LENGTH,
120
                  "Hash too short for descriptor");
121 122 123
    return std::string((char*)key_ref2, EXT4_KEY_DESCRIPTOR_SIZE);
}

124
static bool fill_key(const std::string& key, ext4_encryption_key* ext4_key) {
125 126 127 128
    if (key.size() != EXT4_AES_256_XTS_KEY_SIZE) {
        LOG(ERROR) << "Wrong size key " << key.size();
        return false;
    }
129
    static_assert(EXT4_AES_256_XTS_KEY_SIZE <= sizeof(ext4_key->raw), "Key too long!");
130 131 132 133
    ext4_key->mode = EXT4_ENCRYPTION_MODE_AES_256_XTS;
    ext4_key->size = key.size();
    memset(ext4_key->raw, 0, sizeof(ext4_key->raw));
    memcpy(ext4_key->raw, key.data(), key.size());
134
    return true;
135
}
136

137
static std::string keyname(const std::string& raw_ref) {
138
    std::ostringstream o;
139
    o << "ext4:";
140
    for (auto i : raw_ref) {
141
        o << std::hex << std::setw(2) << std::setfill('0') << (int)i;
142
    }
143 144
    return o.str();
}
145

146
// Get the keyring we store all keys in
147
static bool e4crypt_keyring(key_serial_t* device_keyring) {
148 149
    *device_keyring = keyctl_search(KEY_SPEC_SESSION_KEYRING, "keyring", "e4crypt", 0);
    if (*device_keyring == -1) {
150 151 152 153
        PLOG(ERROR) << "Unable to find device keyring";
        return false;
    }
    return true;
154
}
155

156 157
// Install password into global keyring
// Return raw key reference for use in policy
158
static bool install_key(const std::string& key, std::string* raw_ref) {
159
    ext4_encryption_key ext4_key;
160 161 162
    if (!fill_key(key, &ext4_key)) return false;
    *raw_ref = generate_key_ref(ext4_key.raw, ext4_key.size);
    auto ref = keyname(*raw_ref);
163
    key_serial_t device_keyring;
164
    if (!e4crypt_keyring(&device_keyring)) return false;
165 166
    key_serial_t key_id =
        add_key("logon", ref.c_str(), (void*)&ext4_key, sizeof(ext4_key), device_keyring);
167
    if (key_id == -1) {
168
        PLOG(ERROR) << "Failed to insert key into keyring " << device_keyring;
169
        return false;
170
    }
171 172
    LOG(DEBUG) << "Added key " << key_id << " (" << ref << ") to keyring " << device_keyring
               << " in process " << getpid();
173

174
    return true;
175 176
}

177 178 179 180
static std::string get_de_key_path(userid_t user_id) {
    return StringPrintf("%s/de/%d", user_key_dir.c_str(), user_id);
}

181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267
static std::string get_ce_key_directory_path(userid_t user_id) {
    return StringPrintf("%s/ce/%d", user_key_dir.c_str(), user_id);
}

// Returns the keys newest first
static std::vector<std::string> get_ce_key_paths(const std::string& directory_path) {
    auto dirp = std::unique_ptr<DIR, int (*)(DIR*)>(opendir(directory_path.c_str()), closedir);
    if (!dirp) {
        PLOG(ERROR) << "Unable to open ce key directory: " + directory_path;
        return std::vector<std::string>();
    }
    std::vector<std::string> result;
    for (;;) {
        errno = 0;
        auto const entry = readdir(dirp.get());
        if (!entry) {
            if (errno) {
                PLOG(ERROR) << "Unable to read ce key directory: " + directory_path;
                return std::vector<std::string>();
            }
            break;
        }
        if (entry->d_type != DT_DIR || entry->d_name[0] != 'c') {
            LOG(DEBUG) << "Skipping non-key " << entry->d_name;
            continue;
        }
        result.emplace_back(directory_path + "/" + entry->d_name);
    }
    std::sort(result.begin(), result.end());
    std::reverse(result.begin(), result.end());
    return result;
}

static std::string get_ce_key_current_path(const std::string& directory_path) {
    return directory_path + "/current";
}

static bool get_ce_key_new_path(const std::string& directory_path,
                                const std::vector<std::string>& paths,
                                std::string *ce_key_path) {
    if (paths.empty()) {
        *ce_key_path = get_ce_key_current_path(directory_path);
        return true;
    }
    for (unsigned int i = 0; i < UINT_MAX; i++) {
        auto const candidate = StringPrintf("%s/cx%010u", directory_path.c_str(), i);
        if (paths[0] < candidate) {
            *ce_key_path = candidate;
            return true;
        }
    }
    return false;
}

// Discard all keys but the named one; rename it to canonical name.
// No point in acting on errors in this; ignore them.
static void fixate_user_ce_key(const std::string& directory_path, const std::string &to_fix,
                               const std::vector<std::string>& paths) {
    for (auto const other_path: paths) {
        if (other_path != to_fix) {
            android::vold::destroyKey(other_path);
        }
    }
    auto const current_path = get_ce_key_current_path(directory_path);
    if (to_fix != current_path) {
        LOG(DEBUG) << "Renaming " << to_fix << " to " << current_path;
        if (rename(to_fix.c_str(), current_path.c_str()) != 0) {
            PLOG(WARNING) << "Unable to rename " << to_fix << " to " << current_path;
        }
    }
}

static bool read_and_fixate_user_ce_key(userid_t user_id,
                                        const android::vold::KeyAuthentication& auth,
                                        std::string *ce_key) {
    auto const directory_path = get_ce_key_directory_path(user_id);
    auto const paths = get_ce_key_paths(directory_path);
    for (auto const ce_key_path: paths) {
        LOG(DEBUG) << "Trying user CE key " << ce_key_path;
        if (android::vold::retrieveKey(ce_key_path, auth, ce_key)) {
            LOG(DEBUG) << "Successfully retrieved key";
            fixate_user_ce_key(directory_path, ce_key_path, paths);
            return true;
        }
    }
    LOG(ERROR) << "Failed to find working ce key for user " << user_id;
    return false;
268 269
}

270 271
static bool read_and_install_user_ce_key(userid_t user_id,
                                         const android::vold::KeyAuthentication& auth) {
272
    if (s_ce_key_raw_refs.count(user_id) != 0) return true;
273
    std::string ce_key;
274
    if (!read_and_fixate_user_ce_key(user_id, auth, &ce_key)) return false;
275
    std::string ce_raw_ref;
276
    if (!install_key(ce_key, &ce_raw_ref)) return false;
277 278
    s_ce_keys[user_id] = ce_key;
    s_ce_key_raw_refs[user_id] = ce_raw_ref;
279
    LOG(DEBUG) << "Installed ce key for user " << user_id;
280
    return true;
281 282
}

283
static bool prepare_dir(const std::string& dir, mode_t mode, uid_t uid, gid_t gid) {
284
    LOG(DEBUG) << "Preparing: " << dir;
285 286
    if (fs_prepare_dir(dir.c_str(), mode, uid, gid) != 0) {
        PLOG(ERROR) << "Failed to prepare " << dir;
287 288
        return false;
    }
289 290 291
    return true;
}

292 293 294 295 296 297 298 299 300
static bool destroy_dir(const std::string& dir) {
    LOG(DEBUG) << "Destroying: " << dir;
    if (rmdir(dir.c_str()) != 0 && errno != ENOENT) {
        PLOG(ERROR) << "Failed to destroy " << dir;
        return false;
    }
    return true;
}

301
static bool random_key(std::string* key) {
302
    if (android::vold::ReadRandomBytes(EXT4_AES_256_XTS_KEY_SIZE, *key) != 0) {
303 304
        // TODO status_t plays badly with PLOG, fix it.
        LOG(ERROR) << "Random read failed";
305 306
        return false;
    }
307 308 309
    return true;
}

310
static bool path_exists(const std::string& path) {
311 312 313 314 315
    return access(path.c_str(), F_OK) == 0;
}

// NB this assumes that there is only one thread listening for crypt commands, because
// it creates keys in a fixed location.
316 317
static bool store_key(const std::string& key_path, const std::string& tmp_path,
                      const android::vold::KeyAuthentication& auth, const std::string& key) {
318 319 320 321
    if (path_exists(key_path)) {
        LOG(ERROR) << "Already exists, cannot create key at: " << key_path;
        return false;
    }
322
    if (path_exists(tmp_path)) {
323
        android::vold::destroyKey(tmp_path);  // May be partially created so ignore errors
324
    }
325 326
    if (!android::vold::storeKey(tmp_path, auth, key)) return false;
    if (rename(tmp_path.c_str(), key_path.c_str()) != 0) {
327 328 329 330 331 332 333
        PLOG(ERROR) << "Unable to move new key to location: " << key_path;
        return false;
    }
    LOG(DEBUG) << "Created key " << key_path;
    return true;
}

334 335
static bool create_and_install_user_keys(userid_t user_id, bool create_ephemeral) {
    std::string de_key, ce_key;
336 337
    if (!random_key(&de_key)) return false;
    if (!random_key(&ce_key)) return false;
338
    if (create_ephemeral) {
339 340
        // If the key should be created as ephemeral, don't store it.
        s_ephemeral_users.insert(user_id);
341
    } else {
342 343 344 345 346 347 348 349 350
        auto const directory_path = get_ce_key_directory_path(user_id);
        if (!prepare_dir(directory_path, 0700, AID_ROOT, AID_ROOT)) return false;
        auto const paths = get_ce_key_paths(directory_path);
        std::string ce_key_path;
        if (!get_ce_key_new_path(directory_path, paths, &ce_key_path)) return false;
        if (!store_key(ce_key_path, user_key_temp,
                kEmptyAuthentication, ce_key)) return false;
        fixate_user_ce_key(directory_path, ce_key_path, paths);
        // Write DE key second; once this is written, all is good.
351 352
        if (!store_key(get_de_key_path(user_id), user_key_temp,
                kEmptyAuthentication, de_key)) return false;
353
    }
354
    std::string de_raw_ref;
355
    if (!install_key(de_key, &de_raw_ref)) return false;
356
    s_de_key_raw_refs[user_id] = de_raw_ref;
357
    std::string ce_raw_ref;
358
    if (!install_key(ce_key, &ce_raw_ref)) return false;
359
    s_ce_keys[user_id] = ce_key;
360
    s_ce_key_raw_refs[user_id] = ce_raw_ref;
361
    LOG(DEBUG) << "Created keys for user " << user_id;
362
    return true;
363 364
}

365 366
static bool lookup_key_ref(const std::map<userid_t, std::string>& key_map, userid_t user_id,
                           std::string* raw_ref) {
367 368 369 370 371
    auto refi = key_map.find(user_id);
    if (refi == key_map.end()) {
        LOG(ERROR) << "Cannot find key for " << user_id;
        return false;
    }
372
    *raw_ref = refi->second;
373 374 375
    return true;
}

376
static bool ensure_policy(const std::string& raw_ref, const std::string& path) {
377 378 379
    if (e4crypt_policy_ensure(path.c_str(),
                              raw_ref.data(), raw_ref.size(),
                              cryptfs_get_file_encryption_mode()) != 0) {
380 381
        LOG(ERROR) << "Failed to set policy on: " << path;
        return false;
382
    }
383
    return true;
384 385
}

386 387 388
static bool is_numeric(const char* name) {
    for (const char* p = name; *p != '\0'; p++) {
        if (!isdigit(*p)) return false;
389 390 391 392 393 394
    }
    return true;
}

static bool load_all_de_keys() {
    auto de_dir = user_key_dir + "/de";
395
    auto dirp = std::unique_ptr<DIR, int (*)(DIR*)>(opendir(de_dir.c_str()), closedir);
396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415
    if (!dirp) {
        PLOG(ERROR) << "Unable to read de key directory";
        return false;
    }
    for (;;) {
        errno = 0;
        auto entry = readdir(dirp.get());
        if (!entry) {
            if (errno) {
                PLOG(ERROR) << "Unable to read de key directory";
                return false;
            }
            break;
        }
        if (entry->d_type != DT_DIR || !is_numeric(entry->d_name)) {
            LOG(DEBUG) << "Skipping non-de-key " << entry->d_name;
            continue;
        }
        userid_t user_id = atoi(entry->d_name);
        if (s_de_key_raw_refs.count(user_id) == 0) {
416 417
            auto key_path = de_dir + "/" + entry->d_name;
            std::string key;
418
            if (!android::vold::retrieveKey(key_path, kEmptyAuthentication, &key)) return false;
419
            std::string raw_ref;
420
            if (!install_key(key, &raw_ref)) return false;
421 422 423 424 425 426 427 428 429
            s_de_key_raw_refs[user_id] = raw_ref;
            LOG(DEBUG) << "Installed de key for user " << user_id;
        }
    }
    // ext4enc:TODO: go through all DE directories, ensure that all user dirs have the
    // correct policy set on them, and that no rogue ones exist.
    return true;
}

430
bool e4crypt_initialize_global_de() {
431
    LOG(INFO) << "e4crypt_initialize_global_de";
432

433 434
    if (s_global_de_initialized) {
        LOG(INFO) << "Already initialized";
435
        return true;
436 437
    }

438 439 440 441 442 443 444
    std::string mode_filename = std::string("/data") + e4crypt_key_mode;
    std::string mode = cryptfs_get_file_encryption_mode();
    if (!android::base::WriteStringToFile(mode, mode_filename)) {
        PLOG(ERROR) << "Cannot save type";
        return false;
    }

445
    std::string device_key;
446 447
    if (path_exists(device_key_path)) {
        if (!android::vold::retrieveKey(device_key_path,
448
                kEmptyAuthentication, &device_key)) return false;
449
    } else {
450
        LOG(INFO) << "Creating new key";
451
        if (!random_key(&device_key)) return false;
452
        if (!store_key(device_key_path, device_key_temp,
453
                kEmptyAuthentication, device_key)) return false;
454 455 456
    }

    std::string device_key_ref;
457
    if (!install_key(device_key, &device_key_ref)) {
458
        LOG(ERROR) << "Failed to install device key";
459
        return false;
460 461
    }

Paul Lawrence's avatar
Paul Lawrence committed
462 463 464
    std::string ref_filename = std::string("/data") + e4crypt_key_ref;
    if (!android::base::WriteStringToFile(device_key_ref, ref_filename)) {
        PLOG(ERROR) << "Cannot save key reference";
465
        return false;
466 467
    }

468
    s_global_de_initialized = true;
469
    return true;
470 471
}

472
bool e4crypt_init_user0() {
Paul Crowley's avatar
Paul Crowley committed
473 474
    LOG(DEBUG) << "e4crypt_init_user0";
    if (e4crypt_is_native()) {
475 476 477
        if (!prepare_dir(user_key_dir, 0700, AID_ROOT, AID_ROOT)) return false;
        if (!prepare_dir(user_key_dir + "/ce", 0700, AID_ROOT, AID_ROOT)) return false;
        if (!prepare_dir(user_key_dir + "/de", 0700, AID_ROOT, AID_ROOT)) return false;
478
        if (!path_exists(get_de_key_path(0))) {
479
            if (!create_and_install_user_keys(0, false)) return false;
Paul Crowley's avatar
Paul Crowley committed
480
        }
481 482
        // TODO: switch to loading only DE_0 here once framework makes
        // explicit calls to install DE keys for secondary users
483
        if (!load_all_de_keys()) return false;
Paul Crowley's avatar
Paul Crowley committed
484
    }
485 486 487
    // We can only safely prepare DE storage here, since CE keys are probably
    // entangled with user credentials.  The framework will always prepare CE
    // storage once CE keys are installed.
488
    if (!e4crypt_prepare_user_storage(nullptr, 0, 0, FLAG_STORAGE_DE)) {
489
        LOG(ERROR) << "Failed to prepare user 0 storage";
490
        return false;
491
    }
492 493 494 495

    // If this is a non-FBE device that recently left an emulated mode,
    // restore user data directories to known-good state.
    if (!e4crypt_is_native() && !e4crypt_is_emulated()) {
496
        e4crypt_unlock_user_key(0, 0, "!", "!");
497 498
    }

499
    return true;
Paul Crowley's avatar
Paul Crowley committed
500 501
}

502
bool e4crypt_vold_create_user_key(userid_t user_id, int serial, bool ephemeral) {
503
    LOG(DEBUG) << "e4crypt_vold_create_user_key for " << user_id << " serial " << serial;
504
    if (!e4crypt_is_native()) {
505
        return true;
506
    }
507 508
    // FIXME test for existence of key that is not loaded yet
    if (s_ce_key_raw_refs.count(user_id) != 0) {
509 510
        LOG(ERROR) << "Already exists, can't e4crypt_vold_create_user_key for " << user_id
                   << " serial " << serial;
511
        // FIXME should we fail the command?
512
        return true;
513
    }
514
    if (!create_and_install_user_keys(user_id, ephemeral)) {
515
        return false;
516
    }
517
    return true;
518 519
}

520
static bool evict_key(const std::string& raw_ref) {
521
    auto ref = keyname(raw_ref);
522
    key_serial_t device_keyring;
523
    if (!e4crypt_keyring(&device_keyring)) return false;
524
    auto key_serial = keyctl_search(device_keyring, "logon", ref.c_str(), 0);
525
    if (keyctl_revoke(key_serial) != 0) {
526
        PLOG(ERROR) << "Failed to revoke key with serial " << key_serial << " ref " << ref;
527
        return false;
528
    }
529 530 531 532
    LOG(DEBUG) << "Revoked key with serial " << key_serial << " ref " << ref;
    return true;
}

533
bool e4crypt_destroy_user_key(userid_t user_id) {
534
    LOG(DEBUG) << "e4crypt_destroy_user_key(" << user_id << ")";
535
    if (!e4crypt_is_native()) {
536
        return true;
537
    }
538
    bool success = true;
539
    s_ce_keys.erase(user_id);
540
    std::string raw_ref;
541 542 543 544
    // If we haven't loaded the CE key, no need to evict it.
    if (lookup_key_ref(s_ce_key_raw_refs, user_id, &raw_ref)) {
        success &= evict_key(raw_ref);
    }
545
    s_ce_key_raw_refs.erase(user_id);
546
    success &= lookup_key_ref(s_de_key_raw_refs, user_id, &raw_ref) && evict_key(raw_ref);
547
    s_de_key_raw_refs.erase(user_id);
548 549 550
    auto it = s_ephemeral_users.find(user_id);
    if (it != s_ephemeral_users.end()) {
        s_ephemeral_users.erase(it);
551
    } else {
552 553 554
        for (auto const path: get_ce_key_paths(get_ce_key_directory_path(user_id))) {
            success &= android::vold::destroyKey(path);
        }
555
        success &= android::vold::destroyKey(get_de_key_path(user_id));
556
    }
557
    return success;
558
}
559

560
static bool emulated_lock(const std::string& path) {
561 562
    if (chmod(path.c_str(), 0000) != 0) {
        PLOG(ERROR) << "Failed to chmod " << path;
563
        return false;
564 565 566 567
    }
#if EMULATED_USES_SELINUX
    if (setfilecon(path.c_str(), "u:object_r:storage_stub_file:s0") != 0) {
        PLOG(WARNING) << "Failed to setfilecon " << path;
568
        return false;
569 570
    }
#endif
571
    return true;
572 573
}

574
static bool emulated_unlock(const std::string& path, mode_t mode) {
575 576
    if (chmod(path.c_str(), mode) != 0) {
        PLOG(ERROR) << "Failed to chmod " << path;
577
        // FIXME temporary workaround for b/26713622
578
        if (e4crypt_is_emulated()) return false;
579 580 581 582
    }
#if EMULATED_USES_SELINUX
    if (selinux_android_restorecon(path.c_str(), SELINUX_ANDROID_RESTORECON_FORCE) != 0) {
        PLOG(WARNING) << "Failed to restorecon " << path;
583
        // FIXME temporary workaround for b/26713622
584
        if (e4crypt_is_emulated()) return false;
585 586
    }
#endif
587
    return true;
588 589
}

590
static bool parse_hex(const char* hex, std::string* result) {
591
    if (strcmp("!", hex) == 0) {
592
        *result = "";
593 594
        return true;
    }
595
    if (android::vold::HexToStr(hex, *result) != 0) {
596
        LOG(ERROR) << "Invalid FBE hex string";  // Don't log the string for security reasons
597 598 599 600 601
        return false;
    }
    return true;
}

602 603 604
bool e4crypt_add_user_key_auth(userid_t user_id, int serial, const char* token_hex,
                          const char* secret_hex) {
    LOG(DEBUG) << "e4crypt_add_user_key_auth " << user_id << " serial=" << serial
605
               << " token_present=" << (strcmp(token_hex, "!") != 0);
606 607
    if (!e4crypt_is_native()) return true;
    if (s_ephemeral_users.count(user_id) != 0) return true;
608
    std::string token, secret;
609
    if (!parse_hex(token_hex, &token)) return false;
610 611 612
    if (!parse_hex(secret_hex, &secret)) return false;
    auto auth = secret.empty() ? kEmptyAuthentication
                                   : android::vold::KeyAuthentication(token, secret);
613 614 615
    auto it = s_ce_keys.find(user_id);
    if (it == s_ce_keys.end()) {
        LOG(ERROR) << "Key not loaded into memory, can't change for user " << user_id;
616
        return false;
617 618
    }
    auto ce_key = it->second;
619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636
    auto const directory_path = get_ce_key_directory_path(user_id);
    auto const paths = get_ce_key_paths(directory_path);
    std::string ce_key_path;
    if (!get_ce_key_new_path(directory_path, paths, &ce_key_path)) return false;
    if (!store_key(ce_key_path, user_key_temp, auth, ce_key)) return false;
    return true;
}

bool e4crypt_fixate_newest_user_key_auth(userid_t user_id) {
    LOG(DEBUG) << "e4crypt_fixate_newest_user_key_auth " << user_id;
    if (!e4crypt_is_native()) return true;
    auto const directory_path = get_ce_key_directory_path(user_id);
    auto const paths = get_ce_key_paths(directory_path);
    if (paths.empty()) {
        LOG(ERROR) << "No ce keys present, cannot fixate for user " << user_id;
        return false;
    }
    fixate_user_ce_key(directory_path, paths[0], paths);
637
    return true;
638 639
}

640
// TODO: rename to 'install' for consistency, and take flags to know which keys to install
641 642 643 644
bool e4crypt_unlock_user_key(userid_t user_id, int serial, const char* token_hex,
                             const char* secret_hex) {
    LOG(DEBUG) << "e4crypt_unlock_user_key " << user_id << " serial=" << serial
               << " token_present=" << (strcmp(token_hex, "!") != 0);
645
    if (e4crypt_is_native()) {
646 647
        if (s_ce_key_raw_refs.count(user_id) != 0) {
            LOG(WARNING) << "Tried to unlock already-unlocked key for user " << user_id;
648
            return true;
649 650
        }
        std::string token, secret;
651 652
        if (!parse_hex(token_hex, &token)) return false;
        if (!parse_hex(secret_hex, &secret)) return false;
653 654
        android::vold::KeyAuthentication auth(token, secret);
        if (!read_and_install_user_ce_key(user_id, auth)) {
Paul Crowley's avatar
Paul Crowley committed
655
            LOG(ERROR) << "Couldn't read key for " << user_id;
656
            return false;
657
        }
658 659 660 661
    } else {
        // When in emulation mode, we just use chmod. However, we also
        // unlock directories when not in emulation mode, to bring devices
        // back into a known-good state.
662
        if (!emulated_unlock(android::vold::BuildDataSystemCePath(user_id), 0771) ||
663
            !emulated_unlock(android::vold::BuildDataMiscCePath(user_id), 01771) ||
664 665
            !emulated_unlock(android::vold::BuildDataMediaCePath(nullptr, user_id), 0770) ||
            !emulated_unlock(android::vold::BuildDataUserCePath(nullptr, user_id), 0771)) {
666
            LOG(ERROR) << "Failed to unlock user " << user_id;
667
            return false;
668
        }
669
    }
670
    return true;
671 672
}

673
// TODO: rename to 'evict' for consistency
674
bool e4crypt_lock_user_key(userid_t user_id) {
675 676 677
    if (e4crypt_is_native()) {
        // TODO: remove from kernel keyring
    } else if (e4crypt_is_emulated()) {
678
        // When in emulation mode, we just use chmod
679
        if (!emulated_lock(android::vold::BuildDataSystemCePath(user_id)) ||
680
            !emulated_lock(android::vold::BuildDataMiscCePath(user_id)) ||
681 682
            !emulated_lock(android::vold::BuildDataMediaCePath(nullptr, user_id)) ||
            !emulated_lock(android::vold::BuildDataUserCePath(nullptr, user_id))) {
683
            LOG(ERROR) << "Failed to lock user " << user_id;
684
            return false;
685 686
        }
    }
687

688
    return true;
689 690
}

691
bool e4crypt_prepare_user_storage(const char* volume_uuid, userid_t user_id, int serial,
692
        int flags) {
693
    LOG(DEBUG) << "e4crypt_prepare_user_storage for volume " << escape_null(volume_uuid)
694
               << ", user " << user_id << ", serial " << serial << ", flags " << flags;
695 696

    if (flags & FLAG_STORAGE_DE) {
697 698 699 700 701 702 703
        // DE_sys key
        auto system_legacy_path = android::vold::BuildDataSystemLegacyPath(user_id);
        auto misc_legacy_path = android::vold::BuildDataMiscLegacyPath(user_id);
        auto profiles_de_path = android::vold::BuildDataProfilesDePath(user_id);
        auto foreign_de_path = android::vold::BuildDataProfilesForeignDexDePath(user_id);

        // DE_n key
704 705 706 707
        auto system_de_path = android::vold::BuildDataSystemDePath(user_id);
        auto misc_de_path = android::vold::BuildDataMiscDePath(user_id);
        auto user_de_path = android::vold::BuildDataUserDePath(volume_uuid, user_id);

708 709 710 711 712 713 714 715
        if (!prepare_dir(system_legacy_path, 0700, AID_SYSTEM, AID_SYSTEM)) return false;
#if MANAGE_MISC_DIRS
        if (!prepare_dir(misc_legacy_path, 0750, multiuser_get_uid(user_id, AID_SYSTEM),
                multiuser_get_uid(user_id, AID_EVERYBODY))) return false;
#endif
        if (!prepare_dir(profiles_de_path, 0771, AID_SYSTEM, AID_SYSTEM)) return false;
        if (!prepare_dir(foreign_de_path, 0773, AID_SYSTEM, AID_SYSTEM)) return false;

716 717 718
        if (!prepare_dir(system_de_path, 0770, AID_SYSTEM, AID_SYSTEM)) return false;
        if (!prepare_dir(misc_de_path, 01771, AID_SYSTEM, AID_MISC)) return false;
        if (!prepare_dir(user_de_path, 0771, AID_SYSTEM, AID_SYSTEM)) return false;
719

720 721
        // For now, FBE is only supported on internal storage
        if (e4crypt_is_native() && volume_uuid == nullptr) {
722
            std::string de_raw_ref;
723
            if (!lookup_key_ref(s_de_key_raw_refs, user_id, &de_raw_ref)) return false;
724 725 726
            if (!ensure_policy(de_raw_ref, system_de_path)) return false;
            if (!ensure_policy(de_raw_ref, misc_de_path)) return false;
            if (!ensure_policy(de_raw_ref, user_de_path)) return false;
727 728 729 730
        }
    }

    if (flags & FLAG_STORAGE_CE) {
731
        // CE_n key
732 733
        auto system_ce_path = android::vold::BuildDataSystemCePath(user_id);
        auto misc_ce_path = android::vold::BuildDataMiscCePath(user_id);
734 735
        auto media_ce_path = android::vold::BuildDataMediaCePath(volume_uuid, user_id);
        auto user_ce_path = android::vold::BuildDataUserCePath(volume_uuid, user_id);
736

737 738 739 740
        if (!prepare_dir(system_ce_path, 0770, AID_SYSTEM, AID_SYSTEM)) return false;
        if (!prepare_dir(misc_ce_path, 01771, AID_SYSTEM, AID_MISC)) return false;
        if (!prepare_dir(media_ce_path, 0770, AID_MEDIA_RW, AID_MEDIA_RW)) return false;
        if (!prepare_dir(user_ce_path, 0771, AID_SYSTEM, AID_SYSTEM)) return false;
741

742 743
        // For now, FBE is only supported on internal storage
        if (e4crypt_is_native() && volume_uuid == nullptr) {
744
            std::string ce_raw_ref;
745
            if (!lookup_key_ref(s_ce_key_raw_refs, user_id, &ce_raw_ref)) return false;
746 747 748 749
            if (!ensure_policy(ce_raw_ref, system_ce_path)) return false;
            if (!ensure_policy(ce_raw_ref, misc_ce_path)) return false;
            if (!ensure_policy(ce_raw_ref, media_ce_path)) return false;
            if (!ensure_policy(ce_raw_ref, user_ce_path)) return false;
750
        }
751 752
    }

753
    return true;
754
}
755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802

bool e4crypt_destroy_user_storage(const char* volume_uuid, userid_t user_id, int flags) {
    LOG(DEBUG) << "e4crypt_destroy_user_storage for volume " << escape_null(volume_uuid)
               << ", user " << user_id << ", flags " << flags;
    bool res = true;

    if (flags & FLAG_STORAGE_DE) {
        // DE_sys key
        auto system_legacy_path = android::vold::BuildDataSystemLegacyPath(user_id);
        auto misc_legacy_path = android::vold::BuildDataMiscLegacyPath(user_id);
        auto profiles_de_path = android::vold::BuildDataProfilesDePath(user_id);
        auto foreign_de_path = android::vold::BuildDataProfilesForeignDexDePath(user_id);

        // DE_n key
        auto system_de_path = android::vold::BuildDataSystemDePath(user_id);
        auto misc_de_path = android::vold::BuildDataMiscDePath(user_id);
        auto user_de_path = android::vold::BuildDataUserDePath(volume_uuid, user_id);

        if (volume_uuid == nullptr) {
            res &= destroy_dir(system_legacy_path);
#if MANAGE_MISC_DIRS
            res &= destroy_dir(misc_legacy_path);
#endif
            res &= destroy_dir(profiles_de_path);
            res &= destroy_dir(foreign_de_path);
            res &= destroy_dir(system_de_path);
            res &= destroy_dir(misc_de_path);
        }
        res &= destroy_dir(user_de_path);
    }

    if (flags & FLAG_STORAGE_CE) {
        // CE_n key
        auto system_ce_path = android::vold::BuildDataSystemCePath(user_id);
        auto misc_ce_path = android::vold::BuildDataMiscCePath(user_id);
        auto media_ce_path = android::vold::BuildDataMediaCePath(volume_uuid, user_id);
        auto user_ce_path = android::vold::BuildDataUserCePath(volume_uuid, user_id);

        if (volume_uuid == nullptr) {
            res &= destroy_dir(system_ce_path);
            res &= destroy_dir(misc_ce_path);
        }
        res &= destroy_dir(media_ce_path);
        res &= destroy_dir(user_ce_path);
    }

    return res;
}