diff options
Diffstat (limited to 'ext4_utils/ext4_crypt.cpp')
-rw-r--r-- | ext4_utils/ext4_crypt.cpp | 172 |
1 files changed, 92 insertions, 80 deletions
diff --git a/ext4_utils/ext4_crypt.cpp b/ext4_utils/ext4_crypt.cpp index bb573323..7d3dc91e 100644 --- a/ext4_utils/ext4_crypt.cpp +++ b/ext4_utils/ext4_crypt.cpp @@ -1,120 +1,132 @@ -#define TAG "ext4_utils" +/* + * Copyright (c) 2015 Google, Inc. + */ -#include "ext4_crypt.h" +#define TAG "ext4_utils" -#include <string> -#include <fstream> -#include <map> +#include "ext4_crypt_init_extensions.h" +#include <dirent.h> #include <errno.h> -#include <sys/mount.h> +#include <string.h> +#include <unistd.h> + +#include <sys/xattr.h> +#include <sys/syscall.h> +#include <sys/stat.h> #include <cutils/klog.h> -#include <cutils/properties.h> #include "unencrypted_properties.h" -namespace { - std::map<std::string, std::string> s_password_store; -} - -bool e4crypt_non_default_key(const char* dir) -{ - int type = e4crypt_get_password_type(dir); +#define XATTR_NAME_ENCRYPTION_POLICY "encryption.policy" +#define EXT4_KEYREF_DELIMITER ((char)'.') - // ext4enc:TODO Use consts, not 1 here - return type != -1 && type != 1; -} +// ext4enc:TODO Include structure from somewhere sensible +// MUST be in sync with ext4_crypto.c in kernel +#define EXT4_MAX_KEY_SIZE 76 +struct ext4_encryption_key { + uint32_t mode; + char raw[EXT4_MAX_KEY_SIZE]; + uint32_t size; +}; -int e4crypt_get_password_type(const char* path) +/* Validate that all path items are available and accessible. */ +static int is_path_valid(const char *path) { - UnencryptedProperties props(path); - if (props.Get<std::string>(properties::key).empty()) { - KLOG_INFO(TAG, "No master key, so not ext4enc\n"); - return -1; + if (access(path, W_OK)) { + KLOG_ERROR(TAG, "Can't access %s: %s\n",strerror(errno), path); + return 0; } - return props.Get<int>(properties::type, 1); + return 1; } -int e4crypt_change_password(const char* path, int crypt_type, - const char* password) +/* Checks whether the policy provided is valid */ +static int is_keyref_valid(const char *keyref) { - // ext4enc:TODO Encrypt master key with password securely. Store hash of - // master key for validation - UnencryptedProperties props(path); - if ( props.Set(properties::password, password) - && props.Set(properties::type, crypt_type)) - return 0; - return -1; -} + char *period = 0; + size_t key_location_len = 0; -int e4crypt_crypto_complete(const char* path) -{ - KLOG_INFO(TAG, "ext4 crypto complete called on %s\n", path); - if (UnencryptedProperties(path).Get<std::string>(properties::key).empty()) { - KLOG_INFO(TAG, "No master key, so not ext4enc\n"); - return -1; + /* Key ref must have a key and location delimiter character. */ + period = strchr(keyref, EXT4_KEYREF_DELIMITER); + if (!period) { + return 0; } + /* period must be >= keyref. */ + key_location_len = period - keyref; + + if (strncmp(keyref, "@t", key_location_len) == 0 || + strncmp(keyref, "@p", key_location_len) == 0 || + strncmp(keyref, "@s", key_location_len) == 0 || + strncmp(keyref, "@u", key_location_len) == 0 || + strncmp(keyref, "@g", key_location_len) == 0 || + strncmp(keyref, "@us", key_location_len) == 0) + return 1; + return 0; } -int e4crypt_check_passwd(const char* path, const char* password) +static int is_dir_empty(const char *dirname) { - UnencryptedProperties props(path); - if (props.Get<std::string>(properties::key).empty()) { - KLOG_INFO(TAG, "No master key, so not ext4enc\n"); - return -1; - } - - auto actual_password = props.Get<std::string>(properties::password); - - if (actual_password == password) { - s_password_store[path] = password; - return 0; - } else { - return -1; + int n = 0; + struct dirent *d; + DIR *dir; + + dir = opendir(dirname); + while ((d = readdir(dir)) != NULL) { + if (strcmp(d->d_name, "lost+found") == 0) { + // Skip lost+found directory + } else if (++n > 2) { + break; + } } + closedir(dir); + return n <= 2; } -int e4crypt_restart(const char* path) +int do_policy_set(const char *directory, const char *policy) { - int rc = 0; + struct stat st; + ssize_t ret; - KLOG_INFO(TAG, "ext4 restart called on %s\n", path); - property_set("vold.decrypt", "trigger_reset_main"); - KLOG_INFO(TAG, "Just asked init to shut down class main\n"); - sleep(2); + if (!is_keyref_valid(policy)) { + KLOG_ERROR(TAG, "Policy has invalid format.\n"); + return -EINVAL; + } - std::string tmp_path = std::string() + path + "/tmp_mnt"; + if (!is_path_valid(directory)) { + return -EINVAL; + } - // ext4enc:TODO add retry logic - rc = umount(tmp_path.c_str()); - if (rc) { - KLOG_ERROR(TAG, "umount %s failed with rc %d, msg %s\n", - tmp_path.c_str(), rc, strerror(errno)); - return rc; + stat(directory, &st); + if (!S_ISDIR(st.st_mode)) { + KLOG_ERROR(TAG, "Can only set policy on a directory (%s)\n", directory); + return -EINVAL; } - // ext4enc:TODO add retry logic - rc = umount(path); - if (rc) { - KLOG_ERROR(TAG, "umount %s failed with rc %d, msg %s\n", - path, rc, strerror(errno)); - return rc; + if (!is_dir_empty(directory)) { + KLOG_ERROR(TAG, "Can only set policy on an empty directory (%s)\n", + directory); + return -EINVAL; } + ret = lsetxattr(directory, XATTR_NAME_ENCRYPTION_POLICY, policy, + strlen(policy), 0); + + if (ret) { + KLOG_ERROR(TAG, "Failed to set encryption policy for %s: %s\n", + directory, strerror(errno)); + return -EINVAL; + } + + KLOG_INFO(TAG, "Encryption policy for %s is set to %s\n", directory, policy); return 0; } -const char* e4crypt_get_password(const char* path) +bool e4crypt_non_default_key(const char* dir) { - // ext4enc:TODO scrub password after timeout - auto i = s_password_store.find(path); - if (i == s_password_store.end()) { - return 0; - } else { - return i->second.c_str(); - } + UnencryptedProperties props(dir); + return props.Get<int>(properties::is_default, 1) != 1; } |