Add support for per-user DE keys.
FBE devices need a factory reset after this change.
Bug: 26704408
Change-Id: I150b82a13a4a007d9a8997ef6a676e96576356b2
diff --git a/Ext4Crypt.cpp b/Ext4Crypt.cpp
index 5c1b921..72c79fa 100644
--- a/Ext4Crypt.cpp
+++ b/Ext4Crypt.cpp
@@ -89,6 +89,7 @@
// Some users are ephemeral, don't try to wipe their keys from disk
std::set<userid_t> s_ephemeral_users;
// 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;
// ext4enc:TODO get this const from somewhere good
@@ -549,8 +550,12 @@
.Set(fieldname, std::string(value)) ? 0 : -1;
}
+static std::string get_de_key_path(userid_t user_id) {
+ return StringPrintf("%s/de/%d", user_key_dir.c_str(), user_id);
+}
+
static std::string get_ce_key_path(userid_t user_id) {
- return StringPrintf("%s/user_%d/current", user_key_dir.c_str(), user_id);
+ return StringPrintf("%s/ce/%d/current", user_key_dir.c_str(), user_id);
}
static bool read_and_install_key(const std::string &key_path, std::string &raw_ref)
@@ -613,21 +618,26 @@
return true;
}
-static bool create_and_install_user_key(userid_t user_id, bool create_ephemeral) {
- std::string ce_key;
+static bool create_and_install_user_keys(userid_t user_id, bool create_ephemeral) {
+ std::string de_key, ce_key;
+ if (!random_key(de_key)) return false;
if (!random_key(ce_key)) return false;
if (create_ephemeral) {
// If the key should be created as ephemeral, don't store it.
s_ephemeral_users.insert(user_id);
} else {
- if (!prepare_dir(user_key_dir + "/user_" + std::to_string(user_id),
+ if (!store_key(get_de_key_path(user_id), de_key)) return false;
+ if (!prepare_dir(user_key_dir + "/ce/" + std::to_string(user_id),
0700, AID_ROOT, AID_ROOT)) return false;
if (!store_key(get_ce_key_path(user_id), ce_key)) return false;
}
+ std::string de_raw_ref;
+ if (!install_key(de_key, de_raw_ref)) return false;
+ s_de_key_raw_refs[user_id] = de_raw_ref;
std::string ce_raw_ref;
if (!install_key(ce_key, ce_raw_ref)) return false;
s_ce_key_raw_refs[user_id] = ce_raw_ref;
- LOG(DEBUG) << "Created key for user " << user_id;
+ LOG(DEBUG) << "Created keys for user " << user_id;
return true;
}
@@ -650,14 +660,66 @@
return true;
}
+static bool is_numeric(const char *name) {
+ for (const char *p = name; *p != '\0'; p++) {
+ if (!isdigit(*p))
+ return false;
+ }
+ return true;
+}
+
+static bool load_all_de_keys() {
+ auto de_dir = user_key_dir + "/de";
+ auto dirp = std::unique_ptr<DIR, int(*)(DIR*)>(opendir(de_dir.c_str()), closedir);
+ 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) {
+ std::string raw_ref;
+ if (!read_and_install_key(de_dir + "/" + entry->d_name, raw_ref)) return false;
+ 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;
+}
+
int e4crypt_init_user0() {
LOG(DEBUG) << "e4crypt_init_user0";
if (e4crypt_is_native()) {
if (!prepare_dir(user_key_dir, 0700, AID_ROOT, AID_ROOT)) return -1;
+ if (!prepare_dir(user_key_dir + "/ce", 0700, AID_ROOT, AID_ROOT)) return -1;
+ if (!prepare_dir(user_key_dir + "/de", 0700, AID_ROOT, AID_ROOT)) return -1;
+ auto de_path = get_de_key_path(0);
auto ce_path = get_ce_key_path(0);
- if (!path_exists(ce_path)) {
- if (!create_and_install_user_key(0, false)) return -1;
+ if (!path_exists(de_path) || !path_exists(ce_path)) {
+ if (path_exists(de_path)) {
+ android::vold::destroyKey(de_path); // Ignore failure
+ }
+ if (path_exists(ce_path)) {
+ android::vold::destroyKey(ce_path); // Ignore failure
+ }
+ if (!create_and_install_user_keys(0, false)) return -1;
}
+ if (!load_all_de_keys()) return -1;
}
// Ignore failures. FIXME this is horrid
// FIXME: we need an idempotent policy-setting call, which simply verifies the
@@ -679,7 +741,7 @@
// FIXME should we fail the command?
return 0;
}
- if (!create_and_install_user_key(user_id, ephemeral)) {
+ if (!create_and_install_user_keys(user_id, ephemeral)) {
return -1;
}
// TODO: create second key for user_de data
@@ -702,15 +764,16 @@
if (!e4crypt_is_native()) {
return 0;
}
- // TODO: destroy second key for user_de data
bool success = true;
std::string raw_ref;
success &= lookup_key_ref(s_ce_key_raw_refs, user_id, raw_ref) && evict_key(raw_ref);
+ success &= lookup_key_ref(s_de_key_raw_refs, user_id, raw_ref) && evict_key(raw_ref);
auto it = s_ephemeral_users.find(user_id);
if (it != s_ephemeral_users.end()) {
s_ephemeral_users.erase(it);
} else {
success &= android::vold::destroyKey(get_ce_key_path(user_id));
+ success &= android::vold::destroyKey(get_de_key_path(user_id));
}
return success ? 0 : -1;
}
@@ -803,12 +866,14 @@
if (!prepare_dir(user_de_path, 0771, AID_SYSTEM, AID_SYSTEM)) return -1;
if (e4crypt_crypto_complete(DATA_MNT_POINT) == 0) {
- std::string ce_raw_ref;
+ std::string ce_raw_ref, de_raw_ref;
if (!lookup_key_ref(s_ce_key_raw_refs, user_id, ce_raw_ref)) return -1;
+ if (!lookup_key_ref(s_de_key_raw_refs, user_id, de_raw_ref)) return -1;
if (!set_policy(ce_raw_ref, system_ce_path)) return -1;
if (!set_policy(ce_raw_ref, media_ce_path)) return -1;
if (!set_policy(ce_raw_ref, user_ce_path)) return -1;
- // ext4enc:TODO set DE policy too
+ if (!set_policy(de_raw_ref, user_de_path)) return -1;
+ // FIXME I thought there were more DE directories than this
}
return 0;