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
diff --git a/compos/compos_key_helper/compos_key_main.cpp b/compos/compos_key_helper/compos_key_main.cpp
index 224e42b..4fb0762 100644
--- a/compos/compos_key_helper/compos_key_main.cpp
+++ b/compos/compos_key_helper/compos_key_main.cpp
@@ -20,6 +20,7 @@
#include <vm_payload.h>
#include <string_view>
+#include <vector>
#include "compos_key.h"
@@ -37,8 +38,9 @@
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_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;
}
diff --git a/compos/src/compsvc_main.rs b/compos/src/compsvc_main.rs
index 64e2ced..991725d 100644
--- a/compos/src/compsvc_main.rs
+++ b/compos/src/compsvc_main.rs
@@ -27,7 +27,7 @@
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 @@
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");
diff --git a/microdroid/vm_payload/include/vm_payload.h b/microdroid/vm_payload/include/vm_payload.h
index 0744146..05abdce 100644
--- a/microdroid/vm_payload/include/vm_payload.h
+++ b/microdroid/vm_payload/include/vm_payload.h
@@ -18,7 +18,6 @@
#include <stdbool.h>
#include <stddef.h>
-#include <stdint.h>
#ifdef __cplusplus
extern "C" {
@@ -26,9 +25,10 @@
/**
* 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 @@
*
* \return true on success and false on failure.
*/
-bool get_vm_instance_secret(const void *identifier, size_t identifier_size, void *secret,
- size_t size);
+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"
diff --git a/microdroid/vm_payload/src/lib.rs b/microdroid/vm_payload/src/lib.rs
index 74dd8f4..ca0c17b 100644
--- a/microdroid/vm_payload/src/lib.rs
+++ b/microdroid/vm_payload/src/lib.rs
@@ -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,
};
diff --git a/microdroid/vm_payload/src/vm_service.rs b/microdroid/vm_payload/src/vm_service.rs
index cfc3884..44013c9 100644
--- a/microdroid/vm_payload/src/vm_service.rs
+++ b/microdroid/vm_payload/src/vm_service.rs
@@ -23,7 +23,7 @@
/// 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 @@
///
/// # 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 @@
}
/// 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 @@
}
/// 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
}
}
}
diff --git a/tests/benchmark/src/native/benchmarkbinary.cpp b/tests/benchmark/src/native/benchmarkbinary.cpp
index 36784b9..4e3c14d 100644
--- a/tests/benchmark/src/native/benchmarkbinary.cpp
+++ b/tests/benchmark/src/native/benchmarkbinary.cpp
@@ -158,7 +158,7 @@
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();
}
diff --git a/tests/testapk/src/native/testbinary.cpp b/tests/testapk/src/native/testbinary.cpp
index 5d6e901..003aca8 100644
--- a/tests/testapk/src/native/testbinary.cpp
+++ b/tests/testapk/src/native/testbinary.cpp
@@ -75,41 +75,48 @@
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();
}