summaryrefslogtreecommitdiff
path: root/libfscrypt
diff options
context:
space:
mode:
Diffstat (limited to 'libfscrypt')
l---------libfscrypt/.clang-format1
-rw-r--r--libfscrypt/Android.bp1
-rw-r--r--libfscrypt/fscrypt.cpp427
-rw-r--r--libfscrypt/fscrypt_init_extensions.cpp146
-rw-r--r--libfscrypt/include/fscrypt/fscrypt.h41
-rw-r--r--libfscrypt/include/fscrypt/fscrypt_init_extensions.h33
-rw-r--r--libfscrypt/tests/Android.bp33
-rw-r--r--libfscrypt/tests/fscrypt_test.cpp138
8 files changed, 376 insertions, 444 deletions
diff --git a/libfscrypt/.clang-format b/libfscrypt/.clang-format
deleted file mode 120000
index 973b2fab..00000000
--- a/libfscrypt/.clang-format
+++ /dev/null
@@ -1 +0,0 @@
-../../../build/soong/scripts/system-clang-format \ No newline at end of file
diff --git a/libfscrypt/Android.bp b/libfscrypt/Android.bp
index 65b94ed9..cca38235 100644
--- a/libfscrypt/Android.bp
+++ b/libfscrypt/Android.bp
@@ -5,6 +5,7 @@ cc_library {
recovery_available: true,
srcs: [
"fscrypt.cpp",
+ "fscrypt_init_extensions.cpp",
],
export_include_dirs: ["include"],
shared_libs: [
diff --git a/libfscrypt/fscrypt.cpp b/libfscrypt/fscrypt.cpp
index b76f0b17..adeb66aa 100644
--- a/libfscrypt/fscrypt.cpp
+++ b/libfscrypt/fscrypt.cpp
@@ -16,101 +16,42 @@
#include "fscrypt/fscrypt.h"
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/strings.h>
-#include <android-base/unique_fd.h>
+#include <array>
+
#include <asm/ioctl.h>
-#include <cutils/properties.h>
+#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <linux/fs.h>
-#include <logwrap/logwrap.h>
#include <string.h>
#include <sys/stat.h>
+#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
-#include <utils/misc.h>
-
-#include <array>
-#include <string>
-#include <vector>
-
-using namespace std::string_literals;
-
-// TODO: switch to <linux/fscrypt.h> once it's in Bionic
-#ifndef FSCRYPT_POLICY_V1
-// Careful: due to an API quirk this is actually 0, not 1. We use 1 everywhere
-// else, so make sure to only use this constant in the ioctl itself.
-#define FSCRYPT_POLICY_V1 0
-#define FSCRYPT_KEY_DESCRIPTOR_SIZE 8
-struct fscrypt_policy_v1 {
- __u8 version;
- __u8 contents_encryption_mode;
- __u8 filenames_encryption_mode;
- __u8 flags;
- __u8 master_key_descriptor[FSCRYPT_KEY_DESCRIPTOR_SIZE];
-};
-
-#define FSCRYPT_POLICY_V2 2
-#define FSCRYPT_KEY_IDENTIFIER_SIZE 16
-struct fscrypt_policy_v2 {
- __u8 version;
- __u8 contents_encryption_mode;
- __u8 filenames_encryption_mode;
- __u8 flags;
- __u8 __reserved[4];
- __u8 master_key_identifier[FSCRYPT_KEY_IDENTIFIER_SIZE];
-};
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <cutils/properties.h>
+#include <logwrap/logwrap.h>
+#include <utils/misc.h>
-#endif /* FSCRYPT_POLICY_V1 */
+#define FS_KEY_DESCRIPTOR_SIZE_HEX (2 * FS_KEY_DESCRIPTOR_SIZE + 1)
/* modes not supported by upstream kernel, so not in <linux/fs.h> */
#define FS_ENCRYPTION_MODE_AES_256_HEH 126
#define FS_ENCRYPTION_MODE_PRIVATE 127
-#define HEX_LOOKUP "0123456789abcdef"
-
-struct ModeLookupEntry {
- std::string name;
- int id;
-};
-
-static const auto contents_modes = std::vector<ModeLookupEntry>{
- {"aes-256-xts"s, FS_ENCRYPTION_MODE_AES_256_XTS},
- {"software"s, FS_ENCRYPTION_MODE_AES_256_XTS},
- {"adiantum"s, FS_ENCRYPTION_MODE_ADIANTUM},
- {"ice"s, FS_ENCRYPTION_MODE_PRIVATE},
-};
+/* new definition, not yet in Bionic's <linux/fs.h> */
+#ifndef FS_ENCRYPTION_MODE_ADIANTUM
+#define FS_ENCRYPTION_MODE_ADIANTUM 9
+#endif
-static const auto filenames_modes = std::vector<ModeLookupEntry>{
- {"aes-256-cts"s, FS_ENCRYPTION_MODE_AES_256_CTS},
- {"aes-256-heh"s, FS_ENCRYPTION_MODE_AES_256_HEH},
- {"adiantum"s, FS_ENCRYPTION_MODE_ADIANTUM},
-};
-
-static bool LookupModeByName(const std::vector<struct ModeLookupEntry>& modes,
- const std::string& name, int* result) {
- for (const auto& e : modes) {
- if (e.name == name) {
- *result = e.id;
- return true;
- }
- }
- return false;
-}
+/* new definition, not yet in Bionic's <linux/fs.h> */
+#ifndef FS_POLICY_FLAG_DIRECT_KEY
+#define FS_POLICY_FLAG_DIRECT_KEY 0x4
+#endif
-static bool LookupModeById(const std::vector<struct ModeLookupEntry>& modes, int id,
- std::string* result) {
- for (const auto& e : modes) {
- if (e.id == id) {
- *result = e.name;
- return true;
- }
- }
- return false;
-}
+#define HEX_LOOKUP "0123456789abcdef"
bool fscrypt_is_native() {
char value[PROPERTY_VALUE_MAX];
@@ -118,14 +59,11 @@ bool fscrypt_is_native() {
return !strcmp(value, "file");
}
-namespace android {
-namespace fscrypt {
-
static void log_ls(const char* dirname) {
std::array<const char*, 3> argv = {"ls", "-laZ", dirname};
int status = 0;
auto res =
- logwrap_fork_execvp(argv.size(), argv.data(), &status, false, LOG_ALOG, false, nullptr);
+ android_fork_execvp(argv.size(), const_cast<char**>(argv.data()), &status, false, true);
if (res != 0) {
PLOG(ERROR) << argv[0] << " " << argv[1] << " " << argv[2] << "failed";
return;
@@ -142,197 +80,204 @@ static void log_ls(const char* dirname) {
}
}
-void BytesToHex(const std::string& bytes, std::string* hex) {
- hex->clear();
- for (char c : bytes) {
- *hex += HEX_LOOKUP[(c & 0xF0) >> 4];
- *hex += HEX_LOOKUP[c & 0x0F];
+static void policy_to_hex(const char* policy, char* hex) {
+ for (size_t i = 0, j = 0; i < FS_KEY_DESCRIPTOR_SIZE; i++) {
+ hex[j++] = HEX_LOOKUP[(policy[i] & 0xF0) >> 4];
+ hex[j++] = HEX_LOOKUP[policy[i] & 0x0F];
}
+ hex[FS_KEY_DESCRIPTOR_SIZE_HEX - 1] = '\0';
}
-static bool fscrypt_is_encrypted(int fd) {
- fscrypt_policy_v1 policy;
-
- // success => encrypted with v1 policy
- // EINVAL => encrypted with v2 policy
- // ENODATA => not encrypted
- return ioctl(fd, FS_IOC_GET_ENCRYPTION_POLICY, &policy) == 0 || errno == EINVAL;
+static bool is_dir_empty(const char *dirname, bool *is_empty)
+{
+ int n = 0;
+ auto dirp = std::unique_ptr<DIR, int (*)(DIR*)>(opendir(dirname), closedir);
+ if (!dirp) {
+ PLOG(ERROR) << "Unable to read directory: " << dirname;
+ return false;
+ }
+ for (;;) {
+ errno = 0;
+ auto entry = readdir(dirp.get());
+ if (!entry) {
+ if (errno) {
+ PLOG(ERROR) << "Unable to read directory: " << dirname;
+ return false;
+ }
+ break;
+ }
+ if (strcmp(entry->d_name, "lost+found") != 0) { // Skip lost+found
+ ++n;
+ if (n > 2) {
+ *is_empty = false;
+ return true;
+ }
+ }
+ }
+ *is_empty = true;
+ return true;
}
-bool OptionsToString(const EncryptionOptions& options, std::string* options_string) {
- std::string contents_mode, filenames_mode;
- if (!LookupModeById(contents_modes, options.contents_mode, &contents_mode)) {
- return false;
+static uint8_t fscrypt_get_policy_flags(int filenames_encryption_mode) {
+ if (filenames_encryption_mode == FS_ENCRYPTION_MODE_AES_256_CTS) {
+ // Use legacy padding with our original filenames encryption mode.
+ return FS_POLICY_FLAGS_PAD_4;
+ } else if (filenames_encryption_mode == FS_ENCRYPTION_MODE_ADIANTUM) {
+ // Use DIRECT_KEY for Adiantum, since it's much more efficient but just
+ // as secure since Android doesn't reuse the same master key for
+ // multiple encryption modes
+ return (FS_POLICY_FLAGS_PAD_16 | FS_POLICY_FLAG_DIRECT_KEY);
}
- if (!LookupModeById(filenames_modes, options.filenames_mode, &filenames_mode)) {
+ // With a new mode we can use the better padding flag without breaking existing devices: pad
+ // filenames with zeroes to the next 16-byte boundary. This is more secure (helps hide the
+ // length of filenames) and makes the inputs evenly divisible into blocks which is more
+ // efficient for encryption and decryption.
+ return FS_POLICY_FLAGS_PAD_16;
+}
+
+static bool fscrypt_policy_set(const char *directory, const char *policy,
+ size_t policy_length,
+ int contents_encryption_mode,
+ int filenames_encryption_mode) {
+ if (policy_length != FS_KEY_DESCRIPTOR_SIZE) {
+ LOG(ERROR) << "Policy wrong length: " << policy_length;
return false;
}
- *options_string = contents_mode + ":" + filenames_mode + ":v" + std::to_string(options.version);
- if ((options.flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64)) {
- *options_string += "+inlinecrypt_optimized";
- }
- EncryptionOptions options_check;
- if (!ParseOptions(*options_string, &options_check)) {
- LOG(ERROR) << "Internal error serializing options as string: " << *options_string;
+ char policy_hex[FS_KEY_DESCRIPTOR_SIZE_HEX];
+ policy_to_hex(policy, policy_hex);
+
+ int fd = open(directory, O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
+ if (fd == -1) {
+ PLOG(ERROR) << "Failed to open directory " << directory;
return false;
}
- if (memcmp(&options, &options_check, sizeof(options_check)) != 0) {
- LOG(ERROR) << "Internal error serializing options as string, round trip failed: "
- << *options_string;
+
+ fscrypt_policy fp;
+ fp.version = 0;
+ fp.contents_encryption_mode = contents_encryption_mode;
+ fp.filenames_encryption_mode = filenames_encryption_mode;
+ fp.flags = fscrypt_get_policy_flags(filenames_encryption_mode);
+ memcpy(fp.master_key_descriptor, policy, FS_KEY_DESCRIPTOR_SIZE);
+ if (ioctl(fd, FS_IOC_SET_ENCRYPTION_POLICY, &fp)) {
+ PLOG(ERROR) << "Failed to set encryption policy for " << directory << " to " << policy_hex
+ << " modes " << contents_encryption_mode << "/" << filenames_encryption_mode;
+ close(fd);
return false;
}
+ close(fd);
+
+ LOG(INFO) << "Policy for " << directory << " set to " << policy_hex
+ << " modes " << contents_encryption_mode << "/" << filenames_encryption_mode;
return true;
}
-bool ParseOptions(const std::string& options_string, EncryptionOptions* options) {
- memset(options, '\0', sizeof(*options));
- auto parts = android::base::Split(options_string, ":");
- if (parts.size() < 1 || parts.size() > 3) {
+static bool fscrypt_policy_get(const char *directory, char *policy,
+ size_t policy_length,
+ int contents_encryption_mode,
+ int filenames_encryption_mode) {
+ if (policy_length != FS_KEY_DESCRIPTOR_SIZE) {
+ LOG(ERROR) << "Policy wrong length: " << policy_length;
return false;
}
- if (!LookupModeByName(contents_modes, parts[0], &options->contents_mode)) {
- LOG(ERROR) << "Invalid file contents encryption mode: " << parts[0];
+
+ int fd = open(directory, O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
+ if (fd == -1) {
+ PLOG(ERROR) << "Failed to open directory " << directory;
return false;
}
- if (parts.size() >= 2) {
- if (!LookupModeByName(filenames_modes, parts[1], &options->filenames_mode)) {
- LOG(ERROR) << "Invalid file names encryption mode: " << parts[1];
- return false;
- }
- } else if (options->contents_mode == FS_ENCRYPTION_MODE_ADIANTUM) {
- options->filenames_mode = FS_ENCRYPTION_MODE_ADIANTUM;
- } else {
- options->filenames_mode = FS_ENCRYPTION_MODE_AES_256_CTS;
- }
- options->version = 1;
- options->flags = 0;
- if (parts.size() >= 3) {
- auto flags = android::base::Split(parts[2], "+");
- for (const auto& flag : flags) {
- if (flag == "v1") {
- options->version = 1;
- } else if (flag == "v2") {
- options->version = 2;
- } else if (flag == "inlinecrypt_optimized") {
- options->flags |= FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64;
- } else {
- LOG(ERROR) << "Unknown flag: " << flag;
- return false;
- }
- }
- }
- // In the original setting of v1 policies and AES-256-CTS we used 4-byte
- // padding of filenames, so we have to retain that for compatibility.
- //
- // For everything else, use 16-byte padding. This is more secure (it helps
- // hide the length of filenames), and it makes the inputs evenly divisible
- // into cipher blocks which is more efficient for encryption and decryption.
- if (options->version == 1 && options->filenames_mode == FS_ENCRYPTION_MODE_AES_256_CTS) {
- options->flags |= FS_POLICY_FLAGS_PAD_4;
- } else {
- options->flags |= FS_POLICY_FLAGS_PAD_16;
+ fscrypt_policy fp;
+ memset(&fp, 0, sizeof(fscrypt_policy));
+ if (ioctl(fd, FS_IOC_GET_ENCRYPTION_POLICY, &fp) != 0) {
+ PLOG(ERROR) << "Failed to get encryption policy for " << directory;
+ close(fd);
+ log_ls(directory);
+ return false;
}
-
- // Use DIRECT_KEY for Adiantum, since it's much more efficient but just as
- // secure since Android doesn't reuse the same master key for multiple
- // encryption modes.
- if (options->filenames_mode == FS_ENCRYPTION_MODE_ADIANTUM) {
- options->flags |= FS_POLICY_FLAG_DIRECT_KEY;
+ close(fd);
+
+ if ((fp.version != 0)
+ || (fp.contents_encryption_mode != contents_encryption_mode)
+ || (fp.filenames_encryption_mode != filenames_encryption_mode)
+ || (fp.flags !=
+ fscrypt_get_policy_flags(filenames_encryption_mode))) {
+ LOG(ERROR) << "Failed to find matching encryption policy for " << directory;
+ return false;
}
- return true;
-}
+ memcpy(policy, fp.master_key_descriptor, FS_KEY_DESCRIPTOR_SIZE);
-static std::string PolicyDebugString(const EncryptionPolicy& policy) {
- std::stringstream ss;
- std::string ref_hex;
- BytesToHex(policy.key_raw_ref, &ref_hex);
- ss << ref_hex;
- ss << " v" << policy.options.version;
- ss << " modes " << policy.options.contents_mode << "/" << policy.options.filenames_mode;
- ss << std::hex << " flags 0x" << policy.options.flags;
- return ss.str();
+ return true;
}
-bool EnsurePolicy(const EncryptionPolicy& policy, const std::string& directory) {
- union {
- fscrypt_policy_v1 v1;
- fscrypt_policy_v2 v2;
- } kern_policy;
- memset(&kern_policy, 0, sizeof(kern_policy));
-
- switch (policy.options.version) {
- case 1:
- if (policy.key_raw_ref.size() != FSCRYPT_KEY_DESCRIPTOR_SIZE) {
- LOG(ERROR) << "Invalid key descriptor length for v1 policy: "
- << policy.key_raw_ref.size();
- return false;
- }
- // Careful: FSCRYPT_POLICY_V1 is actually 0 in the API, so make sure
- // to use it here instead of a literal 1.
- kern_policy.v1.version = FSCRYPT_POLICY_V1;
- kern_policy.v1.contents_encryption_mode = policy.options.contents_mode;
- kern_policy.v1.filenames_encryption_mode = policy.options.filenames_mode;
- kern_policy.v1.flags = policy.options.flags;
- policy.key_raw_ref.copy(reinterpret_cast<char*>(kern_policy.v1.master_key_descriptor),
- FSCRYPT_KEY_DESCRIPTOR_SIZE);
- break;
- case 2:
- if (policy.key_raw_ref.size() != FSCRYPT_KEY_IDENTIFIER_SIZE) {
- LOG(ERROR) << "Invalid key identifier length for v2 policy: "
- << policy.key_raw_ref.size();
- return false;
- }
- kern_policy.v2.version = FSCRYPT_POLICY_V2;
- kern_policy.v2.contents_encryption_mode = policy.options.contents_mode;
- kern_policy.v2.filenames_encryption_mode = policy.options.filenames_mode;
- kern_policy.v2.flags = policy.options.flags;
- policy.key_raw_ref.copy(reinterpret_cast<char*>(kern_policy.v2.master_key_identifier),
- FSCRYPT_KEY_IDENTIFIER_SIZE);
- break;
- default:
- LOG(ERROR) << "Invalid encryption policy version: " << policy.options.version;
- return false;
+static bool fscrypt_policy_check(const char *directory, const char *policy,
+ size_t policy_length,
+ int contents_encryption_mode,
+ int filenames_encryption_mode) {
+ if (policy_length != FS_KEY_DESCRIPTOR_SIZE) {
+ LOG(ERROR) << "Policy wrong length: " << policy_length;
+ return false;
}
-
- android::base::unique_fd fd(open(directory.c_str(), O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC));
- if (fd == -1) {
- PLOG(ERROR) << "Failed to open directory " << directory;
+ char existing_policy[FS_KEY_DESCRIPTOR_SIZE];
+ if (!fscrypt_policy_get(directory, existing_policy, FS_KEY_DESCRIPTOR_SIZE,
+ contents_encryption_mode,
+ filenames_encryption_mode)) return false;
+ char existing_policy_hex[FS_KEY_DESCRIPTOR_SIZE_HEX];
+
+ policy_to_hex(existing_policy, existing_policy_hex);
+
+ if (memcmp(policy, existing_policy, FS_KEY_DESCRIPTOR_SIZE) != 0) {
+ char policy_hex[FS_KEY_DESCRIPTOR_SIZE_HEX];
+ policy_to_hex(policy, policy_hex);
+ LOG(ERROR) << "Found policy " << existing_policy_hex << " at " << directory
+ << " which doesn't match expected value " << policy_hex;
+ log_ls(directory);
return false;
}
+ LOG(INFO) << "Found policy " << existing_policy_hex << " at " << directory
+ << " which matches expected value";
+ return true;
+}
- bool already_encrypted = fscrypt_is_encrypted(fd);
+int fscrypt_policy_ensure(const char *directory, const char *policy,
+ size_t policy_length,
+ const char *contents_encryption_mode,
+ const char *filenames_encryption_mode) {
+ int contents_mode = 0;
+ int filenames_mode = 0;
+
+ if (!strcmp(contents_encryption_mode, "software") ||
+ !strcmp(contents_encryption_mode, "aes-256-xts")) {
+ contents_mode = FS_ENCRYPTION_MODE_AES_256_XTS;
+ } else if (!strcmp(contents_encryption_mode, "adiantum")) {
+ contents_mode = FS_ENCRYPTION_MODE_ADIANTUM;
+ } else if (!strcmp(contents_encryption_mode, "ice")) {
+ contents_mode = FS_ENCRYPTION_MODE_PRIVATE;
+ } else {
+ LOG(ERROR) << "Invalid file contents encryption mode: "
+ << contents_encryption_mode;
+ return -1;
+ }
- // FS_IOC_SET_ENCRYPTION_POLICY will set the policy if the directory is
- // unencrypted; otherwise it will verify that the existing policy matches.
- // Setting the policy will fail if the directory is already nonempty.
- if (ioctl(fd, FS_IOC_SET_ENCRYPTION_POLICY, &kern_policy) != 0) {
- std::string reason;
- switch (errno) {
- case EEXIST:
- reason = "The directory already has a different encryption policy.";
- break;
- default:
- reason = strerror(errno);
- break;
- }
- LOG(ERROR) << "Failed to set encryption policy of " << directory << " to "
- << PolicyDebugString(policy) << ": " << reason;
- if (errno == ENOTEMPTY) {
- log_ls(directory.c_str());
- }
- return false;
+ if (!strcmp(filenames_encryption_mode, "aes-256-cts")) {
+ filenames_mode = FS_ENCRYPTION_MODE_AES_256_CTS;
+ } else if (!strcmp(filenames_encryption_mode, "aes-256-heh")) {
+ filenames_mode = FS_ENCRYPTION_MODE_AES_256_HEH;
+ } else if (!strcmp(filenames_encryption_mode, "adiantum")) {
+ filenames_mode = FS_ENCRYPTION_MODE_ADIANTUM;
+ } else {
+ LOG(ERROR) << "Invalid file names encryption mode: "
+ << filenames_encryption_mode;
+ return -1;
}
- if (already_encrypted) {
- LOG(INFO) << "Verified that " << directory << " has the encryption policy "
- << PolicyDebugString(policy);
+ bool is_empty;
+ if (!is_dir_empty(directory, &is_empty)) return -1;
+ if (is_empty) {
+ if (!fscrypt_policy_set(directory, policy, policy_length,
+ contents_mode, filenames_mode)) return -1;
} else {
- LOG(INFO) << "Encryption policy of " << directory << " set to "
- << PolicyDebugString(policy);
+ if (!fscrypt_policy_check(directory, policy, policy_length,
+ contents_mode, filenames_mode)) return -1;
}
- return true;
+ return 0;
}
-
-} // namespace fscrypt
-} // namespace android
diff --git a/libfscrypt/fscrypt_init_extensions.cpp b/libfscrypt/fscrypt_init_extensions.cpp
new file mode 100644
index 00000000..2fd70e79
--- /dev/null
+++ b/libfscrypt/fscrypt_init_extensions.cpp
@@ -0,0 +1,146 @@
+/*
+ * 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 "fscrypt/fscrypt.h"
+#include "fscrypt/fscrypt_init_extensions.h"
+
+#include <dirent.h>
+#include <errno.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <string>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <cutils/properties.h>
+#include <cutils/sockets.h>
+#include <keyutils.h>
+#include <logwrap/logwrap.h>
+
+#define TAG "fscrypt"
+
+static const std::string arbitrary_sequence_number = "42";
+
+static int set_policy_on(char const* ref_basename, char const* dir);
+
+int fscrypt_install_keyring()
+{
+ key_serial_t device_keyring = add_key("keyring", "fscrypt", 0, 0,
+ KEY_SPEC_SESSION_KEYRING);
+
+ if (device_keyring == -1) {
+ PLOG(ERROR) << "Failed to create keyring";
+ return -1;
+ }
+
+ LOG(INFO) << "Keyring created with id " << device_keyring << " in process " << getpid();
+
+ return 0;
+}
+
+int fscrypt_set_directory_policy(const char* dir)
+{
+ if (!dir || strncmp(dir, "/data/", 6)) {
+ return 0;
+ }
+
+ // Special-case /data/media/obb per b/64566063
+ if (strcmp(dir, "/data/media/obb") == 0) {
+ // Try to set policy on this directory, but if it is non-empty this may fail.
+ set_policy_on(fscrypt_key_ref, dir);
+ return 0;
+ }
+
+ // 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
+ // to apply a global policy to all /data folders created via makedir
+ if (strchr(dir + 6, '/')) {
+ return 0;
+ }
+
+ // Special case various directories that must not be encrypted,
+ // 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",
+ "system_ce", "system_de",
+ "misc_ce", "misc_de",
+ "vendor_ce", "vendor_de",
+ "media",
+ "data", "user", "user_de",
+ "apex", "preloads", "app-staging",
+ "gsi",
+ };
+ std::string prefix = "/data/";
+ for (const auto& d: directories_to_exclude) {
+ if ((prefix + d) == dir) {
+ LOG(INFO) << "Not setting policy on " << dir;
+ return 0;
+ }
+ }
+ std::vector<std::string> per_boot_directories = {
+ "per_boot",
+ };
+ for (const auto& d : per_boot_directories) {
+ if ((prefix + d) == dir) {
+ LOG(INFO) << "Setting per_boot key on " << dir;
+ return set_policy_on(fscrypt_key_per_boot_ref, dir);
+ }
+ }
+ return set_policy_on(fscrypt_key_ref, dir);
+}
+
+static int set_policy_on(char const* ref_basename, char const* dir) {
+ std::string ref_filename = std::string("/data") + ref_basename;
+ std::string policy;
+ if (!android::base::ReadFileToString(ref_filename, &policy)) {
+ LOG(ERROR) << "Unable to read system policy to set on " << dir;
+ return -1;
+ }
+
+ auto type_filename = std::string("/data") + fscrypt_key_mode;
+ std::string modestring;
+ if (!android::base::ReadFileToString(type_filename, &modestring)) {
+ LOG(ERROR) << "Cannot read mode";
+ }
+
+ std::vector<std::string> modes = android::base::Split(modestring, ":");
+
+ if (modes.size() < 1 || modes.size() > 2) {
+ LOG(ERROR) << "Invalid encryption mode string: " << modestring;
+ return -1;
+ }
+
+ LOG(INFO) << "Setting policy on " << dir;
+ int result = fscrypt_policy_ensure(dir, policy.c_str(), policy.length(),
+ modes[0].c_str(),
+ modes.size() >= 2 ?
+ modes[1].c_str() : "aes-256-cts");
+ if (result) {
+ LOG(ERROR) << android::base::StringPrintf(
+ "Setting %02x%02x%02x%02x policy on %s failed!",
+ policy[0], policy[1], policy[2], policy[3], dir);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/libfscrypt/include/fscrypt/fscrypt.h b/libfscrypt/include/fscrypt/fscrypt.h
index 2b809866..ff82d47a 100644
--- a/libfscrypt/include/fscrypt/fscrypt.h
+++ b/libfscrypt/include/fscrypt/fscrypt.h
@@ -17,45 +17,24 @@
#ifndef _FSCRYPT_H_
#define _FSCRYPT_H_
-#include <string>
+#include <sys/cdefs.h>
+#include <stdbool.h>
+#include <cutils/multiuser.h>
-// TODO: switch to <linux/fscrypt.h> once it's in Bionic
-#define FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64 0x08
+__BEGIN_DECLS
bool fscrypt_is_native();
+int fscrypt_policy_ensure(const char *directory, const char *policy,
+ size_t policy_length,
+ const char *contents_encryption_mode,
+ const char *filenames_encryption_mode);
+
static const char* fscrypt_unencrypted_folder = "/unencrypted";
static const char* fscrypt_key_ref = "/unencrypted/ref";
static const char* fscrypt_key_per_boot_ref = "/unencrypted/per_boot_ref";
static const char* fscrypt_key_mode = "/unencrypted/mode";
-namespace android {
-namespace fscrypt {
-
-struct EncryptionOptions {
- int version;
- int contents_mode;
- int filenames_mode;
- int flags;
-
- // Ensure that "version" is not valid on creation and so must be explicitly set
- EncryptionOptions() : version(0) {}
-};
-
-struct EncryptionPolicy {
- EncryptionOptions options;
- std::string key_raw_ref;
-};
-
-void BytesToHex(const std::string& bytes, std::string* hex);
-
-bool OptionsToString(const EncryptionOptions& options, std::string* options_string);
-
-bool ParseOptions(const std::string& options_string, EncryptionOptions* options);
-
-bool EnsurePolicy(const EncryptionPolicy& policy, const std::string& directory);
-
-} // namespace fscrypt
-} // namespace android
+__END_DECLS
#endif // _FSCRYPT_H_
diff --git a/libfscrypt/include/fscrypt/fscrypt_init_extensions.h b/libfscrypt/include/fscrypt/fscrypt_init_extensions.h
new file mode 100644
index 00000000..2b6c46e1
--- /dev/null
+++ b/libfscrypt/include/fscrypt/fscrypt_init_extensions.h
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+#ifndef _FSCRYPT_INIT_EXTENSIONS_H_
+#define _FSCRYPT_INIT_EXTENSIONS_H_
+
+#include <sys/cdefs.h>
+#include <stdbool.h>
+#include <cutils/multiuser.h>
+
+__BEGIN_DECLS
+
+// These functions assume they are being called from init
+// They will not operate properly outside of init
+int fscrypt_install_keyring();
+int fscrypt_set_directory_policy(const char* path);
+
+__END_DECLS
+
+#endif // _FSCRYPT_INIT_EXTENSIONS_H_
diff --git a/libfscrypt/tests/Android.bp b/libfscrypt/tests/Android.bp
deleted file mode 100644
index 985b425f..00000000
--- a/libfscrypt/tests/Android.bp
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright (C) 2019 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.
-
-cc_test {
- name: "libfscrypt_unit_test",
-
- shared_libs: [
- "libbase",
- ],
- static_libs: [
- "libfscrypt",
- ],
- srcs: [
- "fscrypt_test.cpp",
- ],
-
- cflags: [
- "-Wall",
- "-Wextra",
- "-Werror",
- ],
-}
diff --git a/libfscrypt/tests/fscrypt_test.cpp b/libfscrypt/tests/fscrypt_test.cpp
deleted file mode 100644
index 677f0f22..00000000
--- a/libfscrypt/tests/fscrypt_test.cpp
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2019 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 <linux/fs.h>
-
-#include <fscrypt/fscrypt.h>
-
-#include <gtest/gtest.h>
-
-using namespace android::fscrypt;
-
-/* modes not supported by upstream kernel, so not in <linux/fs.h> */
-#define FS_ENCRYPTION_MODE_AES_256_HEH 126
-#define FS_ENCRYPTION_MODE_PRIVATE 127
-
-TEST(fscrypt, ParseOptions) {
- EncryptionOptions options;
- std::string options_string;
-
- EXPECT_FALSE(ParseOptions("", &options));
- EXPECT_FALSE(ParseOptions("blah", &options));
-
- EXPECT_TRUE(ParseOptions("software", &options));
- EXPECT_EQ(1, options.version);
- EXPECT_EQ(FS_ENCRYPTION_MODE_AES_256_XTS, options.contents_mode);
- EXPECT_EQ(FS_ENCRYPTION_MODE_AES_256_CTS, options.filenames_mode);
- EXPECT_EQ(FS_POLICY_FLAGS_PAD_4, options.flags);
- EXPECT_TRUE(OptionsToString(options, &options_string));
- EXPECT_EQ("aes-256-xts:aes-256-cts:v1", options_string);
-
- EXPECT_TRUE(ParseOptions("aes-256-xts", &options));
- EXPECT_EQ(1, options.version);
- EXPECT_EQ(FS_ENCRYPTION_MODE_AES_256_XTS, options.contents_mode);
- EXPECT_EQ(FS_ENCRYPTION_MODE_AES_256_CTS, options.filenames_mode);
- EXPECT_EQ(FS_POLICY_FLAGS_PAD_4, options.flags);
- EXPECT_TRUE(OptionsToString(options, &options_string));
- EXPECT_EQ("aes-256-xts:aes-256-cts:v1", options_string);
-
- EXPECT_TRUE(ParseOptions("adiantum", &options));
- EXPECT_EQ(1, options.version);
- EXPECT_EQ(FS_ENCRYPTION_MODE_ADIANTUM, options.contents_mode);
- EXPECT_EQ(FS_ENCRYPTION_MODE_ADIANTUM, options.filenames_mode);
- EXPECT_EQ(FS_POLICY_FLAGS_PAD_16 | FS_POLICY_FLAG_DIRECT_KEY, options.flags);
- EXPECT_TRUE(OptionsToString(options, &options_string));
- EXPECT_EQ("adiantum:adiantum:v1", options_string);
-
- EXPECT_TRUE(ParseOptions("adiantum:aes-256-heh", &options));
- EXPECT_EQ(1, options.version);
- EXPECT_EQ(FS_ENCRYPTION_MODE_ADIANTUM, options.contents_mode);
- EXPECT_EQ(FS_ENCRYPTION_MODE_AES_256_HEH, options.filenames_mode);
- EXPECT_EQ(FS_POLICY_FLAGS_PAD_16, options.flags);
- EXPECT_TRUE(OptionsToString(options, &options_string));
- EXPECT_EQ("adiantum:aes-256-heh:v1", options_string);
-
- EXPECT_TRUE(ParseOptions("ice", &options));
- EXPECT_EQ(1, options.version);
- EXPECT_EQ(FS_ENCRYPTION_MODE_PRIVATE, options.contents_mode);
- EXPECT_EQ(FS_ENCRYPTION_MODE_AES_256_CTS, options.filenames_mode);
- EXPECT_EQ(FS_POLICY_FLAGS_PAD_4, options.flags);
- EXPECT_TRUE(OptionsToString(options, &options_string));
- EXPECT_EQ("ice:aes-256-cts:v1", options_string);
-
- EXPECT_FALSE(ParseOptions("ice:blah", &options));
-
- EXPECT_TRUE(ParseOptions("ice:aes-256-cts", &options));
- EXPECT_EQ(1, options.version);
- EXPECT_EQ(FS_ENCRYPTION_MODE_PRIVATE, options.contents_mode);
- EXPECT_EQ(FS_ENCRYPTION_MODE_AES_256_CTS, options.filenames_mode);
- EXPECT_EQ(FS_POLICY_FLAGS_PAD_4, options.flags);
- EXPECT_TRUE(OptionsToString(options, &options_string));
- EXPECT_EQ("ice:aes-256-cts:v1", options_string);
-
- EXPECT_TRUE(ParseOptions("ice:aes-256-heh", &options));
- EXPECT_EQ(1, options.version);
- EXPECT_EQ(FS_ENCRYPTION_MODE_PRIVATE, options.contents_mode);
- EXPECT_EQ(FS_ENCRYPTION_MODE_AES_256_HEH, options.filenames_mode);
- EXPECT_EQ(FS_POLICY_FLAGS_PAD_16, options.flags);
- EXPECT_TRUE(OptionsToString(options, &options_string));
- EXPECT_EQ("ice:aes-256-heh:v1", options_string);
-
- EXPECT_TRUE(ParseOptions("ice:adiantum", &options));
- EXPECT_EQ(1, options.version);
- EXPECT_EQ(FS_ENCRYPTION_MODE_PRIVATE, options.contents_mode);
- EXPECT_EQ(FS_ENCRYPTION_MODE_ADIANTUM, options.filenames_mode);
- EXPECT_EQ(FS_POLICY_FLAGS_PAD_16 | FS_POLICY_FLAG_DIRECT_KEY, options.flags);
- EXPECT_TRUE(OptionsToString(options, &options_string));
- EXPECT_EQ("ice:adiantum:v1", options_string);
-
- EXPECT_TRUE(ParseOptions("aes-256-xts:aes-256-cts", &options));
- EXPECT_EQ(1, options.version);
- EXPECT_EQ(FS_ENCRYPTION_MODE_AES_256_XTS, options.contents_mode);
- EXPECT_EQ(FS_ENCRYPTION_MODE_AES_256_CTS, options.filenames_mode);
- EXPECT_EQ(FS_POLICY_FLAGS_PAD_4, options.flags);
- EXPECT_TRUE(OptionsToString(options, &options_string));
- EXPECT_EQ("aes-256-xts:aes-256-cts:v1", options_string);
-
- EXPECT_TRUE(ParseOptions("aes-256-xts:aes-256-cts:v1", &options));
- EXPECT_EQ(1, options.version);
- EXPECT_EQ(FS_ENCRYPTION_MODE_AES_256_XTS, options.contents_mode);
- EXPECT_EQ(FS_ENCRYPTION_MODE_AES_256_CTS, options.filenames_mode);
- EXPECT_EQ(FS_POLICY_FLAGS_PAD_4, options.flags);
- EXPECT_TRUE(OptionsToString(options, &options_string));
- EXPECT_EQ("aes-256-xts:aes-256-cts:v1", options_string);
-
- EXPECT_TRUE(ParseOptions("aes-256-xts:aes-256-cts:v2", &options));
- EXPECT_EQ(2, options.version);
- EXPECT_EQ(FS_ENCRYPTION_MODE_AES_256_XTS, options.contents_mode);
- EXPECT_EQ(FS_ENCRYPTION_MODE_AES_256_CTS, options.filenames_mode);
- EXPECT_EQ(FS_POLICY_FLAGS_PAD_16, options.flags);
- EXPECT_TRUE(OptionsToString(options, &options_string));
- EXPECT_EQ("aes-256-xts:aes-256-cts:v2", options_string);
-
- EXPECT_TRUE(ParseOptions("aes-256-xts:aes-256-cts:v2+inlinecrypt_optimized", &options));
- EXPECT_EQ(2, options.version);
- EXPECT_EQ(FS_ENCRYPTION_MODE_AES_256_XTS, options.contents_mode);
- EXPECT_EQ(FS_ENCRYPTION_MODE_AES_256_CTS, options.filenames_mode);
- EXPECT_EQ(FS_POLICY_FLAGS_PAD_16 | FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64, options.flags);
- EXPECT_TRUE(OptionsToString(options, &options_string));
- EXPECT_EQ("aes-256-xts:aes-256-cts:v2+inlinecrypt_optimized", options_string);
-
- EXPECT_FALSE(ParseOptions("aes-256-xts:aes-256-cts:v2:", &options));
- EXPECT_FALSE(ParseOptions("aes-256-xts:aes-256-cts:v2:foo", &options));
- EXPECT_FALSE(ParseOptions("aes-256-xts:aes-256-cts:blah", &options));
- EXPECT_FALSE(ParseOptions("aes-256-xts:aes-256-cts:vblah", &options));
-}