blob: b9dca3aef04090f476e9ac34e36680d2d03de29b [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.
#include "encrypted-volume.h"
#include <lib/fdio/fdio.h>
#include <lib/syslog/cpp/macros.h>
#include <stdio.h>
#include <zircon/status.h>
#include <zxcrypt/fdio-volume.h>
namespace devmgr {
EncryptedVolume::EncryptedVolume(fbl::unique_fd fd, fbl::unique_fd devfs_root)
: fd_(std::move(fd)), devfs_root_(std::move(devfs_root)) {}
zx_status_t EncryptedVolume::Unseal() {
zx_status_t rc;
std::unique_ptr<zxcrypt::FdioVolume> zxcrypt_volume;
rc = zxcrypt::FdioVolume::Init(fd_.duplicate(), devfs_root_.duplicate(), &zxcrypt_volume);
if (rc != ZX_OK) {
FX_LOGS(ERROR) << "couldn't open zxcrypt fdio volume: " << zx_status_get_string(rc);
return rc;
}
zx::channel zxcrypt_volume_manager_chan;
rc = zxcrypt_volume->OpenManager(zx::sec(2), zxcrypt_volume_manager_chan.reset_and_get_address());
if (rc != ZX_OK) {
FX_LOGS(ERROR) << "couldn't open zxcrypt manager device: " << zx_status_get_string(rc);
return rc;
}
zxcrypt::FdioVolumeManager zxcrypt_volume_manager(std::move(zxcrypt_volume_manager_chan));
uint8_t slot = 0;
rc = zxcrypt_volume_manager.UnsealWithDeviceKey(slot);
if (rc != ZX_OK) {
FX_LOGS(ERROR) << "couldn't unseal zxcrypt manager device: " << zx_status_get_string(rc);
return rc;
}
return ZX_OK;
}
zx_status_t EncryptedVolume::Format() {
zx_status_t rc;
rc = zxcrypt::FdioVolume::CreateWithDeviceKey(fd_.duplicate(), devfs_root_.duplicate(), nullptr);
if (rc != ZX_OK) {
FX_LOGS(ERROR) << "couldn't format zxcrypt volume with device key: "
<< zx_status_get_string(rc);
return rc;
}
return ZX_OK;
}
const int kUnsealTryCountBeforeWipe = 5;
zx_status_t EncryptedVolumeInterface::EnsureUnsealedAndFormatIfNeeded() {
// Policy: first, unseal. If that fails, format, then unseal again.
zx_status_t rc;
int try_count = 0;
do {
rc = Unseal();
try_count++;
} while (rc != ZX_OK && try_count < kUnsealTryCountBeforeWipe);
if (rc == ZX_OK) {
// We successfully unsealed the volume. No need to wipe. Return success.
return ZX_OK;
}
// Alas, we could not unseal the volume. Give up. If the error code suggests
// we just have the wrong key, try formatting the volume with the keys we
// have. Otherwise, just return the error we got from the last Unseal()
// attempt.
if (rc == ZX_ERR_ACCESS_DENIED) {
FX_LOGS(ERROR) <<
"Failed repeatedly to unseal zxcrypt device with all available keys. "
"Destructively reformatting with new key to attempt to bring up an empty block volume "
"rather than none at all. Expect factory-reset-like behavior.";
rc = Format();
if (rc != ZX_OK) {
FX_LOGS(ERROR) << "couldn't format encrypted volume: " << zx_status_get_string(rc);
return rc;
}
// At this point, we had better be able to unseal the volume that we just
// formatted.
rc = Unseal();
if (rc != ZX_OK) {
FX_LOGS(ERROR) << "formatted volume but couldn't unseal it thereafter: "
<< zx_status_get_string(rc);
return rc;
}
return ZX_OK;
} else {
FX_LOGS(ERROR) << "could not produce an unsealed volume for minfs: "
<< zx_status_get_string(rc);
return rc;
}
}
} // namespace devmgr