// 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 "factory_reset.h"

#include <dirent.h>
#include <fcntl.h>
#include <fidl/fuchsia.hardware.block/cpp/wire.h>
#include <fuchsia/fs/cpp/fidl.h>
#include <fuchsia/hardware/block/c/fidl.h>
#include <lib/fdio/fdio.h>
#include <lib/syslog/cpp/macros.h>
#include <lib/zx/channel.h>
#include <zircon/status.h>

#include "lib/fdio/cpp/caller.h"
#include "src/lib/storage/fs_management/cpp/format.h"
#include "src/lib/storage/fs_management/cpp/mount.h"
#include "src/security/kms-stateless/kms-stateless.h"
#include "src/security/zxcrypt/client.h"

namespace factory_reset {

const char* kBlockPath = "class/block";

zx_status_t ShredZxcryptDevice(fbl::unique_fd fd, fbl::unique_fd devfs_root_fd) {
  zx_status_t status;
  zxcrypt::VolumeManager volume(std::move(fd), std::move(devfs_root_fd));

  // Note: the access to /dev/sys/platform from the manifest is load-bearing
  // here, because we can only find the related zxcrypt device for a particular
  // block device via appending "/zxcrypt" to its topological path, and the
  // canonical topological path sits under sys/platform.
  zx::channel driver_chan;
  status = volume.OpenClient(zx::sec(5), driver_chan);
  if (status != ZX_OK) {
    FX_LOGS(ERROR) << "Couldn't open channel to zxcrypt volume manager: " << status << " ("
                   << zx_status_get_string(status) << ")";
    return status;
  }

  zxcrypt::EncryptedVolumeClient zxc_manager(std::move(driver_chan));
  status = zxc_manager.Shred();
  if (status != ZX_OK) {
    FX_LOGS(ERROR) << "Couldn't shred volume: " << status << " (" << zx_status_get_string(status)
                   << ")";
    return status;
  }

  return ZX_OK;
}

zx_status_t ShredFxfsDevice(fbl::unique_fd fd) {
  // Overwrite the magic bytes of both superblocks.
  //
  // Note: This may occasionally be racy. Superblocks may be writen after
  // the overwrite below but before reboot. When we move this to fshost, we
  // will have access to the running filesystem and can wait for shutdown with
  // something like:
  //   fdio_cpp::FdioCaller caller(std::move(fd));
  //   if (zx::status<> status = fs_management::Shutdown(caller.directory()); !status.is_ok()) {
  //     return status.error_value();
  //   }
  // TODO(https://fxbug.dev/98889): Perform secure erase once we have keybag support.
  zx_status_t call_status;
  fdio_cpp::UnownedFdioCaller caller(fd.get());
  fuchsia_hardware_block_BlockInfo block_info;
  if (auto status =
          fuchsia_hardware_block_BlockGetInfo(caller.borrow_channel(), &call_status, &block_info);
      status != ZX_OK) {
    FX_LOGS(ERROR) << "Failed to fetch block size.";
    return status;
  }
  ssize_t block_size = block_info.block_size;
  std::unique_ptr<uint8_t[]> block = std::make_unique<uint8_t[]>(block_size);
  memset(block.get(), 0, block_size);
  for (off_t offset : {0L, 512L << 10}) {
    if (auto status = ::lseek(fd.get(), offset, SEEK_SET); status < 0) {
      FX_LOGS(ERROR) << "Seek on fxfs device shred failed.";
      return ZX_ERR_IO;
    }
    if (auto status = ::write(fd.get(), block.get(), block_size); status < 0) {
      FX_LOGS(ERROR) << "Write to fxfs device at offset " << offset << " failed:" << status;
      return ZX_ERR_IO;
    }
  }
  return ZX_OK;
}

FactoryReset::FactoryReset(fbl::unique_fd dev_fd,
                           fuchsia::hardware::power::statecontrol::AdminPtr admin) {
  dev_fd_ = std::move(dev_fd);
  admin_ = std::move(admin);
}

zx_status_t FactoryReset::Shred() const {
  fbl::unique_fd block_dir(openat(dev_fd_.get(), kBlockPath, O_RDONLY | O_DIRECTORY));
  if (!block_dir) {
    FX_LOGS(ERROR) << "Error opening " << kBlockPath;
    return ZX_ERR_NOT_FOUND;
  }
  struct dirent* de;
  DIR* dir = fdopendir(block_dir.get());
  // Attempts to shred every zxcrypt volume found.
  while ((de = readdir(dir)) != nullptr) {
    fbl::unique_fd block_fd(openat(dirfd(dir), de->d_name, O_RDWR));
    if (!block_fd) {
      continue;
    }

    zx_status_t status = ZX_OK;
    switch (fs_management::DetectDiskFormat(block_fd.get())) {
      case fs_management::kDiskFormatZxcrypt: {
        status = ShredZxcryptDevice(std::move(block_fd), dev_fd_.duplicate());
        break;
      }
      case fs_management::kDiskFormatFxfs: {
        status = ShredFxfsDevice(std::move(block_fd));
        break;
      }
      default:
        continue;
    }
    if (status != ZX_OK) {
      FX_LOGS(ERROR) << "Error shredding " << de->d_name;
      closedir(dir);
      return status;
    } else {
      FX_LOGS(INFO) << "Successfully shredded " << de->d_name;
    }
  }
  closedir(dir);
  return ZX_OK;
}

void FactoryReset::Reset(ResetCallback callback) {
  FX_LOGS(ERROR) << "Reset called. Starting shred.";
  zx_status_t status = Shred();
  if (status != ZX_OK) {
    FX_LOGS(ERROR) << "Shred failed: " << status << " (" << zx_status_get_string(status) << ")";
    callback(std::move(status));
    return;
  }
  FX_LOGS(ERROR) << "Finished shred.";

  uint8_t key_info[kms_stateless::kExpectedKeyInfoSize] = "zxcrypt";
  status = kms_stateless::RotateHardwareDerivedKeyFromService(key_info);
  if (status == ZX_ERR_NOT_SUPPORTED) {
    FX_LOGS(ERROR)
        << "FactoryReset: The device does not support rotatable hardware keys. Ignoring.";
    status = ZX_OK;
  } else if (status != ZX_OK) {
    FX_LOGS(ERROR) << "FactoryReset: RotateHardwareDerivedKey() failed: " << status << " ("
                   << zx_status_get_string(status) << ")";
    callback(std::move(status));
    return;
  }
  // Reboot to initiate the recovery.
  FX_LOGS(ERROR) << "Requesting reboot...";
  admin_->Reboot(fuchsia::hardware::power::statecontrol::RebootReason::FACTORY_DATA_RESET,
                 [callback{std::move(callback)}](
                     fuchsia::hardware::power::statecontrol::Admin_Reboot_Result status) {
                   if (status.is_err()) {
                     FX_LOGS(ERROR) << "Reboot call failed: " << status.err();
                     callback(status.err());
                   } else {
                     callback(ZX_OK);
                   }
                 });
}

}  // namespace factory_reset
