| // Copyright 2023 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/startup/uefi_startup.h" | |
| #include <fcntl.h> | |
| #include <sys/mount.h> | |
| // The include for sys/mount.h must come before this. | |
| #include <linux/fs.h> | |
| #include <base/files/file_util.h> | |
| #include <base/logging.h> | |
| #include <brillo/userdb_utils.h> | |
| #include "init/startup/constants.h" | |
| #include "init/startup/uefi_startup_impl.h" | |
| #include "init/utils.h" | |
| namespace startup { | |
| std::unique_ptr<UefiDelegate> UefiDelegate::Create( | |
| libstorage::Platform* platform, const base::FilePath& root_dir) { | |
| return std::make_unique<UefiDelegateImpl>(platform, root_dir); | |
| } | |
| UefiDelegate::~UefiDelegate() = default; | |
| UefiDelegateImpl::UefiDelegateImpl(libstorage::Platform* platform, | |
| const base::FilePath& root_dir) | |
| : platform_(platform), root_dir_(root_dir) {} | |
| bool UefiDelegateImpl::IsUefiEnabled() const { | |
| return platform_->DirectoryExists(root_dir_.Append(kSysEfiDir)); | |
| } | |
| std::optional<UefiDelegate::UserAndGroup> | |
| UefiDelegateImpl::GetFwupdUserAndGroup() const { | |
| UserAndGroup fwupd; | |
| if (!brillo::userdb::GetUserInfo("fwupd", &fwupd.uid, nullptr)) { | |
| return std::nullopt; | |
| } | |
| if (!brillo::userdb::GetGroupInfo("fwupd", &fwupd.gid)) { | |
| return std::nullopt; | |
| } | |
| return fwupd; | |
| } | |
| bool UefiDelegateImpl::MountEfivarfs(const UserAndGroup& fwupd) { | |
| const base::FilePath efivars_dir = root_dir_.Append(kEfivarsDir); | |
| const std::string data = | |
| "uid=" + std::to_string(fwupd.uid) + ",gid=" + std::to_string(fwupd.gid); | |
| if (!platform_->Mount(/*from=*/base::FilePath(), | |
| /*to=*/efivars_dir, | |
| /*type=*/kFsTypeEfivarfs, | |
| /*mount_flags=*/kCommonMountFlags, | |
| /*mount_options=*/data)) { | |
| PLOG(WARNING) << "Unable to mount " << efivars_dir; | |
| return false; | |
| } | |
| return true; | |
| } | |
| bool UefiDelegateImpl::MakeUefiVarMutable(const std::string& vendor, | |
| const std::string& name) { | |
| const base::FilePath var_path = | |
| root_dir_.Append(kEfivarsDir).Append(name + '-' + vendor); | |
| return platform_->SetExtFileAttributes(var_path, 0, FS_IMMUTABLE_FL); | |
| } | |
| void UefiDelegateImpl::MakeEsrtReadableByFwupd(const UserAndGroup& fwupd) { | |
| const base::FilePath esrt_dir = root_dir_.Append(kSysEfiDir).Append("esrt"); | |
| std::unique_ptr<libstorage::FileEnumerator> file_enumerator( | |
| platform_->GetFileEnumerator( | |
| esrt_dir, /*recursive=*/true, | |
| base::FileEnumerator::DIRECTORIES | base::FileEnumerator::FILES)); | |
| for (base::FilePath path = file_enumerator->Next(); !path.empty(); | |
| path = file_enumerator->Next()) { | |
| if (!platform_->SetOwnership(path, fwupd.uid, fwupd.gid, | |
| false /* follow_links */)) { | |
| PLOG(WARNING) << "Failed to change ownership of " << path << " to " | |
| << fwupd.uid << ":" << fwupd.gid; | |
| } | |
| } | |
| } | |
| void MaybeRunUefiStartup(UefiDelegate& uefi_delegate) { | |
| if (!uefi_delegate.IsUefiEnabled()) { | |
| return; | |
| } | |
| const auto fwupd = uefi_delegate.GetFwupdUserAndGroup(); | |
| if (!fwupd.has_value()) { | |
| LOG(WARNING) << "Failed to get fwupd user or group"; | |
| return; | |
| } | |
| if (uefi_delegate.MountEfivarfs(fwupd.value())) { | |
| uefi_delegate.MakeUefiVarMutable(kEfiImageSecurityDatabaseGuid, "dbx"); | |
| } | |
| uefi_delegate.MakeEsrtReadableByFwupd(fwupd.value()); | |
| } | |
| } // namespace startup |