Skip to content

Commit 467e7bb

Browse files
committed
Add RawInstance::set_accessible_aux_size
1 parent 8ee6d58 commit 467e7bb

File tree

8 files changed

+169
-7
lines changed

8 files changed

+169
-7
lines changed

crates/polkavm-common/src/zygote.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ define_address_table! {
7171
ext_load_program: unsafe extern "C" fn() -> !,
7272
ext_recycle: unsafe extern "C" fn() -> !,
7373
ext_fetch_idle_regs: unsafe extern "C" fn() -> !,
74+
ext_set_accessible_aux_size: unsafe extern "C" fn() -> !,
7475
}
7576

7677
pub const FD_DUMMY_STDIN: i32 = 0;
@@ -262,6 +263,7 @@ pub struct VmCtx {
262263
pub heap_info: VmCtxHeapInfo,
263264

264265
pub arg2: AtomicU32,
266+
pub arg3: AtomicU32,
265267

266268
/// Offset in shared memory to this sandbox's memory map.
267269
pub shm_memory_map_offset: AtomicU64,
@@ -343,6 +345,7 @@ impl VmCtx {
343345
next_program_counter: AtomicU32::new(0),
344346
arg: AtomicU32::new(0),
345347
arg2: AtomicU32::new(0),
348+
arg3: AtomicU32::new(0),
346349
regs: [ATOMIC_U64_ZERO; REG_COUNT],
347350
jump_into: AtomicU64::new(0),
348351
next_native_program_counter: AtomicU64::new(0),

crates/polkavm-zygote/src/main.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -682,6 +682,7 @@ unsafe fn initialize(mut stack: *mut usize) {
682682
(if a == linux_raw::SYS_rt_sigreturn => jump @1),
683683
(if a == linux_raw::SYS_sched_yield => jump @1),
684684
(if a == linux_raw::SYS_exit => jump @1),
685+
(if a == linux_raw::SYS_mprotect => jump @7),
685686
(seccomp_return_eperm),
686687

687688
// SYS_write
@@ -705,6 +706,13 @@ unsafe fn initialize(mut stack: *mut usize) {
705706
(if a != linux_raw::PROT_EXEC => jump @0),
706707
(seccomp_allow),
707708

709+
// SYS_mprotect
710+
([7]: a = syscall_arg[2]),
711+
(if a != linux_raw::PROT_READ => jump @8),
712+
(seccomp_allow),
713+
([8]: if a != 0 => jump @0),
714+
(seccomp_allow),
715+
708716
([0]: seccomp_return_eperm),
709717
([1]: seccomp_allow),
710718
};
@@ -913,6 +921,7 @@ pub static EXT_TABLE: ExtTableRaw = ExtTableRaw {
913921
ext_load_program,
914922
ext_recycle,
915923
ext_fetch_idle_regs,
924+
ext_set_accessible_aux_size,
916925
};
917926

918927
#[inline(always)]
@@ -1103,3 +1112,39 @@ pub unsafe extern "C" fn ext_fetch_idle_regs() -> ! {
11031112

11041113
signal_host_and_longjmp(VMCTX_FUTEX_IDLE);
11051114
}
1115+
1116+
#[inline(never)]
1117+
pub unsafe extern "C" fn ext_set_accessible_aux_size() -> ! {
1118+
trace!("Entry point: ext_set_accessible_aux_size");
1119+
let address = VMCTX.arg.load(Ordering::Relaxed) as usize;
1120+
let length_accessible = VMCTX.arg2.load(Ordering::Relaxed) as usize;
1121+
let length_full = VMCTX.arg3.load(Ordering::Relaxed) as usize;
1122+
1123+
trace!(
1124+
"Setting inaccessible: ",
1125+
Hex(address),
1126+
"-",
1127+
Hex(address + length_full),
1128+
" (",
1129+
Hex(length_full),
1130+
")"
1131+
);
1132+
1133+
linux_raw::sys_mprotect(address as *mut core::ffi::c_void, length_full, 0)
1134+
.unwrap_or_else(|error| abort_with_error("failed to set accessible aux size: failed to set the region inaccessible", error));
1135+
1136+
trace!(
1137+
"Setting accessible: ",
1138+
Hex(address),
1139+
"-",
1140+
Hex(address + length_accessible),
1141+
" (",
1142+
Hex(length_accessible),
1143+
")"
1144+
);
1145+
1146+
linux_raw::sys_mprotect(address as *mut core::ffi::c_void, length_accessible, linux_raw::PROT_READ)
1147+
.unwrap_or_else(|error| abort_with_error("failed to set accessible aux size: failed to set the region read-only", error));
1148+
1149+
signal_host_and_longjmp(VMCTX_FUTEX_IDLE);
1150+
}

crates/polkavm/src/api.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,10 @@ impl Module {
336336
value & !self.state().page_size_mask
337337
}
338338

339+
pub(crate) fn round_to_page_size_up(&self, value: u32) -> u32 {
340+
self.round_to_page_size_down(value) + (u32::from((value & self.state().page_size_mask) != 0) << self.state().page_shift)
341+
}
342+
339343
pub(crate) fn address_to_page(&self, address: u32) -> u32 {
340344
address >> self.state().page_shift
341345
}
@@ -1034,6 +1038,31 @@ impl RawInstance {
10341038
}
10351039
}
10361040

1041+
/// Sets the accessible region of the aux data, rounded up to the nearest page size.
1042+
pub fn set_accessible_aux_size(&mut self, size: u32) -> Result<(), Error> {
1043+
if self.module.is_dynamic_paging() {
1044+
return Err("setting accessible aux size is only possible on modules without dynamic paging".into());
1045+
}
1046+
1047+
if size > self.module.memory_map().aux_data_size() {
1048+
return Err(format!(
1049+
"cannot set accessible aux size: the maximum is {}, while tried to set {}",
1050+
self.module.memory_map().aux_data_size(),
1051+
size
1052+
)
1053+
.into());
1054+
}
1055+
1056+
let size = self.module.round_to_page_size_up(size);
1057+
if let Some(ref mut crosscheck) = self.crosscheck_instance {
1058+
crosscheck.set_accessible_aux_size(size);
1059+
}
1060+
1061+
access_backend!(self.backend, |mut backend| backend
1062+
.set_accessible_aux_size(size)
1063+
.into_result("failed to set accessible aux size"))
1064+
}
1065+
10371066
/// Resets the VM's memory to its initial state.
10381067
pub fn reset_memory(&mut self) -> Result<(), Error> {
10391068
if let Some(ref mut crosscheck) = self.crosscheck_instance {

crates/polkavm/src/interpreter.rs

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ pub(crate) struct BasicMemory {
8383
aux: Vec<u8>,
8484
is_memory_dirty: bool,
8585
heap_size: u32,
86+
accessible_aux_size: usize,
8687
}
8788

8889
impl BasicMemory {
@@ -93,6 +94,7 @@ impl BasicMemory {
9394
aux: Vec::new(),
9495
is_memory_dirty: false,
9596
heap_size: 0,
97+
accessible_aux_size: usize::MAX,
9698
}
9799
}
98100

@@ -116,6 +118,7 @@ impl BasicMemory {
116118
self.aux.clear();
117119
self.heap_size = 0;
118120
self.is_memory_dirty = false;
121+
self.accessible_aux_size = 0;
119122

120123
if let Some(interpreted_module) = module.interpreted_module().as_ref() {
121124
self.rw_data.extend_from_slice(&interpreted_module.rw_data);
@@ -124,21 +127,26 @@ impl BasicMemory {
124127

125128
// TODO: Do this lazily?
126129
self.aux.resize(cast(module.memory_map().aux_data_size()).to_usize(), 0);
130+
self.accessible_aux_size = cast(module.memory_map().aux_data_size()).to_usize();
127131
}
128132
}
129133

134+
fn set_accessible_aux_size(&mut self, size: u32) {
135+
self.accessible_aux_size = cast(size).to_usize();
136+
}
137+
130138
#[inline]
131139
fn get_memory_slice<'a>(&'a self, module: &'a Module, address: u32, length: u32) -> Option<&'a [u8]> {
132140
let memory_map = module.memory_map();
133141
let (start, memory_slice) = if address >= memory_map.aux_data_address() {
134-
(memory_map.aux_data_address(), &self.aux)
142+
(memory_map.aux_data_address(), &self.aux[..self.accessible_aux_size])
135143
} else if address >= memory_map.stack_address_low() {
136-
(memory_map.stack_address_low(), &self.stack)
144+
(memory_map.stack_address_low(), &self.stack[..])
137145
} else if address >= memory_map.rw_data_address() {
138-
(memory_map.rw_data_address(), &self.rw_data)
146+
(memory_map.rw_data_address(), &self.rw_data[..])
139147
} else if address >= memory_map.ro_data_address() {
140148
let module = module.interpreted_module().unwrap();
141-
(memory_map.ro_data_address(), &module.ro_data)
149+
(memory_map.ro_data_address(), &module.ro_data[..])
142150
} else {
143151
return None;
144152
};
@@ -153,11 +161,11 @@ impl BasicMemory {
153161
fn get_memory_slice_mut<const IS_EXTERNAL: bool>(&mut self, module: &Module, address: u32, length: u32) -> Option<&mut [u8]> {
154162
let memory_map = module.memory_map();
155163
let (start, memory_slice) = if IS_EXTERNAL && address >= memory_map.aux_data_address() {
156-
(memory_map.aux_data_address(), &mut self.aux)
164+
(memory_map.aux_data_address(), &mut self.aux[..self.accessible_aux_size])
157165
} else if address >= memory_map.stack_address_low() {
158-
(memory_map.stack_address_low(), &mut self.stack)
166+
(memory_map.stack_address_low(), &mut self.stack[..])
159167
} else if address >= memory_map.rw_data_address() {
160-
(memory_map.rw_data_address(), &mut self.rw_data)
168+
(memory_map.rw_data_address(), &mut self.rw_data[..])
161169
} else {
162170
return None;
163171
};
@@ -440,6 +448,11 @@ impl InterpretedInstance {
440448
self.next_program_counter_changed = true;
441449
}
442450

451+
pub fn set_accessible_aux_size(&mut self, size: u32) {
452+
assert!(!self.module.is_dynamic_paging());
453+
self.basic_memory.set_accessible_aux_size(size);
454+
}
455+
443456
#[allow(clippy::unused_self)]
444457
pub fn next_native_program_counter(&self) -> Option<usize> {
445458
None

crates/polkavm/src/sandbox.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ pub(crate) trait Sandbox: Sized {
122122
fn next_program_counter(&self) -> Option<ProgramCounter>;
123123
fn next_native_program_counter(&self) -> Option<usize>;
124124
fn set_next_program_counter(&mut self, pc: ProgramCounter);
125+
fn set_accessible_aux_size(&mut self, size: u32) -> Result<(), Self::Error>;
125126
fn reset_memory(&mut self) -> Result<(), Self::Error>;
126127
fn read_memory_into<'slice>(&self, address: u32, slice: &'slice mut [MaybeUninit<u8>]) -> Result<&'slice mut [u8], MemoryAccessError>;
127128
fn write_memory(&mut self, address: u32, data: &[u8]) -> Result<(), MemoryAccessError>;

crates/polkavm/src/sandbox/linux.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -995,6 +995,8 @@ pub struct Sandbox {
995995
page_set: PageSet,
996996
dynamic_paging_enabled: bool,
997997
idle_regs: linux_raw::user_regs_struct,
998+
aux_data_address: u32,
999+
aux_data_length: u32,
9981000
}
9991001

10001002
impl Drop for Sandbox {
@@ -1598,6 +1600,8 @@ impl super::Sandbox for Sandbox {
15981600
page_set: PageSet::new(),
15991601
dynamic_paging_enabled: false,
16001602
idle_regs,
1603+
aux_data_address: 0,
1604+
aux_data_length: 0,
16011605
})
16021606
}
16031607

@@ -1705,6 +1709,8 @@ impl super::Sandbox for Sandbox {
17051709
reg.store(0, Ordering::Relaxed);
17061710
}
17071711

1712+
self.aux_data_address = module.memory_map().aux_data_address();
1713+
self.aux_data_length = module.memory_map().aux_data_size();
17081714
self.dynamic_paging_enabled = module.is_dynamic_paging();
17091715
self.is_program_counter_valid = false;
17101716
self.gas_metering = module.gas_metering();
@@ -1904,6 +1910,20 @@ impl super::Sandbox for Sandbox {
19041910
}
19051911
}
19061912

1913+
fn set_accessible_aux_size(&mut self, size: u32) -> Result<(), Error> {
1914+
assert!(!self.dynamic_paging_enabled);
1915+
1916+
let module = self.module.as_ref().unwrap();
1917+
self.aux_data_length = size;
1918+
self.vmctx().arg.store(self.aux_data_address, Ordering::Relaxed);
1919+
self.vmctx().arg2.store(size, Ordering::Relaxed);
1920+
self.vmctx().arg3.store(module.memory_map().aux_data_size(), Ordering::Relaxed);
1921+
self.vmctx()
1922+
.jump_into
1923+
.store(ZYGOTE_TABLES.1.ext_set_accessible_aux_size, Ordering::Relaxed);
1924+
self.wake_oneshot_and_expect_idle()
1925+
}
1926+
19071927
fn reset_memory(&mut self) -> Result<(), Error> {
19081928
if self.module.is_none() {
19091929
return Err(Error::from_str("no module loaded into the sandbox"));
96 Bytes
Binary file not shown.

crates/polkavm/src/tests.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1823,6 +1823,56 @@ fn aux_data_works(config: Config) {
18231823
assert_eq!(instance.read_u32(module.memory_map().aux_data_address()).unwrap(), 0);
18241824
}
18251825

1826+
fn aux_data_accessible_area(config: Config) {
1827+
let _ = env_logger::try_init();
1828+
let engine = Engine::new(&config).unwrap();
1829+
let page_size = get_native_page_size() as u32;
1830+
let mut builder = ProgramBlobBuilder::new();
1831+
builder.add_export_by_basic_block(0, b"main");
1832+
builder.set_code(&[asm::load_indirect_i32(Reg::A1, Reg::A0, 0), asm::ret()], &[]);
1833+
1834+
let blob = ProgramBlob::parse(builder.into_vec().into()).unwrap();
1835+
let mut module_config = ModuleConfig::new();
1836+
module_config.set_page_size(page_size);
1837+
module_config.set_aux_data_size(2_u32.pow(24));
1838+
let module = Module::from_blob(&engine, &module_config, blob).unwrap();
1839+
let offsets: Vec<_> = module
1840+
.blob()
1841+
.instructions(DefaultInstructionSet::default())
1842+
.map(|inst| inst.offset)
1843+
.collect();
1844+
1845+
let mut instance = module.instantiate().unwrap();
1846+
instance.set_accessible_aux_size(1).unwrap();
1847+
instance.write_u32(module.memory_map().aux_data_address(), 0x12345678).unwrap();
1848+
instance.set_reg(Reg::RA, crate::RETURN_TO_HOST);
1849+
1850+
instance.set_reg(Reg::A0, u64::from(module.memory_map().aux_data_address()));
1851+
instance.set_next_program_counter(offsets[0]);
1852+
match_interrupt!(instance.run().unwrap(), InterruptKind::Finished);
1853+
assert_eq!(instance.reg(Reg::A1), 0x12345678);
1854+
1855+
instance.set_reg(Reg::A0, u64::from(module.memory_map().aux_data_address() + page_size - 4));
1856+
instance.set_next_program_counter(offsets[0]);
1857+
match_interrupt!(instance.run().unwrap(), InterruptKind::Finished);
1858+
1859+
assert!(instance.read_u32(module.memory_map().aux_data_address() + page_size - 4).is_ok());
1860+
1861+
instance.set_reg(Reg::A0, u64::from(module.memory_map().aux_data_address() + page_size - 3));
1862+
instance.set_next_program_counter(offsets[0]);
1863+
match_interrupt!(instance.run().unwrap(), InterruptKind::Trap);
1864+
1865+
assert!(instance.read_u32(module.memory_map().aux_data_address() + page_size - 3).is_err());
1866+
1867+
instance.set_accessible_aux_size(page_size + 1).unwrap();
1868+
1869+
instance.set_reg(Reg::A0, u64::from(module.memory_map().aux_data_address() + page_size - 3));
1870+
instance.set_next_program_counter(offsets[0]);
1871+
match_interrupt!(instance.run().unwrap(), InterruptKind::Finished);
1872+
1873+
assert!(instance.read_u32(module.memory_map().aux_data_address() + page_size - 3).is_ok());
1874+
}
1875+
18261876
fn access_memory_from_host(config: Config) {
18271877
let _ = env_logger::try_init();
18281878
let engine = Engine::new(&config).unwrap();
@@ -2733,6 +2783,7 @@ run_tests! {
27332783
invalid_instruction_after_fallthrough
27342784
invalid_branch_target
27352785
aux_data_works
2786+
aux_data_accessible_area
27362787
access_memory_from_host
27372788
sbrk_knob_works
27382789

0 commit comments

Comments
 (0)