Skip to content

Commit

Permalink
Add syncs when creating parent directories
Browse files Browse the repository at this point in the history
vold creates some directories for storing encryption keys if they don't
already exist, potentially including parent directories:

    /metadata/vold/metadata_encryption
    /data/misc/vold/volume_keys/$volume_uuid
    /data/misc_de/$user/vold/volume_keys/$volume_uuid
    /data/misc_ce/$user/vold/volume_keys/$volume_uuid

Currently fs_mkdirs() is used for this.  However, fs_mkdirs() doesn't
include the fsync()s of the parent directories that are needed to ensure
that the new directories are persisted to disk right away -- which is
important for encryption keys.

Add a utility function MkdirsSync() which does what is needed, and make
the appropriate places call it.

Test: Booted and checked log for "Created directory" message.
      Also ran 'atest vold_tests' to run the new unit test.
Change-Id: Ie9917b616433080139b8db3fd6877203ee6faf77
  • Loading branch information
ebiggers committed Feb 17, 2021
1 parent 3345a2a commit fec0c0e
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 12 deletions.
10 changes: 2 additions & 8 deletions FsCrypt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -652,18 +652,12 @@ static bool read_or_create_volkey(const std::string& misc_path, const std::strin
if (!android::vold::readSecdiscardable(secdiscardable_path, &secdiscardable_hash))
return false;
} else {
if (fs_mkdirs(secdiscardable_path.c_str(), 0700) != 0) {
PLOG(ERROR) << "Creating directories for: " << secdiscardable_path;
return false;
}
if (!android::vold::MkdirsSync(secdiscardable_path, 0700)) return false;
if (!android::vold::createSecdiscardable(secdiscardable_path, &secdiscardable_hash))
return false;
}
auto key_path = volkey_path(misc_path, volume_uuid);
if (fs_mkdirs(key_path.c_str(), 0700) != 0) {
PLOG(ERROR) << "Creating directories for: " << key_path;
return false;
}
if (!android::vold::MkdirsSync(key_path, 0700)) return false;
android::vold::KeyAuthentication auth("", secdiscardable_hash);

EncryptionOptions options;
Expand Down
5 changes: 1 addition & 4 deletions MetadataCrypt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,7 @@ static bool read_key(const std::string& metadata_key_dir, const KeyGeneration& g
std::string sKey;
auto dir = metadata_key_dir + "/key";
LOG(DEBUG) << "metadata_key_dir/key: " << dir;
if (fs_mkdirs(dir.c_str(), 0700)) {
PLOG(ERROR) << "Creating directories: " << dir;
return false;
}
if (!MkdirsSync(dir, 0700)) return false;
auto temp = metadata_key_dir + "/tmp";
return retrieveOrGenerateKey(dir, temp, kEmptyAuthentication, gen, key);
}
Expand Down
30 changes: 30 additions & 0 deletions Utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1375,6 +1375,36 @@ bool FsyncParentDirectory(const std::string& path) {
return FsyncDirectory(android::base::Dirname(path));
}

// Creates all parent directories of |path| that don't already exist. Assigns
// the specified |mode| to any new directories, and also fsync()s their parent
// directories so that the new directories get written to disk right away.
bool MkdirsSync(const std::string& path, mode_t mode) {
if (path[0] != '/') {
LOG(ERROR) << "MkdirsSync() needs an absolute path, but got " << path;
return false;
}
std::vector<std::string> components = android::base::Split(android::base::Dirname(path), "/");

std::string current_dir = "/";
for (const std::string& component : components) {
if (component.empty()) continue;

std::string parent_dir = current_dir;
if (current_dir != "/") current_dir += "/";
current_dir += component;

if (!pathExists(current_dir)) {
if (mkdir(current_dir.c_str(), mode) != 0) {
PLOG(ERROR) << "Failed to create " << current_dir;
return false;
}
if (!FsyncDirectory(parent_dir)) return false;
LOG(DEBUG) << "Created directory " << current_dir;
}
}
return true;
}

bool writeStringToFile(const std::string& payload, const std::string& filename) {
android::base::unique_fd fd(TEMP_FAILURE_RETRY(
open(filename.c_str(), O_WRONLY | O_CREAT | O_NOFOLLOW | O_TRUNC | O_CLOEXEC, 0666)));
Expand Down
2 changes: 2 additions & 0 deletions Utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,8 @@ bool FsyncDirectory(const std::string& dirname);

bool FsyncParentDirectory(const std::string& path);

bool MkdirsSync(const std::string& path, mode_t mode);

bool writeStringToFile(const std::string& payload, const std::string& filename);

void ConfigureMaxDirtyRatioForFuse(const std::string& fuse_mount, unsigned int max_ratio);
Expand Down
19 changes: 19 additions & 0 deletions tests/Utils_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* limitations under the License.
*/

#include <android-base/file.h>
#include <gtest/gtest.h>

#include "../Utils.h"
Expand Down Expand Up @@ -43,5 +44,23 @@ TEST_F(UtilsTest, FindValueTest) {
ASSERT_EQ("QUUX", tmp);
}

TEST_F(UtilsTest, MkdirsSyncTest) {
TemporaryDir temp_dir;
std::string temp_dir_path;

ASSERT_TRUE(android::base::Realpath(temp_dir.path, &temp_dir_path));

ASSERT_FALSE(pathExists(temp_dir_path + "/a"));
ASSERT_TRUE(MkdirsSync(temp_dir_path + "/a/b/c", 0700));
ASSERT_TRUE(pathExists(temp_dir_path + "/a"));
ASSERT_TRUE(pathExists(temp_dir_path + "/a/b"));
// The final component of the path should not be created; only the previous
// components should be.
ASSERT_FALSE(pathExists(temp_dir_path + "/a/b/c"));

// Currently, MkdirsSync() only supports absolute paths.
ASSERT_FALSE(MkdirsSync("foo", 0700));
}

} // namespace vold
} // namespace android

0 comments on commit fec0c0e

Please sign in to comment.