| // Copyright 2022 The ChromiumOS Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "libhwsec/middleware/middleware_owner.h" |
| |
| #include <memory> |
| #include <optional> |
| #include <utility> |
| |
| #include <base/functional/callback.h> |
| #include <base/functional/callback_helpers.h> |
| #include <base/logging.h> |
| #include <libhwsec-foundation/tpm/tpm_version.h> |
| |
| #include "base/files/file_path.h" |
| #include "libhwsec/backend/backend.h" |
| #include "libhwsec/middleware/middleware.h" |
| #include "libhwsec/proxy/proxy_impl.h" |
| #include "libhwsec/status.h" |
| |
| #if USE_TPM2 |
| #include "libhwsec/backend/tpm2/backend.h" |
| #endif |
| |
| #if USE_TPM1 |
| #include "libhwsec/backend/tpm1/backend.h" |
| #endif |
| |
| namespace { |
| constexpr char kThreadName[] = "libhwsec_thread"; |
| |
| // Location where we store the Low Entropy (LE) credential manager related |
| // state. |
| [[maybe_unused]] constexpr char kSignInHashTreeDir[] = |
| "/home/.shadow/low_entropy_creds"; |
| |
| scoped_refptr<base::TaskRunner> GetCurrentTaskRunnerOrNullptr() { |
| return base::SequencedTaskRunner::HasCurrentDefault() |
| ? base::SequencedTaskRunner::GetCurrentDefault() |
| : nullptr; |
| } |
| |
| // Use thread_local to ensure the metrics, proxy and backend could only be |
| // accessed on a thread. |
| ABSL_CONST_INIT static thread_local std::unique_ptr<hwsec::Metrics> metrics_; |
| ABSL_CONST_INIT static thread_local std::unique_ptr<hwsec::Proxy> proxy_; |
| ABSL_CONST_INIT static thread_local std::unique_ptr<hwsec::Backend> backend_; |
| |
| } // namespace |
| |
| namespace hwsec { |
| |
| MiddlewareOwner::MiddlewareOwner(ThreadingMode mode) { |
| InitThreadingMode(mode); |
| |
| base::OnceClosure task = |
| base::BindOnce(&MiddlewareOwner::InitBackend, weak_factory_.GetWeakPtr()); |
| Middleware(Derive()).RunBlockingTask(std::move(task)); |
| } |
| |
| MiddlewareOwner::MiddlewareOwner(std::unique_ptr<Backend> custom_backend, |
| ThreadingMode mode) { |
| InitThreadingMode(mode); |
| |
| base::OnceClosure task = |
| base::BindOnce(&MiddlewareOwner::InitWithCustomBackend, |
| weak_factory_.GetWeakPtr(), std::move(custom_backend)); |
| Middleware(Derive()).RunBlockingTask(std::move(task)); |
| } |
| |
| void MiddlewareOwner::InitThreadingMode(ThreadingMode mode) { |
| if (mode == ThreadingMode::kStandaloneWorkerThread) { |
| background_thread_ = std::make_unique<base::Thread>(kThreadName); |
| background_thread_->StartWithOptions( |
| base::Thread::Options(base::MessagePumpType::IO, 0)); |
| task_runner_ = background_thread_->task_runner(); |
| thread_id_ = background_thread_->GetThreadId(); |
| } else { |
| task_runner_ = GetCurrentTaskRunnerOrNullptr(); |
| thread_id_ = base::PlatformThread::CurrentId(); |
| } |
| } |
| |
| MiddlewareOwner::~MiddlewareOwner() { |
| // Post blocking task if we the backend thread had been initialized. |
| if (thread_id_ != base::kInvalidThreadId) { |
| base::OnceClosure task = base::BindOnce(&MiddlewareOwner::FiniBackend, |
| weak_factory_.GetWeakPtr()); |
| task = std::move(task).Then(base::BindOnce( |
| &base::WeakPtrFactory<MiddlewareOwner>::InvalidateWeakPtrs, |
| base::Unretained(&weak_factory_))); |
| Middleware(Derive()).RunBlockingTask(std::move(task)); |
| } |
| } |
| |
| MiddlewareDerivative MiddlewareOwner::Derive() { |
| return MiddlewareDerivative{ |
| .task_runner = task_runner_, |
| .thread_id = thread_id_, |
| .middleware = weak_factory_.GetWeakPtr(), |
| }; |
| } |
| |
| void MiddlewareOwner::InitBackend() { |
| CHECK(!backend_) << "Should not init backend twice."; |
| |
| if (thread_id_ == base::kInvalidThreadId) { |
| thread_id_ = base::PlatformThread::CurrentId(); |
| } |
| |
| metrics_ = std::make_unique<Metrics>(); |
| |
| TPM_SELECT_BEGIN; |
| TPM1_SECTION({ |
| auto proxy = std::make_unique<ProxyImpl>(); |
| if (!proxy->Init()) { |
| LOG(ERROR) << "Failed to init hwsec proxy"; |
| return; |
| } |
| proxy_ = std::move(proxy); |
| backend_ = std::make_unique<BackendTpm1>(*proxy_, Derive()); |
| }); |
| TPM2_SECTION({ |
| auto proxy = std::make_unique<ProxyImpl>(); |
| if (!proxy->Init()) { |
| LOG(ERROR) << "Failed to init hwsec proxy"; |
| return; |
| } |
| proxy_ = std::move(proxy); |
| backend_ = std::make_unique<BackendTpm2>( |
| *proxy_, Derive(), |
| /* pw_hash_tree_dir */ base::FilePath(kSignInHashTreeDir), |
| /* metrics */ metrics_.get()); |
| }); |
| OTHER_TPM_SECTION({ |
| LOG(ERROR) << "Calling on unsupported TPM platform."; |
| return; |
| }); |
| TPM_SELECT_END; |
| } |
| |
| void MiddlewareOwner::InitWithCustomBackend( |
| std::unique_ptr<Backend> custom_backend) { |
| CHECK(!backend_) << "Should not init backend twice."; |
| |
| if (thread_id_ == base::kInvalidThreadId) { |
| thread_id_ = base::PlatformThread::CurrentId(); |
| } |
| |
| // Note: The metrics and proxy is meaningless with the custom backend, so we |
| // don't init them here. |
| |
| backend_ = std::move(custom_backend); |
| } |
| |
| void MiddlewareOwner::FiniBackend() { |
| backend_.reset(); |
| proxy_.reset(); |
| metrics_.reset(); |
| } |
| |
| Metrics* MiddlewareOwner::GetMetrics() const { |
| return metrics_.get(); |
| } |
| |
| Proxy* MiddlewareOwner::GetProxy() const { |
| return proxy_.get(); |
| } |
| |
| Backend* MiddlewareOwner::GetBackend() const { |
| return backend_.get(); |
| } |
| |
| } // namespace hwsec |