Make the vm_payload API look more NDK-like
- Give functions a `AVmPayload_` prefix followed by lower camel case name (hopefully better branding comes later, but this makes it easy to grep). - Let callers find out how big the attestation chain is. Bug: 243514248 Test: atest MicrodroidTests ComposHostTestCases MicrodroidBenchmarks Change-Id: I93c37787eae296d97a44cc369e8ea0c3c670c6cb
This commit is contained in:
parent
8b38f3a7cb
commit
655e98edfb
|
@ -20,6 +20,7 @@
|
|||
#include <vm_payload.h>
|
||||
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include "compos_key.h"
|
||||
|
||||
|
@ -37,8 +38,9 @@ constexpr const char* kSigningKeySeedIdentifier = "CompOS signing key seed";
|
|||
|
||||
Result<Ed25519KeyPair> getSigningKey() {
|
||||
Seed seed;
|
||||
if (!get_vm_instance_secret(kSigningKeySeedIdentifier, strlen(kSigningKeySeedIdentifier),
|
||||
seed.data(), seed.size())) {
|
||||
if (!AVmPayload_getVmInstanceSecret(kSigningKeySeedIdentifier,
|
||||
strlen(kSigningKeySeedIdentifier), seed.data(),
|
||||
seed.size())) {
|
||||
return Error() << "Failed to get signing key seed";
|
||||
}
|
||||
return compos_key::keyFromSeed(seed);
|
||||
|
@ -58,14 +60,18 @@ int write_public_key() {
|
|||
}
|
||||
|
||||
int write_bcc() {
|
||||
uint8_t bcc[4096];
|
||||
size_t bcc_size = get_dice_attestation_chain(bcc, sizeof(bcc));
|
||||
if (bcc_size == 0) {
|
||||
size_t bcc_size;
|
||||
if (!AVmPayload_getDiceAttestationChain(nullptr, 0, &bcc_size)) {
|
||||
LOG(ERROR) << "Failed to measure attestation chain";
|
||||
return 1;
|
||||
}
|
||||
std::vector<uint8_t> bcc(bcc_size);
|
||||
if (!AVmPayload_getDiceAttestationChain(bcc.data(), bcc.size(), &bcc_size)) {
|
||||
LOG(ERROR) << "Failed to get attestation chain";
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!WriteFully(STDOUT_FILENO, bcc, bcc_size)) {
|
||||
if (!WriteFully(STDOUT_FILENO, bcc.data(), bcc.size())) {
|
||||
PLOG(ERROR) << "Write failed";
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ use compos_common::COMPOS_VSOCK_PORT;
|
|||
use log::{debug, error};
|
||||
use rpcbinder::run_rpc_server;
|
||||
use std::panic;
|
||||
use vm_payload_bindgen::notify_payload_ready;
|
||||
use vm_payload_bindgen::AVmPayload_notifyPayloadReady;
|
||||
|
||||
fn main() {
|
||||
if let Err(e) = try_main() {
|
||||
|
@ -49,7 +49,7 @@ fn try_main() -> Result<()> {
|
|||
debug!("compsvc is starting as a rpc service.");
|
||||
// SAFETY: Invokes a method from the bindgen library `vm_payload_bindgen`.
|
||||
let retval = run_rpc_server(service, COMPOS_VSOCK_PORT, || unsafe {
|
||||
notify_payload_ready();
|
||||
AVmPayload_notifyPayloadReady();
|
||||
});
|
||||
if retval {
|
||||
debug!("RPC server has shut down gracefully");
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
@ -26,9 +25,10 @@ extern "C" {
|
|||
|
||||
/**
|
||||
* Notifies the host that the payload is ready.
|
||||
* Returns true if the notification succeeds else false.
|
||||
*
|
||||
* \return true if the notification succeeds else false.
|
||||
*/
|
||||
bool notify_payload_ready(void);
|
||||
bool AVmPayload_notifyPayloadReady(void);
|
||||
|
||||
/**
|
||||
* Get a secret that is uniquely bound to this VM instance. The secrets are 32-byte values and the
|
||||
|
@ -41,23 +41,35 @@ bool notify_payload_ready(void);
|
|||
*
|
||||
* \return true on success and false on failure.
|
||||
*/
|
||||
bool get_vm_instance_secret(const void *identifier, size_t identifier_size, void *secret,
|
||||
bool AVmPayload_getVmInstanceSecret(const void *identifier, size_t identifier_size, void *secret,
|
||||
size_t size);
|
||||
|
||||
/**
|
||||
* Get the VM's attestation chain.
|
||||
* Returns the size of data or 0 on failure.
|
||||
* Get the VM's DICE attestation chain.
|
||||
*
|
||||
* TODO: don't expose the contained privacy breaking identifiers to the payload
|
||||
* TODO: keep the DICE chain as an internal detail for as long as possible
|
||||
*
|
||||
* \param data pointer to size bytes where the chain is written.
|
||||
* \param size number of bytes that can be written to data.
|
||||
* \param total outputs the total size of the chain if the function succeeds
|
||||
*
|
||||
* \return true on success and false on failure.
|
||||
*/
|
||||
size_t get_dice_attestation_chain(void *data, size_t size);
|
||||
bool AVmPayload_getDiceAttestationChain(void *data, size_t size, size_t *total);
|
||||
|
||||
/**
|
||||
* Get the VM's attestation CDI.
|
||||
* Returns the size of data or 0 on failure.
|
||||
* Get the VM's DICE attestation CDI.
|
||||
*
|
||||
* TODO: don't expose the raw CDI, only derived values
|
||||
*
|
||||
* \param data pointer to size bytes where the CDI is written.
|
||||
* \param size number of bytes that can be written to data.
|
||||
* \param total outputs the total size of the CDI if the function succeeds
|
||||
*
|
||||
* \return true on success and false on failure.
|
||||
*/
|
||||
size_t get_dice_attestation_cdi(void *data, size_t size);
|
||||
bool AVmPayload_getDiceAttestationCdi(void *data, size_t size, size_t *total);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
|
|
|
@ -17,6 +17,6 @@
|
|||
mod vm_service;
|
||||
|
||||
pub use vm_service::{
|
||||
get_dice_attestation_cdi, get_dice_attestation_chain, get_vm_instance_secret,
|
||||
notify_payload_ready,
|
||||
AVmPayload_getDiceAttestationCdi, AVmPayload_getDiceAttestationChain,
|
||||
AVmPayload_getVmInstanceSecret, AVmPayload_notifyPayloadReady,
|
||||
};
|
||||
|
|
|
@ -23,7 +23,7 @@ use log::{error, info, Level};
|
|||
/// Notifies the host that the payload is ready.
|
||||
/// Returns true if the notification succeeds else false.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn notify_payload_ready() -> bool {
|
||||
pub extern "C" fn AVmPayload_notifyPayloadReady() -> bool {
|
||||
android_logger::init_once(
|
||||
android_logger::Config::default().with_tag("vm_payload").with_min_level(Level::Debug),
|
||||
);
|
||||
|
@ -46,9 +46,14 @@ fn try_notify_payload_ready() -> Result<()> {
|
|||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The identifier must be identifier_size bytes and secret must be size bytes.
|
||||
/// Behavior is undefined if any of the following conditions are violated:
|
||||
///
|
||||
/// * `identifier` must be [valid] for reads of `identifier_size` bytes.
|
||||
/// * `secret` must be [valid] for writes of `size` bytes.
|
||||
///
|
||||
/// [valid]: std::ptr#safety
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn get_vm_instance_secret(
|
||||
pub unsafe extern "C" fn AVmPayload_getVmInstanceSecret(
|
||||
identifier: *const u8,
|
||||
identifier_size: usize,
|
||||
secret: *mut u8,
|
||||
|
@ -77,25 +82,31 @@ fn try_get_vm_instance_secret(identifier: &[u8], size: usize) -> Result<Vec<u8>>
|
|||
}
|
||||
|
||||
/// Get the VM's attestation chain.
|
||||
/// Returns the size of data or 0 on failure.
|
||||
/// Returns true on success, else false.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The data must be size bytes big.
|
||||
/// Behavior is undefined if any of the following conditions are violated:
|
||||
///
|
||||
/// * `data` must be [valid] for writes of `size` bytes.
|
||||
/// * `total` must be [valid] for writes.
|
||||
///
|
||||
/// [valid]: std::ptr#safety
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn get_dice_attestation_chain(data: *mut u8, size: usize) -> usize {
|
||||
pub unsafe extern "C" fn AVmPayload_getDiceAttestationChain(
|
||||
data: *mut u8,
|
||||
size: usize,
|
||||
total: *mut usize,
|
||||
) -> bool {
|
||||
match try_get_dice_attestation_chain() {
|
||||
Err(e) => {
|
||||
error!("{:?}", e);
|
||||
0
|
||||
false
|
||||
}
|
||||
Ok(chain) => {
|
||||
if size < chain.len() {
|
||||
0
|
||||
} else {
|
||||
std::ptr::copy_nonoverlapping(chain.as_ptr(), data, chain.len());
|
||||
chain.len()
|
||||
}
|
||||
total.write(chain.len());
|
||||
std::ptr::copy_nonoverlapping(chain.as_ptr(), data, std::cmp::min(chain.len(), size));
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -105,25 +116,31 @@ fn try_get_dice_attestation_chain() -> Result<Vec<u8>> {
|
|||
}
|
||||
|
||||
/// Get the VM's attestation CDI.
|
||||
/// Returns the size of data or 0 on failure.
|
||||
/// Returns true on success, else false.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The data must be size bytes big.
|
||||
/// Behavior is undefined if any of the following conditions are violated:
|
||||
///
|
||||
/// * `data` must be [valid] for writes of `size` bytes.
|
||||
/// * `total` must be [valid] for writes.
|
||||
///
|
||||
/// [valid]: std::ptr#safety
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn get_dice_attestation_cdi(data: *mut u8, size: usize) -> usize {
|
||||
pub unsafe extern "C" fn AVmPayload_getDiceAttestationCdi(
|
||||
data: *mut u8,
|
||||
size: usize,
|
||||
total: *mut usize,
|
||||
) -> bool {
|
||||
match try_get_dice_attestation_cdi() {
|
||||
Err(e) => {
|
||||
error!("{:?}", e);
|
||||
0
|
||||
false
|
||||
}
|
||||
Ok(cdi) => {
|
||||
if size < cdi.len() {
|
||||
0
|
||||
} else {
|
||||
std::ptr::copy_nonoverlapping(cdi.as_ptr(), data, cdi.len());
|
||||
cdi.len()
|
||||
}
|
||||
total.write(cdi.len());
|
||||
std::ptr::copy_nonoverlapping(cdi.as_ptr(), data, std::cmp::min(cdi.len(), size));
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -158,7 +158,7 @@ private:
|
|||
Result<void> run_io_benchmark_tests() {
|
||||
auto test_service = ndk::SharedRefBase::make<IOBenchmarkService>();
|
||||
auto callback = []([[maybe_unused]] void* param) {
|
||||
if (!notify_payload_ready()) {
|
||||
if (!AVmPayload_notifyPayloadReady()) {
|
||||
LOG(ERROR) << "failed to notify payload ready to virtualizationservice";
|
||||
abort();
|
||||
}
|
||||
|
|
|
@ -75,41 +75,48 @@ Result<void> start_test_service() {
|
|||
|
||||
ndk::ScopedAStatus insecurelyExposeVmInstanceSecret(std::vector<uint8_t>* out) override {
|
||||
const uint8_t identifier[] = {1, 2, 3, 4};
|
||||
uint8_t secret[32];
|
||||
if (!get_vm_instance_secret(identifier, sizeof(identifier), secret, sizeof(secret))) {
|
||||
out->resize(32);
|
||||
if (!AVmPayload_getVmInstanceSecret(identifier, sizeof(identifier), out->data(),
|
||||
out->size())) {
|
||||
return ndk::ScopedAStatus::
|
||||
fromServiceSpecificErrorWithMessage(0, "Failed to VM instance secret");
|
||||
}
|
||||
*out = {secret, secret + sizeof(secret)};
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus insecurelyExposeAttestationCdi(std::vector<uint8_t>* out) override {
|
||||
uint8_t cdi[64];
|
||||
size_t cdi_size = get_dice_attestation_cdi(cdi, sizeof(cdi));
|
||||
if (cdi_size == 0) {
|
||||
size_t cdi_size;
|
||||
if (!AVmPayload_getDiceAttestationCdi(nullptr, 0, &cdi_size)) {
|
||||
return ndk::ScopedAStatus::
|
||||
fromServiceSpecificErrorWithMessage(0, "Failed to measure attestation cdi");
|
||||
}
|
||||
out->resize(cdi_size);
|
||||
if (!AVmPayload_getDiceAttestationCdi(out->data(), out->size(), &cdi_size)) {
|
||||
return ndk::ScopedAStatus::
|
||||
fromServiceSpecificErrorWithMessage(0, "Failed to get attestation cdi");
|
||||
}
|
||||
*out = {cdi, cdi + cdi_size};
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus getBcc(std::vector<uint8_t>* out) override {
|
||||
uint8_t bcc[4096];
|
||||
size_t bcc_size = get_dice_attestation_chain(bcc, sizeof(bcc));
|
||||
if (bcc_size == 0) {
|
||||
size_t bcc_size;
|
||||
if (!AVmPayload_getDiceAttestationChain(nullptr, 0, &bcc_size)) {
|
||||
return ndk::ScopedAStatus::
|
||||
fromServiceSpecificErrorWithMessage(0,
|
||||
"Failed to measure attestation chain");
|
||||
}
|
||||
out->resize(bcc_size);
|
||||
if (!AVmPayload_getDiceAttestationChain(out->data(), out->size(), &bcc_size)) {
|
||||
return ndk::ScopedAStatus::
|
||||
fromServiceSpecificErrorWithMessage(0, "Failed to get attestation chain");
|
||||
}
|
||||
*out = {bcc, bcc + bcc_size};
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
};
|
||||
auto testService = ndk::SharedRefBase::make<TestService>();
|
||||
|
||||
auto callback = []([[maybe_unused]] void* param) {
|
||||
if (!notify_payload_ready()) {
|
||||
if (!AVmPayload_notifyPayloadReady()) {
|
||||
std::cerr << "failed to notify payload ready to virtualizationservice" << std::endl;
|
||||
abort();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue