From d964376a927a5210f7bb7e80ca738b05b65b8d87 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Thu, 12 Sep 2019 11:20:27 -0700 Subject: [PATCH 1/2] fs_mgr_fstab: support specifying encryption policy version in fstab Allow the encryption policy version to be specified as a third field in the "fileencryption=" fstab option, and expose it through the fstab record so that vold can use it. Bug: 140500999 Test: tested as series; see If64028d8580584b2c33c614cabd5d6b93657f608. Also updated and ran the fs_mgr unit tests. Change-Id: If5d56f4c84c4cd51e3f14c0a861c3e3ab6ff903f --- fs_mgr/fs_mgr_fstab.cpp | 24 ++++++++++++--- fs_mgr/include_fstab/fstab/fstab.h | 1 + fs_mgr/tests/fs_mgr_test.cpp | 49 ++++++++++++++++++++++++++++-- 3 files changed, 67 insertions(+), 7 deletions(-) diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp index e50f7c378..c1a8dae3d 100644 --- a/fs_mgr/fs_mgr_fstab.cpp +++ b/fs_mgr/fs_mgr_fstab.cpp @@ -112,13 +112,16 @@ const std::array kFileNamesEncryptionMode = { }; void ParseFileEncryption(const std::string& arg, FstabEntry* entry) { - // The fileencryption flag is followed by an = and the mode of contents encryption, then - // optionally a and the mode of filenames encryption (defaults to aes-256-cts). Get it and - // return it. + // The fileencryption flag is followed by an = and 1 to 3 colon-separated fields: + // + // 1. Contents encryption mode + // 2. Filenames encryption mode (defaults to "aes-256-cts" or "adiantum" + // depending on the contents encryption mode) + // 3. Encryption policy version (defaults to "v1". Use "v2" on new devices.) entry->fs_mgr_flags.file_encryption = true; auto parts = Split(arg, ":"); - if (parts.empty() || parts.size() > 2) { + if (parts.empty() || parts.size() > 3) { LWARNING << "Warning: fileencryption= flag malformed: " << arg; return; } @@ -137,7 +140,7 @@ void ParseFileEncryption(const std::string& arg, FstabEntry* entry) { entry->file_contents_mode = parts[0]; - if (parts.size() == 2) { + if (parts.size() >= 2) { if (std::find(kFileNamesEncryptionMode.begin(), kFileNamesEncryptionMode.end(), parts[1]) == kFileNamesEncryptionMode.end()) { LWARNING << "fileencryption= flag malformed, file names encryption mode not found: " @@ -151,6 +154,16 @@ void ParseFileEncryption(const std::string& arg, FstabEntry* entry) { } else { entry->file_names_mode = "aes-256-cts"; } + + if (parts.size() >= 3) { + if (!android::base::StartsWith(parts[2], 'v') || + !android::base::ParseInt(&parts[2][1], &entry->file_policy_version)) { + LWARNING << "fileencryption= flag malformed, unknown options: " << arg; + return; + } + } else { + entry->file_policy_version = 1; + } } bool SetMountFlag(const std::string& flag, FstabEntry* entry) { @@ -288,6 +301,7 @@ void ParseFsMgrFlags(const std::string& flags, FstabEntry* entry) { entry->key_loc = arg; entry->file_contents_mode = "aes-256-xts"; entry->file_names_mode = "aes-256-cts"; + entry->file_policy_version = 1; } else if (StartsWith(flag, "max_comp_streams=")) { if (!ParseInt(arg, &entry->max_comp_streams)) { LWARNING << "Warning: max_comp_streams= flag malformed: " << arg; diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h index d999ae18a..3c517dc44 100644 --- a/fs_mgr/include_fstab/fstab/fstab.h +++ b/fs_mgr/include_fstab/fstab/fstab.h @@ -47,6 +47,7 @@ struct FstabEntry { off64_t reserved_size = 0; std::string file_contents_mode; std::string file_names_mode; + int file_policy_version = 0; off64_t erase_blk_size = 0; off64_t logical_blk_size = 0; std::string sysfs_path; diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp index 6d8759404..a7ea81793 100644 --- a/fs_mgr/tests/fs_mgr_test.cpp +++ b/fs_mgr/tests/fs_mgr_test.cpp @@ -467,6 +467,7 @@ source none2 swap defaults forcefdeorfbe= } EXPECT_EQ("aes-256-xts", entry->file_contents_mode); EXPECT_EQ("aes-256-cts", entry->file_names_mode); + EXPECT_EQ(1, entry->file_policy_version); EXPECT_EQ("", entry->key_loc); } @@ -682,6 +683,7 @@ source none0 swap defaults forcefdeorfbe=/dir/key EXPECT_EQ("/dir/key", entry->key_loc); EXPECT_EQ("aes-256-xts", entry->file_contents_mode); EXPECT_EQ("aes-256-cts", entry->file_names_mode); + EXPECT_EQ(1, entry->file_policy_version); } TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_FileEncryption) { @@ -698,14 +700,18 @@ source none6 swap defaults fileencryption=ice:blah source none7 swap defaults fileencryption=ice:aes-256-cts source none8 swap defaults fileencryption=ice:aes-256-heh source none9 swap defaults fileencryption=ice:adiantum -source none10 swap defaults fileencryption=ice:adiantum: +source none10 swap defaults fileencryption=aes-256-xts:aes-256-cts:v1 +source none11 swap defaults fileencryption=aes-256-xts:aes-256-cts:v2 +source none12 swap defaults fileencryption=aes-256-xts:aes-256-cts:v2: +source none13 swap defaults fileencryption=aes-256-xts:aes-256-cts:blah +source none14 swap defaults fileencryption=aes-256-xts:aes-256-cts:vblah )fs"; ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path)); Fstab fstab; EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab)); - ASSERT_EQ(11U, fstab.size()); + ASSERT_EQ(15U, fstab.size()); FstabEntry::FsMgrFlags flags = {}; flags.file_encryption = true; @@ -715,66 +721,105 @@ source none10 swap defaults fileencryption=ice:adiantum: EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ("", entry->file_contents_mode); EXPECT_EQ("", entry->file_names_mode); + EXPECT_EQ(0, entry->file_policy_version); entry++; EXPECT_EQ("none1", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ("aes-256-xts", entry->file_contents_mode); EXPECT_EQ("aes-256-cts", entry->file_names_mode); + EXPECT_EQ(1, entry->file_policy_version); entry++; EXPECT_EQ("none2", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ("aes-256-xts", entry->file_contents_mode); EXPECT_EQ("aes-256-cts", entry->file_names_mode); + EXPECT_EQ(1, entry->file_policy_version); entry++; EXPECT_EQ("none3", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ("adiantum", entry->file_contents_mode); EXPECT_EQ("adiantum", entry->file_names_mode); + EXPECT_EQ(1, entry->file_policy_version); entry++; EXPECT_EQ("none4", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ("adiantum", entry->file_contents_mode); EXPECT_EQ("aes-256-heh", entry->file_names_mode); + EXPECT_EQ(1, entry->file_policy_version); entry++; EXPECT_EQ("none5", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ("ice", entry->file_contents_mode); EXPECT_EQ("aes-256-cts", entry->file_names_mode); + EXPECT_EQ(1, entry->file_policy_version); entry++; EXPECT_EQ("none6", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ("ice", entry->file_contents_mode); EXPECT_EQ("", entry->file_names_mode); + EXPECT_EQ(0, entry->file_policy_version); entry++; EXPECT_EQ("none7", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ("ice", entry->file_contents_mode); EXPECT_EQ("aes-256-cts", entry->file_names_mode); + EXPECT_EQ(1, entry->file_policy_version); entry++; EXPECT_EQ("none8", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ("ice", entry->file_contents_mode); EXPECT_EQ("aes-256-heh", entry->file_names_mode); + EXPECT_EQ(1, entry->file_policy_version); entry++; EXPECT_EQ("none9", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ("ice", entry->file_contents_mode); EXPECT_EQ("adiantum", entry->file_names_mode); + EXPECT_EQ(1, entry->file_policy_version); entry++; EXPECT_EQ("none10", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); + EXPECT_EQ("aes-256-xts", entry->file_contents_mode); + EXPECT_EQ("aes-256-cts", entry->file_names_mode); + EXPECT_EQ(1, entry->file_policy_version); + + entry++; + EXPECT_EQ("none11", entry->mount_point); + EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); + EXPECT_EQ("aes-256-xts", entry->file_contents_mode); + EXPECT_EQ("aes-256-cts", entry->file_names_mode); + EXPECT_EQ(2, entry->file_policy_version); + + entry++; + EXPECT_EQ("none12", entry->mount_point); + EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ("", entry->file_contents_mode); EXPECT_EQ("", entry->file_names_mode); + EXPECT_EQ(0, entry->file_policy_version); + + entry++; + EXPECT_EQ("none13", entry->mount_point); + EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); + EXPECT_EQ("aes-256-xts", entry->file_contents_mode); + EXPECT_EQ("aes-256-cts", entry->file_names_mode); + EXPECT_EQ(0, entry->file_policy_version); + + entry++; + EXPECT_EQ("none14", entry->mount_point); + EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); + EXPECT_EQ("aes-256-xts", entry->file_contents_mode); + EXPECT_EQ("aes-256-cts", entry->file_names_mode); + EXPECT_EQ(0, entry->file_policy_version); } TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_MaxCompStreams) { From eaadc9d4266c2c20274d9d4f4a8ad55c48e155f5 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Fri, 13 Sep 2019 10:54:53 -0700 Subject: [PATCH 2/2] init/fscrypt_init_extensions: support setting v2 encryption policies Support setting v2 encryption policies on init-created directories. The policy version to set is gotten from a new field in /data/unencrypted/mode, which is the file that's used to pass the encryption options from vold to init. Also don't bother falling back to defaults if fields are missing from this file, since it's re-written on every boot by vold. Bug: 140500999 Test: tested as series; see If64028d8580584b2c33c614cabd5d6b93657f608 Change-Id: Ia9c5d4b80199686799e3ac80de78a50ed3bdabf4 --- init/fscrypt_init_extensions.cpp | 51 ++++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 12 deletions(-) diff --git a/init/fscrypt_init_extensions.cpp b/init/fscrypt_init_extensions.cpp index bd23e31df..bbebbe84d 100644 --- a/init/fscrypt_init_extensions.cpp +++ b/init/fscrypt_init_extensions.cpp @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -163,33 +164,59 @@ int fscrypt_set_directory_policy(const std::string& dir) { return err; } +static int parse_encryption_options_string(const std::string& options_string, + std::string* contents_mode_ret, + std::string* filenames_mode_ret, + int* policy_version_ret) { + auto parts = android::base::Split(options_string, ":"); + + if (parts.size() != 3) { + return -1; + } + + *contents_mode_ret = parts[0]; + *filenames_mode_ret = parts[1]; + if (!android::base::StartsWith(parts[2], 'v') || + !android::base::ParseInt(&parts[2][1], policy_version_ret)) { + return -1; + } + + return 0; +} + +// Set an encryption policy on the given directory. The policy (key reference +// and encryption options) to use is read from files that were written by vold. static int set_policy_on(const std::string& ref_basename, const std::string& dir) { std::string ref_filename = std::string("/data") + ref_basename; - std::string policy; - if (!android::base::ReadFileToString(ref_filename, &policy)) { + std::string key_ref; + if (!android::base::ReadFileToString(ref_filename, &key_ref)) { 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"; + auto options_filename = std::string("/data") + fscrypt_key_mode; + std::string options_string; + if (!android::base::ReadFileToString(options_filename, &options_string)) { + LOG(ERROR) << "Cannot read encryption options string"; + return -1; } - std::vector modes = android::base::Split(modestring, ":"); + std::string contents_mode; + std::string filenames_mode; + int policy_version = 0; - if (modes.size() < 1 || modes.size() > 2) { - LOG(ERROR) << "Invalid encryption mode string: " << modestring; + if (parse_encryption_options_string(options_string, &contents_mode, &filenames_mode, + &policy_version)) { + LOG(ERROR) << "Invalid encryption options string: " << options_string; return -1; } int result = - fscrypt_policy_ensure(dir.c_str(), policy.c_str(), policy.length(), modes[0].c_str(), - modes.size() >= 2 ? modes[1].c_str() : "aes-256-cts"); + fscrypt_policy_ensure(dir.c_str(), key_ref.c_str(), key_ref.length(), + contents_mode.c_str(), filenames_mode.c_str(), policy_version); if (result) { LOG(ERROR) << android::base::StringPrintf("Setting %02x%02x%02x%02x policy on %s failed!", - policy[0], policy[1], policy[2], policy[3], + key_ref[0], key_ref[1], key_ref[2], key_ref[3], dir.c_str()); return -1; }