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
This commit is contained in:
Eric Biggers 2019-09-13 10:54:53 -07:00
parent d964376a92
commit eaadc9d426
1 changed files with 39 additions and 12 deletions

View File

@ -28,6 +28,7 @@
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <cutils/properties.h>
@ -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<std::string> 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;
}