blob: 1d293df956a5bf659b3497810068420518d675dc [file] [log] [blame] [edit]
// 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 "secagentd/secagent.h"
#include <unistd.h>
#include <cstdlib>
#include <iomanip>
#include <memory>
#include <string>
#include <sysexits.h>
#include <utility>
#include "absl/status/status.h"
#include "attestation-client/attestation/dbus-proxies.h"
#include "base/functional/bind.h"
#include "base/functional/callback_forward.h"
#include "base/functional/callback_helpers.h"
#include "base/logging.h"
#include "base/memory/scoped_refptr.h"
#include "base/task/thread_pool/thread_pool_instance.h"
#include "brillo/daemons/daemon.h"
#include "brillo/daemons/dbus_daemon.h"
#include "missive/client/missive_client.h"
#include "secagentd/daemon.h"
#include "secagentd/message_sender.h"
#include "secagentd/metrics_sender.h"
#include "secagentd/plugins.h"
#include "secagentd/policies_features_broker.h"
#include "secagentd/process_cache.h"
namespace secagentd {
SecAgent::SecAgent(
base::OnceCallback<void(int)> quit_daemon_cb,
scoped_refptr<MessageSenderInterface> message_sender,
scoped_refptr<ProcessCacheInterface> process_cache,
scoped_refptr<DeviceUserInterface> device_user,
std::unique_ptr<PluginFactoryInterface> plugin_factory,
std::unique_ptr<org::chromium::AttestationProxyInterface> attestation_proxy,
std::unique_ptr<org::chromium::TpmManagerProxyInterface> tpm_proxy,
std::unique_ptr<feature::PlatformFeaturesInterface> platform_features,
bool bypass_policy_for_testing,
bool bypass_enq_ok_wait_for_testing,
uint32_t heartbeat_period_s,
uint32_t plugin_batch_interval_s)
: message_sender_(message_sender),
process_cache_(process_cache),
device_user_(device_user),
plugin_factory_(std::move(plugin_factory)),
attestation_proxy_(std::move(attestation_proxy)),
tpm_proxy_(std::move(tpm_proxy)),
platform_features_(std::move(platform_features)),
bypass_policy_for_testing_(bypass_policy_for_testing),
bypass_enq_ok_wait_for_testing_(bypass_enq_ok_wait_for_testing),
heartbeat_period_s_(heartbeat_period_s),
plugin_batch_interval_s_(plugin_batch_interval_s),
quit_daemon_cb_(std::move(quit_daemon_cb)),
weak_ptr_factory_(this) {
policies_features_broker_ = base::MakeRefCounted<PoliciesFeaturesBroker>(
std::make_unique<policy::PolicyProvider>(), std::move(platform_features_),
base::BindRepeating(&SecAgent::CheckPolicyAndFeature,
weak_ptr_factory_.GetWeakPtr()));
}
void SecAgent::Activate() {
absl::Status result = message_sender_->Initialize();
if (result != absl::OkStatus()) {
LOG(ERROR) << result.message();
std::move(quit_daemon_cb_).Run(EX_SOFTWARE);
return;
}
process_cache_->InitializeFilter();
// This will post a task to run CheckPolicyAndFeature.
policies_features_broker_->StartAndBlockForSync(
PoliciesFeaturesBroker::kDefaultPollDuration);
}
void SecAgent::CheckPolicyAndFeature() {
static bool first_visit = true;
bool xdr_reporting_policy =
policies_features_broker_->GetDeviceReportXDREventsPolicy() ||
bypass_policy_for_testing_;
bool xdr_reporting_feature = policies_features_broker_->GetFeature(
PoliciesFeaturesBroker::Feature::kCrOSLateBootSecagentdXDRReporting);
// If either policy is false do not report.
if (reporting_events_ && !(xdr_reporting_feature && xdr_reporting_policy)) {
LOG(INFO) << "Stopping event reporting and quitting. Policy: "
<< std::to_string(xdr_reporting_policy)
<< " Feature: " << std::to_string(xdr_reporting_feature);
reporting_events_ = false;
// Will exit and restart secagentd.
std::move(quit_daemon_cb_).Run(EX_OK);
return;
} else if (!reporting_events_ &&
(xdr_reporting_feature && xdr_reporting_policy)) {
LOG(INFO) << "Starting event reporting";
// This is emitted at most once per daemon lifetime.
MetricsSender::GetInstance().SendEnumMetricToUMA(metrics::kPolicy,
metrics::Policy::kEnabled);
reporting_events_ = true;
StartXDRReporting();
} else if (first_visit) {
LOG(INFO) << "Not reporting yet.";
LOG(INFO) << "DeviceReportXDREventsPolicy: " << xdr_reporting_policy
<< (bypass_policy_for_testing_ ? " (set by flag)" : "");
LOG(INFO) << "CrOSLateBootSecagentdXDRReporting: " << xdr_reporting_feature;
}
// Else do nothing until the next poll.
first_visit = false;
}
void SecAgent::StartXDRReporting() {
device_user_->RegisterSessionChangeHandler();
MetricsSender::GetInstance().InitBatchedMetrics();
using CbType = base::OnceCallback<void()>;
CbType cb_for_agent =
base::BindOnce(&SecAgent::RunPlugins, weak_ptr_factory_.GetWeakPtr());
CbType cb_for_now = base::DoNothing();
if (bypass_enq_ok_wait_for_testing_) {
std::swap(cb_for_agent, cb_for_now);
}
agent_plugin_ = plugin_factory_->CreateAgentPlugin(
message_sender_, device_user_, std::move(attestation_proxy_),
std::move(tpm_proxy_), std::move(cb_for_agent), heartbeat_period_s_);
if (!agent_plugin_) {
std::move(quit_daemon_cb_).Run(EX_SOFTWARE);
return;
}
absl::Status result = agent_plugin_->Activate();
if (!result.ok()) {
LOG(ERROR) << result.message();
std::move(quit_daemon_cb_).Run(EX_SOFTWARE);
return;
}
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, std::move(cb_for_now));
}
void SecAgent::RunPlugins() {
if (CreatePlugin(Types::Plugin::kProcess) != EX_OK) {
std::move(quit_daemon_cb_).Run(EX_SOFTWARE);
return;
}
for (auto& plugin : plugins_) {
absl::Status result = plugin->Activate();
if (!result.ok()) {
LOG(ERROR) << result.message();
std::move(quit_daemon_cb_).Run(EX_SOFTWARE);
return;
}
}
}
int SecAgent::CreatePlugin(Types::Plugin type) {
std::unique_ptr<PluginInterface> plugin;
switch (type) {
case Types::Plugin::kProcess: {
plugin = plugin_factory_->Create(
Types::Plugin::kProcess, message_sender_, process_cache_,
policies_features_broker_, device_user_, plugin_batch_interval_s_);
break;
}
default:
CHECK(false) << "Unsupported plugin type";
}
if (!plugin) {
return EX_SOFTWARE;
}
plugins_.push_back(std::move(plugin));
return EX_OK;
}
} // namespace secagentd