blob: d01869624261475ff8ab17f8c5d919fafdbda1a7 [file] [log] [blame] [edit]
// Copyright 2021 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "init/utils.h"
#include <selinux/restorecon.h>
#include <selinux/selinux.h>
#include <algorithm>
#include <string>
#include <vector>
#include <base/files/file_path.h>
#include <base/files/file_util.h>
#include <base/logging.h>
#include <base/strings/string_number_conversions.h>
#include <base/strings/string_util.h>
#include <brillo/process/process.h>
#include <rootdev/rootdev.h>
namespace {
// A callback function for SELinux restorecon.
PRINTF_FORMAT(2, 3)
int RestoreConLogCallback(int type, const char* fmt, ...) {
va_list ap;
std::string message = "restorecon: ";
va_start(ap, fmt);
message += base::StringPrintV(fmt, ap);
va_end(ap);
// This already has a line feed at the end, so trim it off to avoid
// empty lines in the log.
base::TrimString(message, "\r\n", &message);
if (type == SELINUX_INFO)
LOG(INFO) << message;
else
LOG(ERROR) << message;
return 0;
}
} // namespace
namespace utils {
// |strip_partition| attempts to remove the partition number from the result.
bool GetRootDevice(base::FilePath* root, bool strip_partition) {
char buf[PATH_MAX];
int ret = rootdev(buf, PATH_MAX, true, strip_partition);
if (ret == 0) {
*root = base::FilePath(buf);
} else {
*root = base::FilePath();
}
return !ret;
}
bool ReadFileToInt(const base::FilePath& path, int* value) {
std::string str;
if (!base::ReadFileToString(path, &str)) {
return false;
}
base::TrimWhitespaceASCII(str, base::TRIM_ALL, &str);
return base::StringToInt(str, value);
}
bool CreateEncryptedRebootVault() {
brillo::ProcessImpl create_erv;
create_erv.AddArg("/usr/sbin/encrypted-reboot-vault");
create_erv.AddArg("--action=create");
if (create_erv.Run() != 0) {
return false;
}
return true;
}
bool UnlockEncryptedRebootVault() {
brillo::ProcessImpl unlock_erv;
unlock_erv.AddArg("/usr/sbin/encrypted-reboot-vault");
unlock_erv.AddArg("--action=unlock");
if (unlock_erv.Run() != 0) {
return false;
}
return true;
}
void Reboot() {
brillo::ProcessImpl proc;
proc.AddArg("/sbin/shutdown");
proc.AddArg("-r");
proc.AddArg("now");
int ret = proc.Run();
if (ret == 0) {
// Wait for reboot to finish (it's an async call).
sleep(60 * 60 * 24);
}
// If we've reached here, reboot (probably) failed.
LOG(ERROR) << "Requesting reboot failed with failure code " << ret;
}
void Restorecon(const base::FilePath& path,
const std::vector<base::FilePath>& exclude,
bool is_recursive,
bool set_digests) {
union selinux_callback cb;
cb.func_log = RestoreConLogCallback;
selinux_set_callback(SELINUX_CB_LOG, cb);
if (!exclude.empty()) {
std::vector<const char*> exclude_cstring(exclude.size());
std::transform(exclude.begin(), exclude.end(), exclude_cstring.begin(),
[](const base::FilePath& path) -> const char* {
return path.value().c_str();
});
exclude_cstring.push_back(NULL);
// We need to exclude directories because restoring context could
// mislabel files if the encrypted filename happens to match something
// or could increase boot time.
selinux_restorecon_set_exclude_list(exclude_cstring.data());
}
const unsigned int recurse_flags =
(set_digests
? SELINUX_RESTORECON_RECURSE
: SELINUX_RESTORECON_RECURSE | SELINUX_RESTORECON_SKIP_DIGEST);
const unsigned int base_flags =
(is_recursive ? recurse_flags : 0) | SELINUX_RESTORECON_REALPATH;
selinux_restorecon(path.value().c_str(), base_flags);
}
} // namespace utils