blob: 78a7a65e0d26db0b187eaa6dfe63d094277972fb [file] [log] [blame]
// Copyright 2019 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This file contains assorted functions used in mount-related classed.
#include "cryptohome/storage/mount_utils.h"
#include <linux/magic.h>
#include <sys/types.h>
#include <sys/vfs.h>
#include <sys/wait.h>
#include <unistd.h>
#include <unordered_map>
#include <vector>
#include <base/files/file_util.h>
#include <base/logging.h>
#include <chromeos/constants/cryptohome.h>
#include "cryptohome/crypto_error.h"
namespace {
// Size of span when writing protobuf message size to file.
constexpr int kSpanSize = 1;
} // namespace
namespace cryptohome {
bool UserSessionMountNamespaceExists() {
struct statfs buff;
if (statfs(kUserSessionMountNamespacePath, &buff) == 0) {
if (static_cast<uint64_t>(buff.f_type) != NSFS_MAGIC) {
LOG(ERROR) << kUserSessionMountNamespacePath
<< " is not a namespace file, has the user session namespace "
"been created?";
return false;
}
} else {
PLOG(ERROR) << "statfs(" << kUserSessionMountNamespacePath << ") failed";
return false;
}
return true;
}
bool ReadProtobuf(int in_fd, google::protobuf::MessageLite* message) {
size_t proto_size = 0;
if (!base::ReadFromFD(in_fd, reinterpret_cast<char*>(&proto_size),
sizeof(proto_size))) {
PLOG(ERROR) << "Failed to read protobuf size";
return false;
}
std::vector<char> buf(proto_size);
if (!base::ReadFromFD(in_fd, buf.data(), buf.size())) {
PLOG(ERROR) << "Failed to read protobuf";
return false;
}
if (!message->ParseFromArray(buf.data(), buf.size())) {
LOG(ERROR) << "Failed to parse protobuf";
return false;
}
return true;
}
bool WriteProtobuf(int out_fd, const google::protobuf::MessageLite& message) {
size_t size = message.ByteSizeLong();
if (!base::WriteFileDescriptor(
out_fd, base::as_bytes(base::make_span(&size, kSpanSize)))) {
PLOG(ERROR) << "Failed to write protobuf size";
return false;
}
if (!message.SerializeToFileDescriptor(out_fd)) {
LOG(ERROR) << "Failed to serialize and write protobuf";
return false;
}
return true;
}
void ForkAndCrash(const std::string& message) {
pid_t child_pid = fork();
if (child_pid < 0) {
PLOG(ERROR) << "fork() failed";
} else if (child_pid == 0) {
// Child process: crash with |message|.
LOG(FATAL) << message;
} else {
// |child_pid| > 0
// Parent process: reap the child process in a best-effort way and return
// normally.
waitpid(child_pid, nullptr, 0);
}
}
user_data_auth::CryptohomeErrorCode CryptoErrorToCryptohomeError(
const CryptoError code) {
return MountErrorToCryptohomeError(CryptoErrorToMountError(code));
}
MountError CryptoErrorToMountError(CryptoError crypto_error) {
MountError local_error = MOUNT_ERROR_NONE;
switch (crypto_error) {
case CryptoError::CE_TPM_FATAL:
case CryptoError::CE_OTHER_FATAL:
local_error = MOUNT_ERROR_VAULT_UNRECOVERABLE;
break;
case CryptoError::CE_TPM_COMM_ERROR:
local_error = MOUNT_ERROR_TPM_COMM_ERROR;
break;
case CryptoError::CE_TPM_DEFEND_LOCK:
local_error = MOUNT_ERROR_TPM_DEFEND_LOCK;
break;
case CryptoError::CE_TPM_REBOOT:
local_error = MOUNT_ERROR_TPM_NEEDS_REBOOT;
break;
default:
local_error = MOUNT_ERROR_KEY_FAILURE;
break;
}
return local_error;
}
user_data_auth::CryptohomeErrorCode MountErrorToCryptohomeError(
const MountError code) {
static const std::unordered_map<MountError,
user_data_auth::CryptohomeErrorCode>
error_code_lut = {
{MOUNT_ERROR_NONE, user_data_auth::CRYPTOHOME_ERROR_NOT_SET},
{MOUNT_ERROR_FATAL, user_data_auth::CRYPTOHOME_ERROR_MOUNT_FATAL},
{MOUNT_ERROR_KEY_FAILURE,
user_data_auth::CRYPTOHOME_ERROR_AUTHORIZATION_KEY_FAILED},
{MOUNT_ERROR_MOUNT_POINT_BUSY,
user_data_auth::CRYPTOHOME_ERROR_MOUNT_MOUNT_POINT_BUSY},
{MOUNT_ERROR_TPM_COMM_ERROR,
user_data_auth::CRYPTOHOME_ERROR_TPM_COMM_ERROR},
{MOUNT_ERROR_UNPRIVILEGED_KEY,
user_data_auth::CRYPTOHOME_ERROR_AUTHORIZATION_KEY_DENIED},
{MOUNT_ERROR_TPM_DEFEND_LOCK,
user_data_auth::CRYPTOHOME_ERROR_TPM_DEFEND_LOCK},
{MOUNT_ERROR_TPM_UPDATE_REQUIRED,
user_data_auth::CRYPTOHOME_ERROR_TPM_UPDATE_REQUIRED},
{MOUNT_ERROR_USER_DOES_NOT_EXIST,
user_data_auth::CRYPTOHOME_ERROR_ACCOUNT_NOT_FOUND},
{MOUNT_ERROR_TPM_NEEDS_REBOOT,
user_data_auth::CRYPTOHOME_ERROR_TPM_NEEDS_REBOOT},
{MOUNT_ERROR_OLD_ENCRYPTION,
user_data_auth::CRYPTOHOME_ERROR_MOUNT_OLD_ENCRYPTION},
{MOUNT_ERROR_PREVIOUS_MIGRATION_INCOMPLETE,
user_data_auth::
CRYPTOHOME_ERROR_MOUNT_PREVIOUS_MIGRATION_INCOMPLETE},
{MOUNT_ERROR_RECREATED, user_data_auth::CRYPTOHOME_ERROR_NOT_SET},
{MOUNT_ERROR_VAULT_UNRECOVERABLE,
user_data_auth::CRYPTOHOME_ERROR_VAULT_UNRECOVERABLE}};
if (error_code_lut.count(code) != 0) {
return error_code_lut.at(code);
}
return user_data_auth::CRYPTOHOME_ERROR_MOUNT_FATAL;
}
} // namespace cryptohome