Move encrypted directories into place already-encrypted
Even after having changed the SELinux policy to remove system_server's permission to create directories like /data/system_ce/10, there's still a very small loophole where system_server can create a subdirectory after vold creates the directory but before vold assigns an encryption policy to it. This isn't known to have actually happened (b/285239971 was a candidate, but it seems to have actually been caused by SELinux being in permissive mode), but it's theoretically possible. Close this loophole by making vold create encrypted directories under temporary names and move them into place once they are fully prepared. Bug: 156305599 Bug: 285239971 Test: Cuttlefish boots, and can be rebooted. Change-Id: I53407c938bab02ab4b7e5bab8402f36eb47fb203
This commit is contained in:
parent
39f11368a5
commit
c6f004a9c4
1 changed files with 31 additions and 2 deletions
33
FsCrypt.cpp
33
FsCrypt.cpp
|
@ -323,8 +323,37 @@ static bool prepare_dir(const std::string& dir, mode_t mode, uid_t uid, gid_t gi
|
|||
// Prepare a directory and assign it the given encryption policy.
|
||||
static bool prepare_dir_with_policy(const std::string& dir, mode_t mode, uid_t uid, gid_t gid,
|
||||
const EncryptionPolicy& policy) {
|
||||
if (!prepare_dir(dir, mode, uid, gid)) return false;
|
||||
if (IsFbeEnabled() && !EnsurePolicy(policy, dir)) return false;
|
||||
if (android::vold::pathExists(dir)) {
|
||||
if (!prepare_dir(dir, mode, uid, gid)) return false;
|
||||
if (IsFbeEnabled() && !EnsurePolicy(policy, dir)) return false;
|
||||
} else {
|
||||
// If the directory does not yet exist, then create it under a temporary name, and only move
|
||||
// it to the final name after it is fully prepared with an encryption policy and the desired
|
||||
// file permissions. This prevents the directory from being accessed before it is ready.
|
||||
//
|
||||
// Note: this relies on the SELinux file_contexts assigning the same type to the file path
|
||||
// with the ".new" suffix as to the file path without the ".new" suffix.
|
||||
|
||||
const std::string tmp_dir = dir + ".new";
|
||||
if (android::vold::pathExists(tmp_dir)) {
|
||||
android::vold::DeleteDirContentsAndDir(tmp_dir);
|
||||
}
|
||||
if (!prepare_dir(tmp_dir, mode, uid, gid)) return false;
|
||||
if (IsFbeEnabled() && !EnsurePolicy(policy, tmp_dir)) return false;
|
||||
|
||||
// On some buggy kernels, renaming a directory that is both encrypted and case-insensitive
|
||||
// fails in some specific circumstances. Unfortunately, these circumstances happen here
|
||||
// when processing the "media" directory. This was already fixed by kernel commit
|
||||
// https://git.kernel.org/linus/b5639bb4313b9d45 ('f2fs: don't use casefolded comparison for
|
||||
// "." and ".."'). But to support kernels that lack that fix, we use the below workaround.
|
||||
// It bypasses the bug by making the encryption key of tmp_dir be loaded before the rename.
|
||||
android::vold::pathExists(tmp_dir + "/subdir");
|
||||
|
||||
if (rename(tmp_dir.c_str(), dir.c_str()) != 0) {
|
||||
PLOG(ERROR) << "Failed to rename " << tmp_dir << " to " << dir;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue