blob: 44955668aef74cce2203222fa4591c3ef67fc785 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_DEVICES_BLOCK_DRIVERS_ZXCRYPT_DEVICE_MANAGER_H_
#define SRC_DEVICES_BLOCK_DRIVERS_ZXCRYPT_DEVICE_MANAGER_H_
#include <fidl/fuchsia.hardware.block.encrypted/cpp/wire.h>
#include <lib/ddk/device.h>
#include <stddef.h>
#include <stdint.h>
#include <zircon/compiler.h>
#include <zircon/types.h>
#include <ddktl/device.h>
#include <fbl/macros.h>
#include <fbl/mutex.h>
#include "lib/inspect/cpp/inspector.h"
#include "src/security/lib/zxcrypt/volume.h"
namespace zxcrypt {
class Device;
// |zxcrypt::DeviceManager| is a "wrapper" driver for zxcrypt volumes. Each block device with valid
// zxcrypt metadata will result in a wrapper being created, but the wrapper cannot perform any block
// operations. To perform block operations, |Unseal| must first be called with a valid key and
// slot, which will cause an unsealed |zxcrypt::Device| to be added to the device tree.
class DeviceManager;
using DeviceManagerType =
ddk::Device<DeviceManager, ddk::Unbindable,
ddk::Messageable<fuchsia_hardware_block_encrypted::DeviceManager>::Mixin,
ddk::ChildPreReleaseable>;
class DeviceManager final : public DeviceManagerType {
public:
explicit DeviceManager(zx_device_t* parent) : DeviceManagerType(parent), state_(kBinding) {}
~DeviceManager() = default;
DISALLOW_COPY_ASSIGN_AND_MOVE(DeviceManager);
static zx_status_t Create(void* ctx, zx_device_t* parent);
// Adds the device
zx_status_t Bind();
// ddk::Device methods; see ddktl/device.h
void DdkUnbind(ddk::UnbindTxn txn) __TA_EXCLUDES(mtx_);
void DdkRelease();
// ddk::ChildPreRelease methods
void DdkChildPreRelease(void* child_ctx) __TA_EXCLUDES(mtx_);
// Formats the zxcrypt volume, destroying any data contained therein, and
// enrolls the given key in the requested key slot. Leaves the device sealed.
void Format(FormatRequestView request, FormatCompleter::Sync& completer) __TA_EXCLUDES(mtx_);
// Unseals the zxcrypt volume and adds it as a |zxcrypt::Device| to the device tree.
void Unseal(UnsealRequestView request, UnsealCompleter::Sync& completer) __TA_EXCLUDES(mtx_);
// Removes the unsealed |zxcrypt::Device|, if present.
void Seal(SealCompleter::Sync& completer) __TA_EXCLUDES(mtx_);
// Clobbers the superblock (and any backup superblocks), preventing future
// Unseal operations from succeeding (provided no other program is
// manipulating the underlying block device).
void Shred(ShredCompleter::Sync& completer) __TA_EXCLUDES(mtx_);
private:
// Represents the state of this device. State transitions:
//
// kBinding is initial state
// kBinding -> kSealed on DdkAdd success
// kBinding -> kRemoved on DdkAdd failure
//
// kSealed -> kUnsealed if Unseal called with correct key
// kSealed -> kRemoved on DdkUnbind
//
// kUnsealed -> kSealing if Seal called
// kUnsealed -> kUnsealedShredded if Shred called
// kUnsealed -> kRemoved on DdkUnbind
//
// kSealing -> kSealed when DdkChildPreRelease hook called
// kSealing -> kRemoved on DdkUnbind
//
// kUnsealedShredded -> kSealing if Seal called
// kUnsealedShredded -> kRemoved on DdkUnbind
//
// kRemoved is terminal
enum State {
kBinding,
kSealed,
kUnsealed,
kUnsealedShredded,
kSealing,
kRemoved,
};
// Formats the zxcrypt volume, enrolling |ikm| in key slot |slot|. Keeps the
// device sealed.
zx_status_t FormatLocked(const uint8_t* ikm, size_t ikm_len, key_slot_t slot) __TA_REQUIRES(mtx_);
// Unseals the zxcrypt volume and adds it as a |zxcrypt::Device| to the device tree.
zx_status_t UnsealLocked(const uint8_t* ikm, size_t ikm_len, key_slot_t slot) __TA_REQUIRES(mtx_);
// Transition to the specified |state|.
void TransitionState(State state, std::optional<zxcrypt::Device*> child,
std::optional<SealCompleter::Async> seal_completer) __TA_REQUIRES(mtx_);
void TransitionState(State state, std::optional<zxcrypt::Device*> child) __TA_REQUIRES(mtx_);
void TransitionState(State state) __TA_REQUIRES(mtx_);
// Used to ensure calls to |Unseal|, |Seal|, and |Unbind| are exclusive to each
// other, and protects access to |state_|.
fbl::Mutex mtx_;
// Used for debug state.
inspect::Inspector inspect_;
// Child `unsealed` device, if present. Owned by device_manager, but it'll send us a
// ChildPreRelease hook notification before it destroys it.
std::optional<zxcrypt::Device*> child_ __TA_GUARDED(mtx_);
// A place to hold a FIDL transaction completer so we can asynchronously
// complete the transaction when device_manager confirms the removal of the
// child device.
std::optional<SealCompleter::Async> seal_completer_ __TA_GUARDED(mtx_);
State state_ __TA_GUARDED(mtx_);
};
} // namespace zxcrypt
#endif // SRC_DEVICES_BLOCK_DRIVERS_ZXCRYPT_DEVICE_MANAGER_H_