Skip to content

Commit dd654f5

Browse files
committed
[host/mem] added 'init data' region to store additional guest blob
+ if guest blob is provided, we now write it to shared mem when creating a sandbox Signed-off-by: danbugs <danilochiarlone@gmail.com>
1 parent e42058c commit dd654f5

File tree

6 files changed

+149
-22
lines changed

6 files changed

+149
-22
lines changed

src/hyperlight_host/src/mem/layout.rs

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,20 @@ use rand::{RngCore, rng};
2121
use tracing::{Span, instrument};
2222

2323
use super::memory_region::MemoryRegionType::{
24-
Code, GuardPage, Heap, HostFunctionDefinitions, InputData, OutputData, PageTables, Peb, Stack,
24+
Code, GuardPage, Heap, HostFunctionDefinitions, InitData, InputData, OutputData, PageTables,
25+
Peb, Stack,
26+
};
27+
use super::memory_region::{
28+
DEFAULT_GUEST_BLOB_MEM_FLAGS, MemoryRegion, MemoryRegionFlags, MemoryRegionVecBuilder,
2529
};
26-
use super::memory_region::{MemoryRegion, MemoryRegionFlags, MemoryRegionVecBuilder};
2730
use super::mgr::AMOUNT_OF_MEMORY_PER_PT;
2831
use super::shared_mem::{ExclusiveSharedMemory, GuestSharedMemory, SharedMemory};
2932
use crate::error::HyperlightError::{GuestOffsetIsInvalid, MemoryRequestTooBig};
3033
use crate::sandbox::SandboxConfiguration;
3134
use crate::{Result, new_error};
3235

36+
// +-------------------------------------------+
37+
// | Init Data | (GuestBlob size)
3338
// +-------------------------------------------+
3439
// | Guest (User) Stack |
3540
// +-------------------------------------------+
@@ -56,6 +61,8 @@ use crate::{Result, new_error};
5661
// | PML4 |
5762
// +-------------------------------------------+ 0x0_000
5863

