/* * 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_init_extensions.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define TAG "fscrypt" using namespace android::fscrypt; bool FscryptInstallKeyring() { if (keyctl_search(KEY_SPEC_SESSION_KEYRING, "keyring", "fscrypt", 0) != -1) { LOG(INFO) << "Keyring is already created"; return true; } 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 false; } LOG(INFO) << "Keyring created with id " << device_keyring << " in process " << getpid(); return true; } // TODO(b/139378601): use a single central implementation of this. static void delete_dir_contents(const std::string& dir) { char* const paths[2] = {const_cast(dir.c_str()), nullptr}; FTS* fts = fts_open(paths, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr); FTSENT* cur; while ((cur = fts_read(fts)) != nullptr) { if (cur->fts_info == FTS_ERR) { PLOG(ERROR) << "fts_read"; break; } if (dir == cur->fts_path) { continue; } switch (cur->fts_info) { case FTS_D: break; // Ignore these case FTS_DP: if (rmdir(cur->fts_path) == -1) { PLOG(ERROR) << "rmdir " << cur->fts_path; } break; default: PLOG(ERROR) << "FTS unexpected type " << cur->fts_info << " at " << cur->fts_path; if (rmdir(cur->fts_path) != -1) break; // FALLTHRU (for gcc, lint, pcc, etc; and following for clang) FALLTHROUGH_INTENDED; case FTS_F: case FTS_SL: case FTS_SLNONE: if (unlink(cur->fts_path) == -1) { PLOG(ERROR) << "unlink " << cur->fts_path; } break; } } if (fts_close(fts) != 0) { PLOG(ERROR) << "fts_close"; } } // Look up an encryption policy The policy (key reference // and encryption options) to use is read from files that were written by vold. static bool LookupPolicy(const std::string& ref_basename, EncryptionPolicy* policy) { std::string ref_filename = std::string("/data") + ref_basename; if (!android::base::ReadFileToString(ref_filename, &policy->key_raw_ref)) { LOG(ERROR) << "Unable to read system policy with name " << ref_filename; return false; } 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 false; } if (!ParseOptions(options_string, &policy->options)) { LOG(ERROR) << "Invalid encryption options string: " << options_string; return false; } return true; } static bool EnsurePolicyOrLog(const EncryptionPolicy& policy, const std::string& dir) { if (!EnsurePolicy(policy, dir)) { std::string ref_hex; BytesToHex(policy.key_raw_ref, &ref_hex); LOG(ERROR) << "Setting " << ref_hex << " policy on " << dir << " failed!"; return false; } return true; } static bool SetPolicyOn(const std::string& ref_basename, const std::string& dir) { EncryptionPolicy policy; if (!LookupPolicy(ref_basename, &policy)) return false; if (!EnsurePolicyOrLog(policy, dir)) return false; return true; } bool FscryptSetDirectoryPolicy(const std::string& ref_basename, FscryptAction action, const std::string& dir) { if (action == FscryptAction::kNone) { return true; } if (SetPolicyOn(ref_basename, dir) || action == FscryptAction::kAttempt) { return true; } if (action == FscryptAction::kDeleteIfNecessary) { LOG(ERROR) << "Setting policy failed, deleting: " << dir; delete_dir_contents(dir); return SetPolicyOn(ref_basename, dir); } return false; }