// 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.

#include <errno.h>
#include <fcntl.h>
#include <fuchsia/device/c/fidl.h>
#include <fuchsia/device/llcpp/fidl.h>
#include <fuchsia/hardware/block/c/fidl.h>
#include <fuchsia/hardware/block/encrypted/c/fidl.h>
#include <fuchsia/hardware/block/volume/c/fidl.h>
#include <inttypes.h>
#include <lib/fdio/cpp/caller.h>
#include <lib/fdio/directory.h>
#include <lib/fdio/fdio.h>
#include <lib/zircon-internal/debug.h>
#include <lib/zx/channel.h>
#include <unistd.h>
#include <zircon/status.h>

#include <memory>
#include <utility>

#include <fbl/auto_call.h>
#include <fbl/string_buffer.h>
#include <fbl/vector.h>
#include <ramdevice-client/ramdisk.h>  // Why does wait_for_device_at() come from here?

#include "src/security/kms-stateless/kms-stateless.h"
#include "src/security/zxcrypt/fdio-volume.h"
#include "src/security/zxcrypt/volume.h"

#define ZXDEBUG 0

namespace zxcrypt {

// The zxcrypt driver
const char* kDriverLib = "zxcrypt.so";

namespace {

// Null key should be 32 bytes.
const size_t kKeyLength = 32;
const char kHardwareKeyInfo[] = "zxcrypt";

// How many bytes to read from /boot/config/zxcrypt?
const size_t kMaxKeySourcePolicyLength = 32;
const char kZxcryptConfigFile[] = "/pkg/config/zxcrypt";

// Reads /boot/config/zxcrypt to determine what key source policy was selected for this product at
// build time.
//
// Returns ZX_OK and sets |out| to the appropriate KeySourcePolicy value if the file contents
// exactly match a known configuration value.
// Returns ZX_ERR_NOT_FOUND if the config file was not present
// Returns ZX_ERR_IO if the config file could not be read
// Returns ZX_ERR_BAD_STATE if the config value was not recognized.
zx_status_t SelectKeySourcePolicy(KeySourcePolicy* out) {
  fbl::unique_fd fd(open(kZxcryptConfigFile, O_RDONLY));
  if (!fd) {
    xprintf("zxcrypt: couldn't open %s\n", kZxcryptConfigFile);
    return ZX_ERR_NOT_FOUND;
  }

  char key_source_buf[kMaxKeySourcePolicyLength + 1];
  ssize_t len = read(fd.get(), key_source_buf, sizeof(key_source_buf) - 1);
  if (len < 0) {
    xprintf("zxcrypt: couldn't read %s\n", kZxcryptConfigFile);
    return ZX_ERR_IO;
  } else {
    // add null terminator
    key_source_buf[len] = '\0';
    // Dispatch if recognized
    if (strcmp(key_source_buf, "null") == 0) {
      *out = NullSource;
      return ZX_OK;
    }
    if (strcmp(key_source_buf, "tee") == 0) {
      *out = TeeRequiredSource;
      return ZX_OK;
    }
    if (strcmp(key_source_buf, "tee-transitional") == 0) {
      *out = TeeTransitionalSource;
      return ZX_OK;
    }
    if (strcmp(key_source_buf, "tee-opportunistic") == 0) {
      *out = TeeOpportunisticSource;
      return ZX_OK;
    }
    return ZX_ERR_BAD_STATE;
  }
}

}  // namespace

// Returns a ordered vector of |KeySource|s, representing all key sources,
// ordered from most-preferred to least-preferred, that we should try for the
// purposes of creating a new volume
__EXPORT
fbl::Vector<KeySource> ComputeEffectiveCreatePolicy(KeySourcePolicy ksp) {
  fbl::Vector<KeySource> r;
  switch (ksp) {
    case NullSource:
      r = {kNullSource};
      break;
    case TeeRequiredSource:
    case TeeTransitionalSource:
      r = {kTeeSource};
      break;
    case TeeOpportunisticSource:
      r = {kTeeSource, kNullSource};
      break;
  }
  return r;
}

// Returns a ordered vector of |KeySource|s, representing all key sources,
// ordered from most-preferred to least-preferred, that we should try for the
// purposes of unsealing an existing volume
__EXPORT
fbl::Vector<KeySource> ComputeEffectiveUnsealPolicy(KeySourcePolicy ksp) {
  fbl::Vector<KeySource> r;
  switch (ksp) {
    case NullSource:
      r = {kNullSource};
      break;
    case TeeRequiredSource:
      r = {kTeeSource};
      break;
    case TeeTransitionalSource:
    case TeeOpportunisticSource:
      r = {kTeeSource, kNullSource};
      break;
  }
  return r;
}

__EXPORT
zx_status_t TryWithKeysFrom(
    const fbl::Vector<KeySource>& ordered_key_sources, Activity activity,
    fbl::Function<zx_status_t(std::unique_ptr<uint8_t[]>, size_t)> callback) {
  zx_status_t rc = ZX_ERR_INTERNAL;
  for (auto& key_source : ordered_key_sources) {
    switch (key_source) {
      case kNullSource: {
        auto key_buf = std::unique_ptr<uint8_t[]>(new uint8_t[kKeyLength]);
        memset(key_buf.get(), 0, kKeyLength);
        rc = callback(std::move(key_buf), kKeyLength);
      } break;
      case kTeeSource: {
        // key info is |kHardwareKeyInfo| padded with 0.
        uint8_t key_info[kms_stateless::kExpectedKeyInfoSize] = {0};
        memcpy(key_info, kHardwareKeyInfo, sizeof(kHardwareKeyInfo));
        // make names for these so the callback to kms_stateless can
        // copy them out later
        std::unique_ptr<uint8_t[]> key_buf;
        size_t key_size;
        zx_status_t kms_rc = kms_stateless::GetHardwareDerivedKey(
            [&](std::unique_ptr<uint8_t[]> cb_key_buffer, size_t cb_key_size) {
              key_size = cb_key_size;
              key_buf = std::unique_ptr<uint8_t[]>(new uint8_t[cb_key_size]);
              memcpy(key_buf.get(), cb_key_buffer.get(), cb_key_size);
              return ZX_OK;
            },
            key_info);

        if (kms_rc != ZX_OK) {
          rc = kms_rc;
          break;
        }

        rc = callback(std::move(key_buf), key_size);
      } break;
    }
    if (rc == ZX_OK) {
      return rc;
    }
  }

  xprintf("TryWithKeysFrom (%s): none of the %lu key sources succeeded\n",
          activity == Activity::Create ? "create" : "unseal", ordered_key_sources.size());
  return rc;
}

FdioVolumeManager::FdioVolumeManager(zx::channel&& chan) : chan_(std::move(chan)) {}

zx_status_t FdioVolumeManager::Unseal(const uint8_t* key, size_t key_len, uint8_t slot) {
  zx_status_t rc;
  zx_status_t call_status;
  if ((rc = fuchsia_hardware_block_encrypted_DeviceManagerUnseal(chan_.get(), key, key_len, slot,
                                                                 &call_status)) != ZX_OK) {
    xprintf("failed to call Unseal: %s\n", zx_status_get_string(rc));
    return rc;
  }

  if (call_status != ZX_OK) {
    xprintf("failed to Unseal: %s\n", zx_status_get_string(call_status));
  }
  return call_status;
}

zx_status_t FdioVolumeManager::UnsealWithDeviceKey(uint8_t slot) {
  KeySourcePolicy source;
  zx_status_t rc;
  rc = SelectKeySourcePolicy(&source);
  if (rc != ZX_OK) {
    return rc;
  }

  auto ordered_key_sources = ComputeEffectiveUnsealPolicy(source);

  return TryWithKeysFrom(ordered_key_sources, Activity::Unseal,
                         [&](std::unique_ptr<uint8_t[]> key_buffer, size_t key_size) {
                           return Unseal(key_buffer.get(), key_size, slot);
                         });
}

zx_status_t FdioVolumeManager::Seal() {
  zx_status_t rc;
  zx_status_t call_status;
  if ((rc = fuchsia_hardware_block_encrypted_DeviceManagerSeal(chan_.get(), &call_status)) !=
      ZX_OK) {
    xprintf("failed to call Seal: %s\n", zx_status_get_string(rc));
    return rc;
  }
  if (call_status != ZX_OK) {
    xprintf("failed to Seal: %s\n", zx_status_get_string(call_status));
  }
  return call_status;
}

zx_status_t FdioVolumeManager::Shred() {
  zx_status_t rc;
  zx_status_t call_status;
  if ((rc = fuchsia_hardware_block_encrypted_DeviceManagerShred(chan_.get(), &call_status)) !=
      ZX_OK) {
    xprintf("failed to call Shred: %s\n", zx_status_get_string(rc));
    return rc;
  }
  if (call_status != ZX_OK) {
    xprintf("failed to Shred: %s\n", zx_status_get_string(call_status));
  }
  return call_status;
}

FdioVolume::FdioVolume(fbl::unique_fd&& block_dev_fd, fbl::unique_fd&& devfs_root_fd)
    : Volume(), block_dev_fd_(std::move(block_dev_fd)), devfs_root_fd_(std::move(devfs_root_fd)) {}

zx_status_t FdioVolume::Init(fbl::unique_fd block_dev_fd, fbl::unique_fd devfs_root_fd,
                             std::unique_ptr<FdioVolume>* out) {
  zx_status_t rc;

  if (!block_dev_fd || !devfs_root_fd || !out) {
    xprintf("bad parameter(s): block_dev_fd=%d, devfs_root_fd=%d out=%p\n", block_dev_fd.get(),
            devfs_root_fd.get(), out);
    return ZX_ERR_INVALID_ARGS;
  }

  fbl::AllocChecker ac;
  std::unique_ptr<FdioVolume> volume(
      new (&ac) FdioVolume(std::move(block_dev_fd), std::move(devfs_root_fd)));
  if (!ac.check()) {
    xprintf("allocation failed: %zu bytes\n", sizeof(FdioVolume));
    return ZX_ERR_NO_MEMORY;
  }

  if ((rc = volume->Init()) != ZX_OK) {
    return rc;
  }

  *out = std::move(volume);
  return ZX_OK;
}

zx_status_t FdioVolume::Create(fbl::unique_fd block_dev_fd, fbl::unique_fd devfs_root_fd,
                               const crypto::Secret& key, std::unique_ptr<FdioVolume>* out) {
  zx_status_t rc;

  std::unique_ptr<FdioVolume> volume;

  if ((rc = FdioVolume::Init(std::move(block_dev_fd), std::move(devfs_root_fd), &volume)) !=
      ZX_OK) {
    xprintf("Init failed: %s\n", zx_status_get_string(rc));
    return rc;
  }
  if ((rc = volume->CreateBlock()) != ZX_OK) {
    xprintf("CreateBlock failed: %s\n", zx_status_get_string(rc));
    return rc;
  }
  if ((rc = volume->SealBlock(key, 0)) != ZX_OK) {
    xprintf("SealBlock failed: %s\n", zx_status_get_string(rc));
    return rc;
  }
  if ((rc = volume->CommitBlock()) != ZX_OK) {
    xprintf("CommitBlock failed: %s\n", zx_status_get_string(rc));
    return rc;
  }

  if (out) {
    *out = std::move(volume);
  }
  return ZX_OK;
}

zx_status_t FdioVolume::CreateWithDeviceKey(fbl::unique_fd&& block_dev_fd,
                                            fbl::unique_fd&& devfs_root_fd,
                                            std::unique_ptr<FdioVolume>* out) {
  KeySourcePolicy source;
  zx_status_t rc;
  rc = SelectKeySourcePolicy(&source);
  if (rc != ZX_OK) {
    return rc;
  }

  // Figure out which keying approaches we'll try, based on the key source
  // policy and context we're using this key in
  auto ordered_key_sources = ComputeEffectiveCreatePolicy(source);
  return TryWithKeysFrom(ordered_key_sources, Activity::Create,
                         [&](std::unique_ptr<uint8_t[]> key_buffer, size_t key_size) {
                           crypto::Secret secret;
                           zx_status_t rc;
                           uint8_t* inner;
                           rc = secret.Allocate(key_size, &inner);
                           if (rc != ZX_OK) {
                             xprintf("zxcrypt: couldn't allocate secret\n");
                             return rc;
                           }
                           memcpy(inner, key_buffer.get(), key_size);
                           rc = FdioVolume::Create(std::move(block_dev_fd),
                                                   std::move(devfs_root_fd), secret, out);
                           return rc;
                         });
}

zx_status_t FdioVolume::Unlock(fbl::unique_fd block_dev_fd, fbl::unique_fd devfs_root_fd,
                               const crypto::Secret& key, key_slot_t slot,
                               std::unique_ptr<FdioVolume>* out) {
  zx_status_t rc;

  std::unique_ptr<FdioVolume> volume;
  if ((rc = FdioVolume::Init(std::move(block_dev_fd), std::move(devfs_root_fd), &volume)) !=
      ZX_OK) {
    xprintf("Init failed: %s\n", zx_status_get_string(rc));
    return rc;
  }
  if ((rc = volume->Unlock(key, slot)) != ZX_OK) {
    xprintf("Unlock failed: %s\n", zx_status_get_string(rc));
    return rc;
  }

  *out = std::move(volume);
  return ZX_OK;
}

zx_status_t FdioVolume::UnlockWithDeviceKey(fbl::unique_fd block_dev_fd,
                                            fbl::unique_fd devfs_root_fd, key_slot_t slot,
                                            std::unique_ptr<FdioVolume>* out) {
  KeySourcePolicy source;
  zx_status_t rc;
  rc = SelectKeySourcePolicy(&source);
  if (rc != ZX_OK) {
    return rc;
  }

  auto ordered_key_sources = ComputeEffectiveUnsealPolicy(source);
  return TryWithKeysFrom(ordered_key_sources, Activity::Unseal,
                         [&](std::unique_ptr<uint8_t[]> key_buffer, size_t key_size) {
                           crypto::Secret secret;
                           zx_status_t rc;
                           uint8_t* inner;
                           rc = secret.Allocate(key_size, &inner);
                           if (rc != ZX_OK) {
                             xprintf("FdioVolume::UnlockWithDeviceKey: couldn't allocate secret\n");
                             return rc;
                           }
                           memcpy(inner, key_buffer.get(), key_size);
                           rc = FdioVolume::Unlock(std::move(block_dev_fd),
                                                   std::move(devfs_root_fd), secret, slot, out);
                           return rc;
                         });
}

zx_status_t FdioVolume::Unlock(const crypto::Secret& key, key_slot_t slot) {
  return Volume::Unlock(key, slot);
}

// Configuration methods
zx_status_t FdioVolume::Enroll(const crypto::Secret& key, key_slot_t slot) {
  zx_status_t rc;

  if ((rc = SealBlock(key, slot)) != ZX_OK) {
    xprintf("SealBlock failed: %s\n", zx_status_get_string(rc));
    return rc;
  }
  if ((rc = CommitBlock()) != ZX_OK) {
    xprintf("CommitBlock failed: %s\n", zx_status_get_string(rc));
    return rc;
  }

  return ZX_OK;
}

zx_status_t FdioVolume::Revoke(key_slot_t slot) {
  zx_status_t rc;

  zx_off_t off;
  crypto::Bytes invalid;
  if ((rc = GetSlotOffset(slot, &off)) != ZX_OK) {
    xprintf("GetSlotOffset failed: %s\n", zx_status_get_string(rc));
    return rc;
  }
  if ((rc = invalid.Randomize(slot_len_)) != ZX_OK) {
    xprintf("Randomize failed: %s\n", zx_status_get_string(rc));
    return rc;
  }
  if ((rc = block_.Copy(invalid, off)) != ZX_OK) {
    xprintf("Copy failed: %s\n", zx_status_get_string(rc));
    return rc;
  }
  if ((rc = CommitBlock()) != ZX_OK) {
    xprintf("CommitBlock failed: %s\n", zx_status_get_string(rc));
    return rc;
  }

  return ZX_OK;
}

zx_status_t FdioVolume::Init() { return Volume::Init(); }

zx_status_t FdioVolume::OpenManager(const zx::duration& timeout, zx_handle_t* out) {
  fdio_cpp::UnownedFdioCaller caller(block_dev_fd_.get());
  if (!caller) {
    xprintf("could not convert fd to io\n");
    return ZX_ERR_BAD_STATE;
  }
  return OpenManagerWithCaller(caller, timeout, out);
}

zx_status_t FdioVolume::Open(const zx::duration& timeout, fbl::unique_fd* out) {
  zx_status_t rc;
  fbl::String path_base;

  fdio_cpp::UnownedFdioCaller caller(block_dev_fd_.get());
  if (!caller) {
    xprintf("could not convert fd to io\n");
    return ZX_ERR_BAD_STATE;
  }

  if ((rc = RelativeTopologicalPath(caller, &path_base)) != ZX_OK) {
    xprintf("could not get topological path: %s\n", zx_status_get_string(rc));
    return rc;
  }
  fbl::String path_block_exposed = fbl::String::Concat({path_base, "/zxcrypt/unsealed/block"});

  // Early return if path_block_exposed is already present in the device tree
  fbl::unique_fd fd(openat(devfs_root_fd_.get(), path_block_exposed.c_str(), O_RDWR));
  if (fd) {
    out->reset(fd.release());
    return ZX_OK;
  }

  // Wait for the unsealed and block devices to bind
  if ((rc = wait_for_device_at(devfs_root_fd_.get(), path_block_exposed.c_str(), timeout.get())) !=
      ZX_OK) {
    xprintf("timed out waiting for %s to exist: %s\n", path_block_exposed.c_str(),
            zx_status_get_string(rc));
    return rc;
  }
  fd.reset(openat(devfs_root_fd_.get(), path_block_exposed.c_str(), O_RDWR));
  if (!fd) {
    xprintf("failed to open zxcrypt volume\n");
    return ZX_ERR_NOT_FOUND;
  }

  out->reset(fd.release());
  return ZX_OK;
}

zx_status_t FdioVolume::GetBlockInfo(BlockInfo* out) {
  zx_status_t rc;
  zx_status_t call_status;
  fdio_cpp::UnownedFdioCaller caller(block_dev_fd_.get());
  if (!caller) {
    return ZX_ERR_BAD_STATE;
  }
  fuchsia_hardware_block_BlockInfo block_info;
  if ((rc = fuchsia_hardware_block_BlockGetInfo(caller.borrow_channel(), &call_status,
                                                &block_info)) != ZX_OK) {
    return rc;
  }
  if (call_status != ZX_OK) {
    return call_status;
  }

  out->block_count = block_info.block_count;
  out->block_size = block_info.block_size;
  return ZX_OK;
}

zx_status_t FdioVolume::GetFvmSliceSize(uint64_t* out) {
  zx_status_t rc;
  zx_status_t call_status;
  fdio_cpp::UnownedFdioCaller caller(block_dev_fd_.get());
  if (!caller) {
    return ZX_ERR_BAD_STATE;
  }

  // When this function is called, we're not yet sure if the underlying device
  // actually implements the block protocol, and we use the return value here
  // to tell us if we should utilize FVM-specific codepaths or not.
  // If the underlying channel doesn't respond to volume methods, when we call
  // a method from fuchsia.hardware.block.volume the FIDL channel will be
  // closed and we'll be unable to do other calls to it.  So before making
  // this call, we clone the channel.
  zx::channel channel(fdio_service_clone(caller.borrow_channel()));

  fuchsia_hardware_block_volume_VolumeInfo volume_info;
  if ((rc = fuchsia_hardware_block_volume_VolumeQuery(channel.get(), &call_status, &volume_info)) !=
      ZX_OK) {
    if (rc == ZX_ERR_PEER_CLOSED) {
      // The channel being closed here means that the thing at the other
      // end of this channel does not speak the FVM protocol, and has
      // closed the channel on us.  Return the appropriate error to signal
      // that we shouldn't bother with any of the FVM codepaths.
      return ZX_ERR_NOT_SUPPORTED;
    }
    return rc;
  }
  if (call_status != ZX_OK) {
    return call_status;
  }

  *out = volume_info.slice_size;
  return ZX_OK;
}

zx_status_t FdioVolume::DoBlockFvmVsliceQuery(uint64_t vslice_start,
                                              SliceRegion ranges[Volume::MAX_SLICE_REGIONS],
                                              uint64_t* slice_count) {
  static_assert(fuchsia_hardware_block_volume_MAX_SLICE_REQUESTS == Volume::MAX_SLICE_REGIONS,
                "block volume slice response count must match");
  zx_status_t rc;
  zx_status_t call_status;
  fdio_cpp::UnownedFdioCaller caller(block_dev_fd_.get());
  if (!caller) {
    return ZX_ERR_BAD_STATE;
  }
  fuchsia_hardware_block_volume_VsliceRange tmp_ranges[Volume::MAX_SLICE_REGIONS];
  uint64_t range_count;

  if ((rc = fuchsia_hardware_block_volume_VolumeQuerySlices(
           caller.borrow_channel(), &vslice_start, 1, &call_status, tmp_ranges, &range_count)) !=
      ZX_OK) {
    return rc;
  }
  if (call_status != ZX_OK) {
    return call_status;
  }

  if (range_count > Volume::MAX_SLICE_REGIONS) {
    // Should be impossible.  Trust nothing.
    return ZX_ERR_BAD_STATE;
  }

  *slice_count = range_count;
  for (size_t i = 0; i < range_count; i++) {
    ranges[i].allocated = tmp_ranges[i].allocated;
    ranges[i].count = tmp_ranges[i].count;
  }

  return ZX_OK;
}

zx_status_t FdioVolume::DoBlockFvmExtend(uint64_t start_slice, uint64_t slice_count) {
  zx_status_t rc;
  zx_status_t call_status;
  fdio_cpp::UnownedFdioCaller caller(block_dev_fd_.get());
  if (!caller) {
    return ZX_ERR_BAD_STATE;
  }
  if ((rc = fuchsia_hardware_block_volume_VolumeExtend(caller.borrow_channel(), start_slice,
                                                       slice_count, &call_status)) != ZX_OK) {
    return rc;
  }
  if (call_status != ZX_OK) {
    return call_status;
  }

  return ZX_OK;
}

zx_status_t FdioVolume::Read() {
  if (lseek(block_dev_fd_.get(), offset_, SEEK_SET) < 0) {
    xprintf("lseek(%d, %" PRIu64 ", SEEK_SET) failed: %s\n", block_dev_fd_.get(), offset_,
            strerror(errno));
    return ZX_ERR_IO;
  }
  ssize_t res;
  if ((res = read(block_dev_fd_.get(), block_.get(), block_.len())) < 0) {
    xprintf("read(%d, %p, %zu) failed: %s\n", block_dev_fd_.get(), block_.get(), block_.len(),
            strerror(errno));
    return ZX_ERR_IO;
  }
  if (static_cast<size_t>(res) != block_.len()) {
    xprintf("short read: have %zd, need %zu\n", res, block_.len());
    return ZX_ERR_IO;
  }

  return ZX_OK;
}

zx_status_t FdioVolume::Write() {
  if (lseek(block_dev_fd_.get(), offset_, SEEK_SET) < 0) {
    xprintf("lseek(%d, %" PRIu64 ", SEEK_SET) failed: %s\n", block_dev_fd_.get(), offset_,
            strerror(errno));
    return ZX_ERR_IO;
  }
  ssize_t res;
  if ((res = write(block_dev_fd_.get(), block_.get(), block_.len())) < 0) {
    xprintf("write(%d, %p, %zu) failed: %s\n", block_dev_fd_.get(), block_.get(), block_.len(),
            strerror(errno));
    return ZX_ERR_IO;
  }
  if (static_cast<size_t>(res) != block_.len()) {
    xprintf("short write: have %zd, need %zu\n", res, block_.len());
    return ZX_ERR_IO;
  }
  return ZX_OK;
}

zx_status_t FdioVolume::OpenManagerWithCaller(fdio_cpp::UnownedFdioCaller& caller,
                                              const zx::duration& timeout, zx_handle_t* out) {
  zx_status_t rc;
  fbl::String path_base;

  if ((rc = RelativeTopologicalPath(caller, &path_base)) != ZX_OK) {
    xprintf("could not get topological path: %s\n", zx_status_get_string(rc));
    return rc;
  }
  fbl::String path_manager = fbl::String::Concat({path_base, "/zxcrypt"});

  fbl::unique_fd fd(openat(devfs_root_fd_.get(), path_manager.c_str(), O_RDWR));
  if (!fd) {
    // No manager device in the /dev tree yet.  Try binding the zxcrypt
    // driver and waiting for it to appear.
    auto resp = ::llcpp::fuchsia::device::Controller::Call::Bind(
        zx::unowned_channel(caller.borrow_channel()),
        ::fidl::unowned_str(kDriverLib, strlen(kDriverLib)));
    rc = resp.status();
    if (rc == ZX_OK) {
      if (resp->result.is_err()) {
        rc = resp->result.err();
      }
    }
    if (rc != ZX_OK) {
      xprintf("could not bind zxcrypt driver: %s\n", zx_status_get_string(rc));
      return rc;
    }

    // Await the appearance of the zxcrypt device.
    if ((rc = wait_for_device_at(devfs_root_fd_.get(), path_manager.c_str(), timeout.get())) !=
        ZX_OK) {
      xprintf("zxcrypt driver failed to bind: %s\n", zx_status_get_string(rc));
      return rc;
    }

    fd.reset(openat(devfs_root_fd_.get(), path_manager.c_str(), O_RDWR));
    if (!fd) {
      xprintf("failed to open zxcrypt manager\n");
      return ZX_ERR_NOT_FOUND;
    }
  }

  if ((rc = fdio_get_service_handle(fd.release(), out)) != ZX_OK) {
    xprintf("failed to get service handle for zxcrypt manager: %s\n", zx_status_get_string(rc));
    return rc;
  }

  return ZX_OK;
}

zx_status_t FdioVolume::RelativeTopologicalPath(fdio_cpp::UnownedFdioCaller& caller,
                                                fbl::String* out) {
  zx_status_t rc;

  // Get the full device path
  fbl::StringBuffer<PATH_MAX> path;
  path.Resize(path.capacity());
  size_t path_len;
  auto resp = ::llcpp::fuchsia::device::Controller::Call::GetTopologicalPath(
      zx::unowned_channel(caller.borrow_channel()));
  rc = resp.status();
  if (rc == ZX_OK) {
    if (resp->result.is_err()) {
      rc = resp->result.err();
    } else {
      auto& r = resp->result.response();
      path_len = r.path.size();
      memcpy(path.data(), r.path.data(), r.path.size());
    }
  }

  if (rc != ZX_OK) {
    xprintf("could not find parent device: %s\n", zx_status_get_string(rc));
    return rc;
  }

  // Verify that the path returned starts with "/dev/"
  const char* kSlashDevSlash = "/dev/";
  if (path_len < strlen(kSlashDevSlash)) {
    xprintf("path_len way too short: %lu\n", path_len);
    return ZX_ERR_INTERNAL;
  }
  if (strncmp(path.c_str(), kSlashDevSlash, strlen(kSlashDevSlash)) != 0) {
    xprintf("Expected device path to start with '/dev/' but got %s\n", path.c_str());
    return ZX_ERR_INTERNAL;
  }

  // Strip the leading "/dev/" and return the rest
  size_t path_len_sans_dev = path_len - strlen(kSlashDevSlash);
  memmove(path.begin(), path.begin() + strlen(kSlashDevSlash), path_len_sans_dev);

  path.Resize(path_len_sans_dev);
  *out = path.ToString();
  return ZX_OK;
}

}  // namespace zxcrypt
