New granular encryption commands for framework.
We now have separate methods for key creation/destruction and
unlocking/locking. Key unlocking can pass through an opaque token,
but it's left empty for now.
Extend user storage setup to also create system_ce and user_de
paths. Bring over some path generation logic from installd.
Use strong type checking on user arguments.
Bug: 22358539
Change-Id: I00ba15c7b10dd682640b3f082feade4fb7cbbb5d
diff --git a/Ext4Crypt.cpp b/Ext4Crypt.cpp
index c337dbb..68aa240 100644
--- a/Ext4Crypt.cpp
+++ b/Ext4Crypt.cpp
@@ -1,5 +1,23 @@
+/*
+ * 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.
+ */
+
#include "Ext4Crypt.h"
+#include "Utils.h"
+
#include <iomanip>
#include <map>
#include <fstream>
@@ -23,11 +41,17 @@
#include "ext4_crypt_init_extensions.h"
#define LOG_TAG "Ext4Crypt"
-#include "cutils/log.h"
+
+#include <cutils/fs.h>
+#include <cutils/log.h>
#include <cutils/klog.h>
+
#include <base/file.h>
+#include <base/logging.h>
#include <base/stringprintf.h>
+using android::base::StringPrintf;
+
namespace {
// Key length in bits
const int key_length = 128;
@@ -509,18 +533,14 @@
.Set(fieldname, std::string(value)) ? 0 : -1;
}
-static std::string get_key_path(
- const char *mount_path,
- const char *user_handle)
-{
+static std::string get_key_path(const char *mount_path, userid_t user_id) {
// ext4enc:TODO get the path properly
- auto key_dir = android::base::StringPrintf("%s/misc/vold/user_keys",
- mount_path);
- if (mkdir(key_dir.c_str(), 0700) < 0 && errno != EEXIST) {
- SLOGE("Unable to create %s (%s)", key_dir.c_str(), strerror(errno));
+ auto key_dir = StringPrintf("%s/misc/vold/user_keys", mount_path);
+ if (fs_prepare_dir(key_dir.c_str(), 0700, AID_ROOT, AID_ROOT)) {
+ PLOG(ERROR) << "Failed to prepare " << key_dir;
return "";
}
- return key_dir + "/" + user_handle;
+ return StringPrintf("%s/%d", key_dir.c_str(), user_id);
}
// ext4enc:TODO this can't be the only place keys are read from /dev/urandom
@@ -562,13 +582,11 @@
return key;
}
-static int e4crypt_set_user_policy(const char *mount_path, const char *user_handle,
- const char *path, bool create_if_absent)
-{
- SLOGD("e4crypt_set_user_policy for %s", user_handle);
- auto user_key = e4crypt_get_key(
- get_key_path(mount_path, user_handle),
- create_if_absent);
+static int e4crypt_set_user_policy(const char *mount_path, userid_t user_id,
+ const char *path, bool create_if_absent) {
+ SLOGD("e4crypt_set_user_policy for %d", user_id);
+ auto user_key = e4crypt_get_key(get_key_path(mount_path, user_id),
+ create_if_absent);
if (user_key.empty()) {
return -1;
}
@@ -579,24 +597,6 @@
return do_policy_set(path, raw_ref.c_str(), raw_ref.size());
}
-int e4crypt_create_new_user_dir(const char *user_handle, const char *path) {
- SLOGD("e4crypt_create_new_user_dir(\"%s\", \"%s\")", user_handle, path);
- if (mkdir(path, S_IRWXU | S_IRWXG | S_IXOTH) < 0) {
- return -1;
- }
- if (chmod(path, S_IRWXU | S_IRWXG | S_IXOTH) < 0) {
- return -1;
- }
- if (chown(path, AID_SYSTEM, AID_SYSTEM) < 0) {
- return -1;
- }
- if (e4crypt_crypto_complete(DATA_MNT_POINT) == 0) {
- // ext4enc:TODO handle errors from this.
- e4crypt_set_user_policy(DATA_MNT_POINT, user_handle, path, true);
- }
- return 0;
-}
-
static bool is_numeric(const char *name) {
for (const char *p = name; *p != '\0'; p++) {
if (!isdigit(*p))
@@ -626,10 +626,10 @@
if (result->d_type != DT_DIR || !is_numeric(result->d_name)) {
continue; // skips user 0, which is a symlink
}
+ auto user_id = atoi(result->d_name);
auto user_dir = std::string() + dir + "/" + result->d_name;
// ext4enc:TODO don't hardcode /data
- if (e4crypt_set_user_policy("/data", result->d_name,
- user_dir.c_str(), false)) {
+ if (e4crypt_set_user_policy("/data", user_id, user_dir.c_str(), false)) {
// ext4enc:TODO If this function fails, stop the boot: we must
// deliver on promised encryption.
SLOGE("Unable to set policy on %s\n", user_dir.c_str());
@@ -638,9 +638,20 @@
return 0;
}
-int e4crypt_delete_user_key(const char *user_handle) {
- SLOGD("e4crypt_delete_user_key(\"%s\")", user_handle);
- auto key_path = get_key_path(DATA_MNT_POINT, user_handle);
+int e4crypt_create_user_key(userid_t user_id) {
+ SLOGD("e4crypt_create_user_key(%d)", user_id);
+ // TODO: create second key for user_de data
+ if (e4crypt_get_key(get_key_path(DATA_MNT_POINT, user_id), true).empty()) {
+ return -1;
+ } else {
+ return 0;
+ }
+}
+
+int e4crypt_destroy_user_key(userid_t user_id) {
+ SLOGD("e4crypt_destroy_user_key(%d)", user_id);
+ // TODO: destroy second key for user_de data
+ auto key_path = get_key_path(DATA_MNT_POINT, user_id);
auto key = e4crypt_get_key(key_path, false);
auto ext4_key = fill_key(key);
auto ref = keyname(generate_key_ref(ext4_key.raw, ext4_key.size));
@@ -669,3 +680,66 @@
// ext4enc:TODO reap the zombie
return 0;
}
+
+int e4crypt_unlock_user_key(userid_t user_id, const char* token) {
+ if (property_get_bool("vold.emulate_fbe", false)) {
+ // When in emulation mode, we just use chmod
+ if (chmod(android::vold::BuildDataSystemCePath(user_id).c_str(), 0771) ||
+ chmod(android::vold::BuildDataUserPath(nullptr, user_id).c_str(), 0771)) {
+ PLOG(ERROR) << "Failed to unlock user " << user_id;
+ return -1;
+ }
+ } else {
+ auto user_key = e4crypt_get_key(get_key_path(DATA_MNT_POINT, user_id), false);
+ if (user_key.empty()) {
+ return -1;
+ }
+ auto raw_ref = e4crypt_install_key(user_key);
+ if (raw_ref.empty()) {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int e4crypt_lock_user_key(userid_t user_id) {
+ if (property_get_bool("vold.emulate_fbe", false)) {
+ // When in emulation mode, we just use chmod
+ if (chmod(android::vold::BuildDataSystemCePath(user_id).c_str(), 0000) ||
+ chmod(android::vold::BuildDataUserPath(nullptr, user_id).c_str(), 0000)) {
+ PLOG(ERROR) << "Failed to lock user " << user_id;
+ return -1;
+ }
+ } else {
+ // TODO: remove from kernel keyring
+ }
+ return 0;
+}
+
+int e4crypt_prepare_user_storage(const char* volume_uuid, userid_t user_id) {
+ std::string system_ce_path(android::vold::BuildDataSystemCePath(user_id));
+ std::string user_ce_path(android::vold::BuildDataUserPath(volume_uuid, user_id));
+ std::string user_de_path(android::vold::BuildDataUserDePath(volume_uuid, user_id));
+
+ if (fs_prepare_dir(system_ce_path.c_str(), 0700, AID_SYSTEM, AID_SYSTEM)) {
+ PLOG(ERROR) << "Failed to prepare " << system_ce_path;
+ return -1;
+ }
+ if (fs_prepare_dir(user_ce_path.c_str(), 0771, AID_SYSTEM, AID_SYSTEM)) {
+ PLOG(ERROR) << "Failed to prepare " << user_ce_path;
+ return -1;
+ }
+ if (fs_prepare_dir(user_de_path.c_str(), 0771, AID_SYSTEM, AID_SYSTEM)) {
+ PLOG(ERROR) << "Failed to prepare " << user_de_path;
+ return -1;
+ }
+
+ if (e4crypt_crypto_complete(DATA_MNT_POINT) == 0) {
+ if (e4crypt_set_user_policy(DATA_MNT_POINT, user_id, system_ce_path.c_str(), true)
+ || e4crypt_set_user_policy(DATA_MNT_POINT, user_id, user_ce_path.c_str(), true)) {
+ return -1;
+ }
+ }
+
+ return 0;
+}