# Various instances of dereferencing a type-punned pointer in extent.c
LOCAL_CFLAGS += -fno-strict-aliasing
LOCAL_SHARED_LIBRARIES := \
+ libbase \
libcutils \
libext2_uuid \
libselinux \
# Various instances of dereferencing a type-punned pointer in extent.c
LOCAL_CFLAGS += -fno-strict-aliasing
LOCAL_STATIC_LIBRARIES := \
+ libbase \
+ liblogwrap \
libsparse_static \
libselinux \
libbase
* Copyright (c) 2015 Google, Inc.
*/
-#define TAG "ext4_utils"
-
-#include "ext4_crypt_init_extensions.h"
+#include "ext4_crypt.h"
#include <dirent.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
-#include <cutils/klog.h>
+#include <android-base/logging.h>
#define XATTR_NAME_ENCRYPTION_POLICY "encryption.policy"
#define EXT4_KEYREF_DELIMITER ((char)'.')
// ext4enc:TODO Include structure from somewhere sensible
// MUST be in sync with ext4_crypto.c in kernel
#define EXT4_KEY_DESCRIPTOR_SIZE 8
+#define EXT4_KEY_DESCRIPTOR_SIZE_HEX 17
+
struct ext4_encryption_policy {
char version;
char contents_encryption_mode;
#define EXT4_ENCRYPTION_MODE_AES_256_CTS 4
// ext4enc:TODO Get value from somewhere sensible
-#define EXT4_IOC_SET_ENCRYPTION_POLICY \
- _IOR('f', 19, struct ext4_encryption_policy)
+#define EXT4_IOC_SET_ENCRYPTION_POLICY _IOR('f', 19, struct ext4_encryption_policy)
+#define EXT4_IOC_GET_ENCRYPTION_POLICY _IOW('f', 21, struct ext4_encryption_policy)
-/* Validate that all path items are available and accessible. */
-static int is_path_valid(const char *path)
-{
- if (access(path, W_OK)) {
- KLOG_ERROR(TAG, "Can't access %s: %s\n",strerror(errno), path);
- return 0;
- }
+#define HEX_LOOKUP "0123456789abcdef"
- return 1;
+static void policy_to_hex(const char* policy, char* hex) {
+ for (size_t i = 0, j = 0; i < EXT4_KEY_DESCRIPTOR_SIZE; i++) {
+ hex[j++] = HEX_LOOKUP[(policy[i] & 0xF0) >> 4];
+ hex[j++] = HEX_LOOKUP[policy[i] & 0x0F];
+ }
+ hex[EXT4_KEY_DESCRIPTOR_SIZE_HEX - 1] = '\0';
}
static int is_dir_empty(const char *dirname)
return n <= 2;
}
-int do_policy_set(const char *directory, const char *policy, int policy_length)
-{
- struct stat st;
- ssize_t ret;
-
+int e4crypt_policy_set(const char *directory, const char *policy, size_t policy_length) {
if (policy_length != EXT4_KEY_DESCRIPTOR_SIZE) {
- KLOG_ERROR("Policy wrong length\n");
- return -EINVAL;
+ LOG(ERROR) << "Policy wrong length: " << policy_length;
+ return -1;
}
- if (!is_path_valid(directory)) {
- return -EINVAL;
+ if (access(directory, W_OK)) {
+ PLOG(ERROR) << "Failed to access directory " << directory;
+ return -1;
}
- stat(directory, &st);
- if (!S_ISDIR(st.st_mode)) {
- KLOG_ERROR(TAG, "Can only set policy on a directory (%s)\n", directory);
- return -EINVAL;
+ int fd = open(directory, O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
+ if (fd == -1) {
+ PLOG(ERROR) << "Failed to open directory " << directory;
+ return -1;
}
if (!is_dir_empty(directory)) {
- KLOG_ERROR(TAG, "Can only set policy on an empty directory (%s)\n",
- directory);
- return -EINVAL;
- }
-
- int fd = open(directory, O_DIRECTORY);
- if (fd == -1) {
- KLOG_ERROR(TAG, "Failed to open directory (%s)\n", directory);
- return -EINVAL;
+ LOG(ERROR) << "Can only set policy on an empty directory " << directory;
+ return -1;
}
ext4_encryption_policy eep;
eep.filenames_encryption_mode = EXT4_ENCRYPTION_MODE_AES_256_CTS;
eep.flags = 0;
memcpy(eep.master_key_descriptor, policy, EXT4_KEY_DESCRIPTOR_SIZE);
- ret = ioctl(fd, EXT4_IOC_SET_ENCRYPTION_POLICY, &eep);
- auto preserve_errno = errno;
- close(fd);
-
- if (ret) {
- KLOG_ERROR(TAG, "Failed to set encryption policy for %s: %s\n",
- directory, strerror(preserve_errno));
- return -EINVAL;
+ if (ioctl(fd, EXT4_IOC_SET_ENCRYPTION_POLICY, &eep)) {
+ PLOG(ERROR) << "Failed to set encryption policy for " << directory;
+ close(fd);
+ return -1;
+ } else {
+ close(fd);
}
- KLOG_INFO(TAG, "Encryption policy for %s is set to %02x%02x%02x%02x\n",
- directory, policy[0], policy[1], policy[2], policy[3]);
+ char policy_hex[EXT4_KEY_DESCRIPTOR_SIZE_HEX];
+ policy_to_hex(policy, policy_hex);
+ LOG(INFO) << "Policy for " << directory << " set to " << policy_hex;
return 0;
}
+
+int e4crypt_policy_get(const char *directory, char *policy, size_t policy_length) {
+ if (policy_length != EXT4_KEY_DESCRIPTOR_SIZE) {
+ LOG(ERROR) << "Policy wrong length: " << policy_length;
+ return -1;
+ }
+
+ if (access(directory, W_OK)) {
+ PLOG(ERROR) << "Failed to access directory " << directory;
+ return -1;
+ }
+
+ int fd = open(directory, O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
+ if (fd == -1) {
+ PLOG(ERROR) << "Failed to open directory " << directory;
+ return -1;
+ }
+
+ ext4_encryption_policy eep;
+ memset(&eep, 0, sizeof(ext4_encryption_policy));
+
+ if (ioctl(fd, EXT4_IOC_GET_ENCRYPTION_POLICY, &eep)) {
+ PLOG(WARNING) << "Failed to get encryption policy for " << directory;
+ close(fd);
+ return -1;
+ } else {
+ close(fd);
+ }
+
+ if ((eep.version == 0)
+ && (eep.contents_encryption_mode == EXT4_ENCRYPTION_MODE_AES_256_XTS)
+ && (eep.filenames_encryption_mode == EXT4_ENCRYPTION_MODE_AES_256_CTS)
+ && (eep.flags == 0)) {
+ memcpy(policy, eep.master_key_descriptor, EXT4_KEY_DESCRIPTOR_SIZE);
+ return 0;
+ }
+
+ LOG(ERROR) << "Failed to find matching encryption policy for " << directory;
+ return -1;
+}
+
+int e4crypt_policy_ensure(const char *directory, const char *policy, size_t policy_length) {
+ if (policy_length != EXT4_KEY_DESCRIPTOR_SIZE) {
+ LOG(ERROR) << "Policy wrong length: " << policy_length;
+ return -1;
+ }
+
+ char existing_policy[EXT4_KEY_DESCRIPTOR_SIZE];
+ if (e4crypt_policy_get(directory, existing_policy, EXT4_KEY_DESCRIPTOR_SIZE) == 0) {
+ char policy_hex[EXT4_KEY_DESCRIPTOR_SIZE_HEX];
+ char existing_policy_hex[EXT4_KEY_DESCRIPTOR_SIZE_HEX];
+
+ policy_to_hex(policy, policy_hex);
+ policy_to_hex(existing_policy, existing_policy_hex);
+
+ if (memcmp(policy, existing_policy, EXT4_KEY_DESCRIPTOR_SIZE) == 0) {
+ LOG(INFO) << "Found policy " << existing_policy_hex << " at " << directory
+ << " which matches expected value";
+ return 0;
+ } else {
+ LOG(ERROR) << "Found policy " << existing_policy_hex << " at " << directory
+ << " which doesn't match expected value " << policy_hex;
+ return -1;
+ }
+ }
+
+ return e4crypt_policy_set(directory, policy, policy_length);
+}
--- /dev/null
+/*
+ * Copyright (C) 2016 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 <sys/cdefs.h>
+#include <stdbool.h>
+#include <cutils/multiuser.h>
+
+__BEGIN_DECLS
+
+int e4crypt_policy_get(const char *directory, char* policy, size_t policy_length);
+int e4crypt_policy_set(const char *directory, const char* policy, size_t policy_length);
+int e4crypt_policy_ensure(const char *directory, const char* policy, size_t policy_length);
+
+static const char* e4crypt_unencrypted_folder = "/unencrypted";
+static const char* e4crypt_key_ref = "/unencrypted/ref";
+
+__END_DECLS
+/*
+ * Copyright (C) 2016 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.
+ */
+
#define TAG "ext4_utils"
#include "ext4_crypt_init_extensions.h"
+#include "ext4_crypt.h"
+
+#include <android-base/logging.h>
#include <string>
#include <vector>
#include <cutils/klog.h>
#include <cutils/properties.h>
#include <cutils/sockets.h>
-#include <poll.h>
+#include <logwrap/logwrap.h>
#include "key_control.h"
static const std::string arbitrary_sequence_number = "42";
static const int vold_command_timeout_ms = 60 * 1000;
-static std::string vold_command(std::string const& command)
-{
- KLOG_INFO(TAG, "Running command %s\n", command.c_str());
- int sock = -1;
-
- while (true) {
- sock = socket_local_client("cryptd",
- ANDROID_SOCKET_NAMESPACE_RESERVED,
- SOCK_STREAM);
- if (sock >= 0) {
- break;
- }
- usleep(10000);
- }
-
- if (sock < 0) {
- KLOG_INFO(TAG, "Cannot open vold, failing command (%s)\n", strerror(errno));
- return "";
- }
-
- class CloseSocket
- {
- int sock_;
- public:
- CloseSocket(int sock) : sock_(sock) {}
- ~CloseSocket() { close(sock_); }
- };
-
- CloseSocket cs(sock);
-
- // Use arbitrary sequence number. This should only be used when the
- // framework is down, so this is (mostly) OK.
- std::string actual_command = arbitrary_sequence_number + " " + command;
- if (write(sock, actual_command.c_str(), actual_command.size() + 1) < 0) {
- KLOG_ERROR(TAG, "Cannot write command (%s)\n", strerror(errno));
- return "";
- }
-
- struct pollfd poll_sock = {sock, POLLIN, 0};
-
- int rc = TEMP_FAILURE_RETRY(poll(&poll_sock, 1, vold_command_timeout_ms));
- if (rc < 0) {
- KLOG_ERROR(TAG, "Error in poll (%s)\n", strerror(errno));
- return "";
- }
-
- if (!(poll_sock.revents & POLLIN)) {
- KLOG_ERROR(TAG, "Timeout\n");
- return "";
- }
- char buffer[4096];
- memset(buffer, 0, sizeof(buffer));
- rc = TEMP_FAILURE_RETRY(read(sock, buffer, sizeof(buffer)));
- if (rc <= 0) {
- if (rc == 0) {
- KLOG_ERROR(TAG, "Lost connection to Vold - did it crash?\n");
- } else {
- KLOG_ERROR(TAG, "Error reading data (%s)\n", strerror(errno));
- }
- return "";
+static void kernel_logger(android::base::LogId, android::base::LogSeverity severity, const char*,
+ const char*, unsigned int, const char* message) {
+ if (severity == android::base::ERROR || severity == android::base::FATAL) {
+ KLOG_ERROR(TAG, "%s\n", message);
+ } else if (severity == android::base::WARNING) {
+ KLOG_WARNING(TAG, "%s\n", message);
+ } else {
+ KLOG_INFO(TAG, "%s\n", message);
}
+}
- // We don't truly know that this is the correct result. However,
- // since this will only be used when the framework is down,
- // it should be OK unless someone is running vdc at the same time.
- // Worst case we force a reboot in the very rare synchronization
- // error
- return std::string(buffer, rc);
+static void init_logging() {
+ android::base::SetLogger(kernel_logger);
}
int e4crypt_create_device_key(const char* dir,
int ensure_dir_exists(const char*))
{
+ init_logging();
+
// Make sure folder exists. Use make_dir to set selinux permissions.
std::string unencrypted_dir = std::string(dir) + "/unencrypted";
if (ensure_dir_exists(unencrypted_dir.c_str())) {
return -1;
}
- auto result = vold_command("cryptfs enablefilecrypto");
- // ext4enc:TODO proper error handling
- KLOG_INFO(TAG, "enablefilecrypto returned with result %s\n",
- result.c_str());
-
- return 0;
+ const char* argv[] = { "/system/bin/vdc", "--wait", "cryptfs", "enablefilecrypto" };
+ int rc = android_fork_execvp(4, (char**) argv, NULL, false, true);
+ LOG(INFO) << "enablefilecrypto result: " << rc;
+ return rc;
}
int e4crypt_install_keyring()
{
+ init_logging();
+
key_serial_t device_keyring = add_key("keyring", "e4crypt", 0, 0,
KEY_SPEC_SESSION_KEYRING);
return -1;
}
- KLOG_INFO(TAG, "Keyring created wth id %d in process %d\n",
+ KLOG_INFO(TAG, "Keyring created with id %d in process %d\n",
device_keyring, getpid());
return 0;
int e4crypt_do_init_user0()
{
- auto result = vold_command("cryptfs init_user0");
- // ext4enc:TODO proper error handling
- KLOG_INFO(TAG, "init_user0 returned with result %s\n",
- result.c_str());
- return 0;
+ init_logging();
+
+ const char* argv[] = { "/system/bin/vdc", "--wait", "cryptfs", "init_user0" };
+ int rc = android_fork_execvp(4, (char**) argv, NULL, false, true);
+ LOG(INFO) << "init_user0 result: " << rc;
+ return rc;
}
int e4crypt_set_directory_policy(const char* dir)
{
+ init_logging();
+
// Only set policy on first level /data directories
// To make this less restrictive, consider using a policy file.
// However this is overkill for as long as the policy is simply
// often because their subdirectories must be encrypted.
// This isn't a nice way to do this, see b/26641735
std::vector<std::string> directories_to_exclude = {
- "lost+found", "user", "system_ce", "media", "data", "user_de",
+ "lost+found",
+ "system_ce", "system_de",
+ "misc_ce", "misc_de",
+ "media",
+ "data", "user", "user_de",
// ext4enc:TODO workaround that must be removed b/26673855
"misc",
};
}
KLOG_INFO(TAG, "Setting policy on %s\n", dir);
- int result = do_policy_set(dir, policy.c_str(), policy.size());
+ int result = e4crypt_policy_ensure(dir, policy.c_str(), policy.size());
if (result) {
KLOG_ERROR(TAG, "Setting %02x%02x%02x%02x policy on %s failed!\n",
policy[0], policy[1], policy[2], policy[3], dir);
+/*
+ * Copyright (C) 2016 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 <sys/cdefs.h>
#include <stdbool.h>
#include <cutils/multiuser.h>
int ensure_dir_exists(const char* dir));
int e4crypt_set_directory_policy(const char* path);
int e4crypt_do_init_user0();
-int do_policy_set(const char *directory, const char *policy, int policy_length);
-
-static const char* e4crypt_unencrypted_folder = "/unencrypted";
-static const char* e4crypt_key_ref = "/unencrypted/ref";
__END_DECLS