64+
/// - `InitData` - some extra data that can be loaded onto the sandbox during
65+
/// initialization.
5966
///
6067
/// - `HostDefinitions` - the length of this is the `HostFunctionDefinitionSize`
6168
/// field from `SandboxConfiguration`
@@ -82,6 +89,7 @@ pub(crate) struct SandboxMemoryLayout {
8289
pub(super) stack_size: usize,
8390
/// The heap size of this sandbox.
8491
pub(super) heap_size: usize,
92+
init_data_size: usize,
8593

8694
/// The following fields are offsets to the actual PEB struct fields.
8795
/// They are used when writing the PEB struct itself
@@ -103,6 +111,7 @@ pub(crate) struct SandboxMemoryLayout {
103111
guest_heap_buffer_offset: usize,
104112
guard_page_offset: usize,
105113
guest_user_stack_buffer_offset: usize, // the lowest address of the user stack
114+
init_data_offset: usize,
106115

107116
// other
108117
pub(crate) peb_address: usize,
@@ -111,6 +120,7 @@ pub(crate) struct SandboxMemoryLayout {
111120
total_page_table_size: usize,
112121
// The offset in the sandbox memory where the code starts
113122
guest_code_offset: usize,
123+
pub(crate) init_data_permissions: Option<MemoryRegionFlags>,
114124
}
115125

116126
impl Debug for SandboxMemoryLayout {
@@ -122,6 +132,10 @@ impl Debug for SandboxMemoryLayout {
122132
)
123133
.field("Stack Size", &format_args!("{:#x}", self.stack_size))
124134
.field("Heap Size", &format_args!("{:#x}", self.heap_size))
135+
.field(
136+
"Init Data Size",
137+
&format_args!("{:#x}", self.init_data_size),
138+
)
125139
.field("PEB Address", &format_args!("{:#x}", self.peb_address))
126140
.field("PEB Offset", &format_args!("{:#x}", self.peb_offset))
127141
.field("Code Size", &format_args!("{:#x}", self.code_size))
@@ -181,6 +195,10 @@ impl Debug for SandboxMemoryLayout {
181195
"Guest User Stack Buffer Offset",
182196
&format_args!("{:#x}", self.guest_user_stack_buffer_offset),
183197
)
198+
.field(
199+
"Init Data Offset",
200+
&format_args!("{:#x}", self.init_data_offset),
201+
)
184202
.field(
185203
"Page Table Size",
186204
&format_args!("{:#x}", self.total_page_table_size),
@@ -231,6 +249,8 @@ impl SandboxMemoryLayout {
231249
code_size: usize,
232250
stack_size: usize,
233251
heap_size: usize,
252+
init_data_size: usize,
253+
init_data_permissions: Option<MemoryRegionFlags>,
234254
) -> Result<Self> {
235255
let total_page_table_size =
236256
Self::get_total_page_table_size(cfg, code_size, stack_size, heap_size);
@@ -275,6 +295,7 @@ impl SandboxMemoryLayout {
275295
let guest_user_stack_buffer_offset = guard_page_offset + PAGE_SIZE_USIZE;
276296
// round up stack size to page size. This is needed for MemoryRegion
277297
let stack_size_rounded = round_up_to(stack_size, PAGE_SIZE_USIZE);
298+
let init_data_offset = guest_user_stack_buffer_offset + stack_size_rounded;
278299

279300
Ok(Self {
280301
peb_offset,
@@ -299,6 +320,9 @@ impl SandboxMemoryLayout {
299320
guard_page_offset,
300321
total_page_table_size,
301322
guest_code_offset,
323+
init_data_offset,
324+
init_data_size,
325+
init_data_permissions,
302326
})
303327
}
304328

@@ -444,7 +468,7 @@ impl SandboxMemoryLayout {
444468
/// layout.
445469
#[instrument(skip_all, parent = Span::current(), level= "Trace")]
446470
fn get_unaligned_memory_size(&self) -> usize {
447-
self.get_top_of_user_stack_offset() + self.stack_size
471+
self.init_data_offset + self.init_data_size
448472
}
449473

450474
/// get the code offset
@@ -682,12 +706,31 @@ impl SandboxMemoryLayout {
682706
}
683707

684708
// stack
685-
let final_offset = builder.push_page_aligned(
709+
let init_data_offset = builder.push_page_aligned(
686710
self.get_guest_stack_size(),
687711
MemoryRegionFlags::READ | MemoryRegionFlags::WRITE,
688712
Stack,
689713
);
690714

715+
let expected_init_data_offset = TryInto::<usize>::try_into(self.init_data_offset)?;
716+
717+
if init_data_offset != expected_init_data_offset {
718+
return Err(new_error!(
719+
"Init Data offset does not match expected Init Data offset expected: {}, actual: {}",
720+
expected_init_data_offset,
721+
init_data_offset
722+
));
723+
}
724+
725+
let final_offset = if self.init_data_size > 0 {
726+
let mem_flags = self
727+
.init_data_permissions
728+
.unwrap_or(DEFAULT_GUEST_BLOB_MEM_FLAGS);
729+
builder.push_page_aligned(self.init_data_size, mem_flags, InitData)
730+
} else {
731+
init_data_offset
732+
};
733+
691734
let expected_final_offset = TryInto::<usize>::try_into(self.get_memory_size()?)?;
692735

693736
if final_offset != expected_final_offset {
@@ -701,6 +744,16 @@ impl SandboxMemoryLayout {
701744
Ok(builder.build())
702745
}
703746

747+
#[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")]
748+
pub(crate) fn write_init_data(
749+
&self,
750+
shared_mem: &mut ExclusiveSharedMemory,
751+
bytes: &[u8],
752+
) -> Result<()> {
753+
shared_mem.copy_from_slice(bytes, self.init_data_offset)?;
754+
Ok(())
755+
}
756+
704757
/// Write the finished memory layout to `shared_mem` and return
705758
/// `Ok` if successful.
706759
///
@@ -869,7 +922,8 @@ mod tests {
869922
#[test]
870923
fn test_get_memory_size() {
871924
let sbox_cfg = SandboxConfiguration::default();
872-
let sbox_mem_layout = SandboxMemoryLayout::new(sbox_cfg, 4096, 2048, 4096).unwrap();
925+
let sbox_mem_layout =
926+
SandboxMemoryLayout::new(sbox_cfg, 4096, 2048, 4096, 0, None).unwrap();
873927
assert_eq!(
874928
sbox_mem_layout.get_memory_size().unwrap(),
875929
get_expected_memory_size(&sbox_mem_layout)

src/hyperlight_host/src/mem/memory_region.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ use mshv_bindings::{hv_x64_memory_intercept_message, mshv_user_mem_region};
4343
#[cfg(target_os = "windows")]
4444
use windows::Win32::System::Hypervisor::{self, WHV_MEMORY_ACCESS_TYPE};
4545

46+
use super::mgr::{PAGE_NX, PAGE_PRESENT, PAGE_RW, PAGE_USER};
47+
48+
pub(crate) const DEFAULT_GUEST_BLOB_MEM_FLAGS: MemoryRegionFlags = MemoryRegionFlags::READ;
49+
4650
bitflags! {
4751
/// flags representing memory permission for a memory region
4852
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
@@ -60,6 +64,30 @@ bitflags! {
6064
}
6165
}
6266

67+
impl MemoryRegionFlags {
68+
pub(crate) fn translate_flags(&self) -> u64 {
69+
let mut page_flags = 0;
70+
71+
page_flags |= PAGE_PRESENT; // Mark page as present
72+
73+
if self.contains(MemoryRegionFlags::WRITE) {
74+
page_flags |= PAGE_RW; // Allow read/write
75+
}
76+
77+
if self.contains(MemoryRegionFlags::STACK_GUARD) {
78+
page_flags |= PAGE_RW; // The guard page is marked RW so that if it gets written to we can detect it in the host
79+
}
80+
81+
if self.contains(MemoryRegionFlags::EXECUTE) {
82+
page_flags |= PAGE_USER; // Allow user access
83+
} else {
84+
page_flags |= PAGE_NX; // Mark as non-executable if EXECUTE is not set
85+
}
86+
87+
page_flags
88+
}
89+
}
90+
6391
impl std::fmt::Display for MemoryRegionFlags {
6492
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
6593
if self.is_empty() {
@@ -129,6 +157,8 @@ pub enum MemoryRegionType {
129157
PageTables,
130158
/// The region contains the guest's code
131159
Code,
160+
/// The region contains the guest's init data
161+
InitData,
132162
/// The region contains the PEB
133163
Peb,
134164
/// The region contains the Host Function Definitions

src/hyperlight_host/src/mem/mgr.rs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,14 @@ use tracing::{Span, instrument};
2828

2929
use super::exe::ExeInfo;
3030
use super::layout::SandboxMemoryLayout;
31-
use super::memory_region::{MemoryRegion, MemoryRegionType};
31+
use super::memory_region::{DEFAULT_GUEST_BLOB_MEM_FLAGS, MemoryRegion, MemoryRegionType};
3232
use super::ptr::{GuestPtr, RawPtr};
3333
use super::ptr_offset::Offset;
3434
use super::shared_mem::{ExclusiveSharedMemory, GuestSharedMemory, HostSharedMemory, SharedMemory};
3535
use super::shared_mem_snapshot::SharedMemorySnapshot;
3636
use crate::error::HyperlightError::NoMemorySnapshot;
3737
use crate::sandbox::SandboxConfiguration;
38+
use crate::sandbox::uninitialized::GuestBlob;
3839
use crate::{HyperlightError, Result, log_then_return, new_error};
3940

4041
/// Paging Flags
@@ -43,10 +44,10 @@ use crate::{HyperlightError, Result, log_then_return, new_error};
4344
///
4445
/// * Very basic description: https://stackoverflow.com/a/26945892
4546
/// * More in-depth descriptions: https://wiki.osdev.org/Paging
46-
const PAGE_PRESENT: u64 = 1; // Page is Present
47-
const PAGE_RW: u64 = 1 << 1; // Page is Read/Write (if not set page is read only so long as the WP bit in CR0 is set to 1 - which it is in Hyperlight)
48-
const PAGE_USER: u64 = 1 << 2; // User/Supervisor (if this bit is set then the page is accessible by user mode code)
49-
const PAGE_NX: u64 = 1 << 63; // Execute Disable (if this bit is set then data in the page cannot be executed)
47+
pub(crate) const PAGE_PRESENT: u64 = 1; // Page is Present
48+
pub(crate) const PAGE_RW: u64 = 1 << 1; // Page is Read/Write (if not set page is read only so long as the WP bit in CR0 is set to 1 - which it is in Hyperlight)
49+
pub(crate) const PAGE_USER: u64 = 1 << 2; // User/Supervisor (if this bit is set then the page is accessible by user mode code)
50+
pub(crate) const PAGE_NX: u64 = 1 << 63; // Execute Disable (if this bit is set then data in the page cannot be executed)
5051

5152
// The amount of memory that can be mapped per page table
5253
pub(super) const AMOUNT_OF_MEMORY_PER_PT: usize = 0x200_000;
@@ -158,6 +159,11 @@ where
158159
// TODO: We parse and load the exe according to its sections and then
159160
// have the correct flags set rather than just marking the entire binary as executable
160161
MemoryRegionType::Code => PAGE_PRESENT | PAGE_RW | PAGE_USER,
162+
MemoryRegionType::InitData => self
163+
.layout
164+
.init_data_permissions
165+
.map(|perm| perm.translate_flags())
166+
.unwrap_or(DEFAULT_GUEST_BLOB_MEM_FLAGS.translate_flags()),
161167
MemoryRegionType::Stack => PAGE_PRESENT | PAGE_RW | PAGE_USER | PAGE_NX,
162168
#[cfg(feature = "executable_heap")]
163169
MemoryRegionType::Heap => PAGE_PRESENT | PAGE_RW | PAGE_USER,
@@ -286,12 +292,18 @@ impl SandboxMemoryManager<ExclusiveSharedMemory> {
286292
pub(crate) fn load_guest_binary_into_memory(
287293
cfg: SandboxConfiguration,
288294
exe_info: &mut ExeInfo,
295+
guest_blob: Option<&GuestBlob>,
289296
) -> Result<Self> {
297+
let guest_blob_size = guest_blob.map(|b| b.data.len()).unwrap_or(0);
298+
let guest_blob_mem_flags = guest_blob.map(|b| b.permissions);
299+
290300
let layout = SandboxMemoryLayout::new(
291301
cfg,
292302
exe_info.loaded_size(),
293303
usize::try_from(cfg.get_stack_size(exe_info))?,
294304
usize::try_from(cfg.get_heap_size(exe_info))?,
305+
guest_blob_size,
306+
guest_blob_mem_flags,
295307
)?;
296308
let mut shared_mem = ExclusiveSharedMemory::new(layout.get_memory_size()?)?;
297309

src/hyperlight_host/src/sandbox/mem_mgr.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,15 @@ impl MemMgrWrapper<ExclusiveSharedMemory> {
9898
let mem_size = shared_mem.mem_size();
9999
layout.write(shared_mem, SandboxMemoryLayout::BASE_ADDRESS, mem_size)
100100
}
101+
102+
#[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")]
103+
pub(super) fn write_init_data(&mut self, user_memory: &[u8]) -> Result<()> {
104+
let mgr = self.unwrap_mgr_mut();
105+
let layout = mgr.layout;
106+
let shared_mem = mgr.get_shared_mem_mut();
107+
layout.write_init_data(shared_mem, user_memory)?;
108+
Ok(())
109+
}
101110
}
102111

103112
impl MemMgrWrapper<HostSharedMemory> {

src/hyperlight_host/src/sandbox/outb.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -241,9 +241,12 @@ mod tests {
241241

242242
let new_mgr = || {
243243
let mut exe_info = simple_guest_exe_info().unwrap();
244-
let mut mgr =
245-
SandboxMemoryManager::load_guest_binary_into_memory(sandbox_cfg, &mut exe_info)
246-
.unwrap();
244+
let mut mgr = SandboxMemoryManager::load_guest_binary_into_memory(
245+
sandbox_cfg,
246+
&mut exe_info,
247+
None,
248+
)
249+
.unwrap();
247250
let mem_size = mgr.get_shared_mem_mut().mem_size();
248251
let layout = mgr.layout;
249252
let shared_mem = mgr.get_shared_mem_mut();
@@ -353,9 +356,12 @@ mod tests {
353356
tracing::subscriber::with_default(subscriber.clone(), || {
354357
let new_mgr = || {
355358
let mut exe_info = simple_guest_exe_info().unwrap();
356-
let mut mgr =
357-
SandboxMemoryManager::load_guest_binary_into_memory(sandbox_cfg, &mut exe_info)
358-
.unwrap();
359+
let mut mgr = SandboxMemoryManager::load_guest_binary_into_memory(
360+
sandbox_cfg,
361+
&mut exe_info,
362+
None,
363+
)
364+
.unwrap();
359365
let mem_size = mgr.get_shared_mem_mut().mem_size();
360366
let layout = mgr.layout;
361367
let shared_mem = mgr.get_shared_mem_mut();

0 commit comments

Comments
 (0)