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).outputdata.outputDataSize as usize };
30    let odb = unsafe {
31        from_raw_parts_mut(
32            (*peb_ptr).outputdata.outputDataBuffer as *mut u8,
33            shared_buffer_size,
34        )
35    };
36
37    if odb.is_empty() {
38        return Err(HyperlightGuestError::new(
39            ErrorCode::GuestError,
40            "Got a 0-size buffer in push_shared_output_data".to_string(),
41        ));
42    }
43
44    // get offset to next free address on the stack
45    let stack_ptr_rel: usize =
46        usize::from_le_bytes(odb[..8].try_into().expect("Shared output buffer too small"));
47
48    // check if the stack pointer is within the bounds of the buffer.
49    // It can be equal to the size, but never greater
50    // It can never be less than 8. An empty buffer's stack pointer is 8
51    if stack_ptr_rel > shared_buffer_size || stack_ptr_rel < 8 {
52        return Err(HyperlightGuestError::new(
53            ErrorCode::GuestError,
54            format!(
55                "Invalid stack pointer: {} in push_shared_output_data",
56                stack_ptr_rel
57            ),
58        ));
59    }
60
61    // check if there is enough space in the buffer
62    let size_required = data.len() + 8; // the data plus the pointer pointing to the data
63    let size_available = shared_buffer_size - stack_ptr_rel;
64    if size_required > size_available {
65        return Err(HyperlightGuestError::new(
66            ErrorCode::GuestError,
67            format!(
68                "Not enough space in shared output buffer. Required: {}, Available: {}",
69                size_required, size_available
70            ),
71        ));
72    }
73
74    // write the actual data
75    odb[stack_ptr_rel..stack_ptr_rel + data.len()].copy_from_slice(&data);
76
77    // write the offset to the newly written data, to the top of the stack
78    let bytes = stack_ptr_rel.to_le_bytes();
79    odb[stack_ptr_rel + data.len()..stack_ptr_rel + data.len() + 8].copy_from_slice(&bytes);
80
81    // update stack pointer to point to next free address
82    let new_stack_ptr_rel = stack_ptr_rel + data.len() + 8;
83    odb[0..8].copy_from_slice(&(new_stack_ptr_rel).to_le_bytes());
84
85    Ok(())
86}