blob: 209ba5ea4fb238845d34ec946fc41d9b514e1371 [file] [log] [blame]
// Copyright 2017 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.
#include "imageloader/imageloader.h"
#include <libminijail.h>
#include <scoped_minijail.h>
#include <sysexits.h>
#include <string>
#include <utility>
#include <base/files/file_path.h>
#include <base/threading/thread_task_runner_handle.h>
#include <chromeos/dbus/service_constants.h>
namespace imageloader {
namespace {
constexpr char kSeccompFilterPath[] =
"/usr/share/policy/imageloader-seccomp.policy";
} // namespace
// static
const char ImageLoader::kImageLoaderGroupName[] = "imageloaderd";
const char ImageLoader::kImageLoaderUserName[] = "imageloaderd";
const int ImageLoader::kShutdownTimeoutMilliseconds = 20000;
const char ImageLoader::kLoadedMountsBase[] = "/run/imageloader";
ImageLoader::ImageLoader(ImageLoaderConfig config,
std::unique_ptr<HelperProcessProxy> proxy)
: DBusServiceDaemon(kImageLoaderServiceName),
impl_(std::move(config)),
helper_process_proxy_(std::move(proxy)) {}
ImageLoader::~ImageLoader() = default;
// static
void ImageLoader::EnterSandbox() {
ScopedMinijail jail(minijail_new());
minijail_no_new_privs(jail.get());
minijail_use_seccomp_filter(jail.get());
minijail_parse_seccomp_filters(jail.get(), kSeccompFilterPath);
minijail_reset_signal_mask(jail.get());
minijail_namespace_ipc(jail.get());
minijail_namespace_net(jail.get());
minijail_remount_proc_readonly(jail.get());
CHECK_EQ(0, minijail_change_user(jail.get(), kImageLoaderUserName));
CHECK_EQ(0, minijail_change_group(jail.get(), kImageLoaderGroupName));
minijail_enter(jail.get());
}
int ImageLoader::OnInit() {
// Run with minimal privileges.
EnterSandbox();
int return_code = brillo::DBusServiceDaemon::OnInit();
if (return_code != EX_OK)
return return_code;
process_reaper_.Register(this);
process_reaper_.WatchForChild(
FROM_HERE, helper_process_proxy_->pid(),
base::Bind(&ImageLoader::OnSubprocessExited, weak_factory_.GetWeakPtr(),
helper_process_proxy_->pid()));
PostponeShutdown();
return EX_OK;
}
void ImageLoader::RegisterDBusObjectsAsync(
brillo::dbus_utils::AsyncEventSequencer* sequencer) {
dbus_object_.reset(new brillo::dbus_utils::DBusObject(
nullptr, bus_,
org::chromium::ImageLoaderInterfaceAdaptor::GetObjectPath()));
dbus_adaptor_.RegisterWithDBusObject(dbus_object_.get());
dbus_object_->RegisterAsync(
sequencer->GetHandler("ImageLoader.RegisterAsync() failed.", true));
}
void ImageLoader::OnShutdown(int* return_code) {
brillo::DBusServiceDaemon::OnShutdown(return_code);
}
void ImageLoader::OnSubprocessExited(pid_t pid, const siginfo_t& info) {
LOG(FATAL) << "Subprocess " << pid << " exited unexpectedly.";
}
void ImageLoader::PostponeShutdown() {
shutdown_callback_.Reset(
base::Bind(&brillo::Daemon::Quit, base::Unretained(this)));
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE, shutdown_callback_.callback(),
base::TimeDelta::FromMilliseconds(kShutdownTimeoutMilliseconds));
}
bool ImageLoader::RegisterComponent(
brillo::ErrorPtr* err,
const std::string& name,
const std::string& version,
const std::string& component_folder_abs_path,
bool* out_success) {
*out_success =
impl_.RegisterComponent(name, version, component_folder_abs_path);
PostponeShutdown();
return true;
}
bool ImageLoader::GetComponentVersion(brillo::ErrorPtr* err,
const std::string& name,
std::string* out_version) {
*out_version = impl_.GetComponentVersion(name);
PostponeShutdown();
return true;
}
bool ImageLoader::LoadComponent(brillo::ErrorPtr* err,
const std::string& name,
std::string* out_mount_point) {
*out_mount_point = impl_.LoadComponent(name, helper_process_proxy_.get());
PostponeShutdown();
return true;
}
bool ImageLoader::LoadComponentAtPath(brillo::ErrorPtr* err,
const std::string& name,
const std::string& absolute_path,
std::string* out_mount_point) {
*out_mount_point = impl_.LoadComponentAtPath(
name, base::FilePath(absolute_path), helper_process_proxy_.get());
PostponeShutdown();
return true;
}
bool ImageLoader::LoadDlcImage(brillo::ErrorPtr* err,
const std::string& id,
const std::string& package,
const std::string& a_or_b,
std::string* out_mount_point) {
*out_mount_point =
impl_.LoadDlcImage(id, package, a_or_b, helper_process_proxy_.get());
PostponeShutdown();
return true;
}
bool ImageLoader::RemoveComponent(brillo::ErrorPtr* err,
const std::string& name,
bool* out_success) {
*out_success = impl_.RemoveComponent(name);
PostponeShutdown();
return true;
}
bool ImageLoader::GetComponentMetadata(
brillo::ErrorPtr* err,
const std::string& name,
std::map<std::string, std::string>* out_metadata) {
if (!impl_.GetComponentMetadata(name, out_metadata))
out_metadata->clear();
PostponeShutdown();
return true;
}
bool ImageLoader::UnmountComponent(brillo::ErrorPtr* err,
const std::string& name,
bool* out_success) {
base::FilePath component_mount_root =
base::FilePath(imageloader::ImageLoader::kLoadedMountsBase).Append(name);
*out_success = impl_.CleanupAll(false, component_mount_root, nullptr,
helper_process_proxy_.get());
PostponeShutdown();
return true;
}
bool ImageLoader::UnloadDlcImage(brillo::ErrorPtr* err,
const std::string& id,
const std::string& package,
bool* out_success) {
*out_success = impl_.UnloadDlcImage(id, package, helper_process_proxy_.get());
PostponeShutdown();
return true;
}
} // namespace imageloader