Skip to content

Commit 711387a

Browse files
committed
[common/input_output] making input_output stacks portable
If there's a mismatch in the guest's usize and the host's usize, our input and output stacks would break. This commit fixes that by using u64 instead of usize for ptr accesses. Signed-off-by: danbugs <[email protected]>
1 parent a6fa9b4 commit 711387a

File tree

1 file changed

+54
-46
lines changed

1 file changed

+54
-46
lines changed

src/hyperlight_common/src/input_output.rs

Lines changed: 54 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -15,133 +15,141 @@ limitations under the License.
1515
*/
1616
use anyhow::{bail, Result};
1717
use alloc::vec::Vec;
18-
use core::any::type_name;
1918
use core::slice::from_raw_parts_mut;
2019

2120
pub struct InputDataSection {
2221
ptr: *mut u8,
23-
len: usize,
22+
len: u64,
2423
}
2524

2625
impl InputDataSection {
27-
pub fn new(ptr: *mut u8, len: usize) -> Self {
26+
pub fn new(ptr: *mut u8, len: u64) -> Self {
2827
InputDataSection { ptr, len }
2928
}
3029

3130
pub fn try_pop_shared_input_data_into<T>(&self) -> Result<T>
3231
where
3332
T: for<'a> TryFrom<&'a [u8]>,
3433
{
35-
let input_data_buffer = unsafe { from_raw_parts_mut(self.ptr, self.len) };
34+
let shared_buffer_size = self.len as usize;
3635

37-
if input_data_buffer.is_empty() {
38-
bail!("Got a 0-size buffer in pop_shared_input_data_into");
36+
let idb = unsafe {
37+
from_raw_parts_mut(self.ptr, shared_buffer_size)
38+
};
39+
40+
if idb.is_empty() {
41+
bail!("Got a 0-size buffer in try_pop_shared_input_data_into");
3942
}
4043

4144
// get relative offset to next free address
42-
let stack_ptr_rel: usize = usize::from_le_bytes(
43-
input_data_buffer[..8]
44-
.try_into()
45-
.expect("Shared input buffer too small"),
46-
);
45+
let stack_ptr_rel: u64 = u64::from_le_bytes(match idb[..8].try_into() {
46+
Ok(bytes) => bytes,
47+
Err(_) => bail!("shared input buffer too small"),
48+
});
4749

48-
if stack_ptr_rel > self.len || stack_ptr_rel < 16 {
49-
bail!("Invalid stack pointer: {} in pop_shared_input_data_into", stack_ptr_rel);
50+
if stack_ptr_rel as usize > shared_buffer_size || stack_ptr_rel < 16 {
51+
bail!("Invalid stack pointer: {} in try_pop_shared_input_data_into", stack_ptr_rel);
5052
}
5153

5254
// go back 8 bytes and read. This is the offset to the element on top of stack
53-
let last_element_offset_rel = usize::from_le_bytes(
54-
input_data_buffer[stack_ptr_rel - 8..stack_ptr_rel]
55-
.try_into()
56-
.expect("Invalid stack pointer in pop_shared_input_data_into"),
55+
let last_element_offset_rel = u64::from_le_bytes(
56+
match idb[stack_ptr_rel as usize - 8..stack_ptr_rel as usize].try_into() {
57+
Ok(bytes) => bytes,
58+
Err(_) => bail!("Invalid stack pointer in pop_shared_input_data_into")
59+
},
5760
);
5861

59-
let buffer = &input_data_buffer[last_element_offset_rel..];
62+
let buffer = &idb[last_element_offset_rel as usize..];
6063

6164
// convert the buffer to T
6265
let type_t = match T::try_from(buffer) {
6366
Ok(t) => Ok(t),
64-
Err(_e) => {
65-
bail!("Unable to convert buffer to {}", type_name::<T>());
66-
}
67+
Err(_e) => bail!("failed to convert buffer to type T in pop_shared_input_data_into"),
6768
};
6869

6970
// update the stack pointer to point to the element we just popped of since that is now free
70-
input_data_buffer[..8].copy_from_slice(&last_element_offset_rel.to_le_bytes());
71+
idb[..8].copy_from_slice(&last_element_offset_rel.to_le_bytes());
7172

7273
// zero out popped off buffer
73-
input_data_buffer[last_element_offset_rel..stack_ptr_rel].fill(0);
74+
idb[last_element_offset_rel as usize..stack_ptr_rel as usize].fill(0);
7475

7576
type_t
7677
}
7778
}
7879

7980
pub struct OutputDataSection {
8081
pub ptr: *mut u8,
81-
pub len: usize,
82+
pub len: u64,
8283
}
8384

8485
impl OutputDataSection {
85-
pub fn new(ptr: *mut u8, len: usize) -> Self {
86+
const STACK_PTR_SIZE: usize = size_of::<u64>();
87+
88+
pub fn new(ptr: *mut u8, len: u64) -> Self {
8689
OutputDataSection { ptr, len }
8790
}
8891

8992
pub fn push_shared_output_data(&self, data: Vec<u8>) -> Result<()> {
90-
let output_data_buffer = unsafe { from_raw_parts_mut(self.ptr, self.len) };
93+
let shared_buffer_size = self.len as usize;
94+
let odb: &mut [u8] =
95+
unsafe { from_raw_parts_mut(self.ptr, shared_buffer_size) };
9196

92-
if output_data_buffer.is_empty() {
93-
bail!("Got a 0-size buffer in push_shared_output_data");
97+
if odb.len() < Self::STACK_PTR_SIZE {
98+
bail!("shared output buffer is too small");
9499
}
95100

96101
// get offset to next free address on the stack
97-
let mut stack_ptr_rel: usize = usize::from_le_bytes(
98-
output_data_buffer[..8]
99-
.try_into()
100-
.expect("Shared output buffer too small"),
101-
);
102+
let mut stack_ptr_rel: u64 = u64::from_le_bytes(match odb[..Self::STACK_PTR_SIZE].try_into() {
103+
Ok(bytes) => bytes,
104+
Err(_) => bail!("failed to get stack pointer in shared output buffer"),
105+
});
102106

107+
// if stack_ptr_rel is 0, it means this is the first time we're using the output buffer, so
108+
// we want to offset it by 8 as to not overwrite the stack_ptr location.
103109
if stack_ptr_rel == 0 {
104110
stack_ptr_rel = 8;
105111
}
106112

107113
// check if the stack pointer is within the bounds of the buffer.
108114
// It can be equal to the size, but never greater
109115
// It can never be less than 8. An empty buffer's stack pointer is 8
110-
if stack_ptr_rel > self.len || stack_ptr_rel < 8 {
111-
bail!("Invalid stack pointer: {} in push_shared_output_data", stack_ptr_rel);
116+
if stack_ptr_rel as usize > shared_buffer_size {
117+
bail!("invalid stack pointer in shared output buffer");
112118
}
113119

114120
// check if there is enough space in the buffer
115-
let size_required = data.len() + 8; // the data plus the pointer pointing to the data
116-
let size_available = self.len - stack_ptr_rel;
121+
let size_required: usize = data.len() + 8; // the data plus the pointer pointing to the data
122+
let size_available: usize = shared_buffer_size - stack_ptr_rel as usize;
117123
if size_required > size_available {
118-
bail!("Not enough space in shared output buffer. Required: {}, Available: {}", size_required, size_available);
124+
bail!("not enough space in shared output buffer");
119125
}
120126

121127
// write the actual data
122-
output_data_buffer[stack_ptr_rel..stack_ptr_rel + data.len()].copy_from_slice(&data);
128+
odb[stack_ptr_rel as usize..stack_ptr_rel as usize + data.len()].copy_from_slice(&data);
123129

124130
// write the offset to the newly written data, to the top of the stack
125-
let bytes = stack_ptr_rel.to_le_bytes();
126-
output_data_buffer[stack_ptr_rel + data.len()..stack_ptr_rel + data.len() + 8]
131+
let bytes: [u8; Self::STACK_PTR_SIZE] = stack_ptr_rel.to_le_bytes();
132+
odb[stack_ptr_rel as usize + data.len()
133+
..stack_ptr_rel as usize + data.len() + Self::STACK_PTR_SIZE]
127134
.copy_from_slice(&bytes);
128135

129136
// update stack pointer to point to next free address
130-
let new_stack_ptr_rel = stack_ptr_rel + data.len() + 8;
131-
output_data_buffer[0..8].copy_from_slice(&new_stack_ptr_rel.to_le_bytes());
137+
let new_stack_ptr_rel: u64 =
138+
(stack_ptr_rel as usize + data.len() + Self::STACK_PTR_SIZE) as u64;
139+
odb[0..Self::STACK_PTR_SIZE].copy_from_slice(&new_stack_ptr_rel.to_le_bytes());
132140

133141
Ok(())
134142
}
135143
}
136144

137145
impl From<(u64, u64)> for InputDataSection {
138146
fn from((ptr, len): (u64, u64)) -> Self {
139-
InputDataSection::new(ptr as *mut u8, len as usize)
147+
InputDataSection::new(ptr as *mut u8, len)
140148
}
141149
}
142150

143151
impl From<(u64, u64)> for OutputDataSection {
144152
fn from((ptr, len): (u64, u64)) -> Self {
145-
OutputDataSection::new(ptr as *mut u8, len as usize)
153+
OutputDataSection::new(ptr as *mut u8, len)
146154
}
147-
}
155+
}

0 commit comments

Comments
 (0)