hyperlight_guest/
shared_output_data.rs

1/*
2Copyright 2024 The Hyperlight Authors.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8    http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17use alloc::format;
18use alloc::string::ToString;
19use alloc::vec::Vec;
20use core::slice::from_raw_parts_mut;
21
22use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode;
23
24use crate::error::{HyperlightGuestError, Result};
25use crate::P_PEB;
26
27pub fn push_shared_output_data(data: Vec<u8>) -> Result<()> {
28    let peb_ptr = unsafe { P_PEB.unwrap() };
29    let shared_buffer_size = unsafe { (*peb_ptr).output_stack.size as usize };
30    let odb =
31        unsafe { from_raw_parts_mut((*peb_ptr).output_stack.ptr as *mut u8, shared_buffer_size) };
32
33    if odb.is_empty() {
34        return Err(HyperlightGuestError::new(
35            ErrorCode::GuestError,
36            "Got a 0-size buffer in push_shared_output_data".to_string(),
37        ));
38    }
39
40    // get offset to next free address on the stack
41    let stack_ptr_rel: u64 =
42        u64::from_le_bytes(odb[..8].try_into().expect("Shared output buffer too small"));
43
44    // check if the stack pointer is within the bounds of the buffer.
45    // It can be equal to the size, but never greater
46    // It can never be less than 8. An empty buffer's stack pointer is 8
47    if stack_ptr_rel as usize > shared_buffer_size || stack_ptr_rel < 8 {
48        return Err(HyperlightGuestError::new(
49            ErrorCode::GuestError,
50            format!(
51                "Invalid stack pointer: {} in push_shared_output_data",
52                stack_ptr_rel
53            ),
54        ));
55    }
56
57    // check if there is enough space in the buffer
58    let size_required = data.len() + 8; // the data plus the pointer pointing to the data
59    let size_available = shared_buffer_size - stack_ptr_rel as usize;
60    if size_required > size_available {
61        return Err(HyperlightGuestError::new(
62            ErrorCode::GuestError,
63            format!(
64                "Not enough space in shared output buffer. Required: {}, Available: {}",
65                size_required, size_available
66            ),
67        ));
68    }
69
70    // write the actual data
71    odb[stack_ptr_rel as usize..stack_ptr_rel as usize + data.len()].copy_from_slice(&data);
72
73    // write the offset to the newly written data, to the top of the stack
74    let bytes: [u8; 8] = stack_ptr_rel.to_le_bytes();
75    odb[stack_ptr_rel as usize + data.len()..stack_ptr_rel as usize + data.len() + 8]
76        .copy_from_slice(&bytes);
77
78    // update stack pointer to point to next free address
79    let new_stack_ptr_rel: u64 = (stack_ptr_rel as usize + data.len() + 8) as u64;
80    odb[0..8].copy_from_slice(&(new_stack_ptr_rel).to_le_bytes());
81
82    Ok(())
83}