Skip to content

Commit 88079b4

Browse files
authored
Make table/memory allocation functions safe (#11320)
These were previously marked as `unsafe` trait methods with a requirement that the memory/table shape must be validated ahead of time. Neither the ondemand nor pooling allocator actually has an unsafe contract to uphold with respect to this and both may assert/reject non-validated shapes but memory unsafety won't happen as a result. Consequently these functions are made safe. Instance allocation functions are adjusted to reflect how the correctness of `imports` is required for the functions to be safe.
1 parent 686ea89 commit 88079b4

File tree

6 files changed

+46
-68
lines changed

6 files changed

+46
-68
lines changed

crates/wasmtime/src/runtime/store.rs

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1461,12 +1461,10 @@ impl StoreOpaque {
14611461
let mem_ty = engine.tunables().gc_heap_memory_type();
14621462
let tunables = engine.tunables();
14631463

1464-
// SAFETY: We validated the GC heap's memory type during engine creation.
1465-
let (mem_alloc_index, mem) = unsafe {
1464+
let (mem_alloc_index, mem) =
14661465
engine
14671466
.allocator()
1468-
.allocate_memory(&mut request, &mem_ty, tunables, None)?
1469-
};
1467+
.allocate_memory(&mut request, &mem_ty, tunables, None)?;
14701468

14711469
// Then, allocate the actual GC heap, passing in that memory
14721470
// storage.
@@ -2062,10 +2060,8 @@ at https://bytecodealliance.org/security.
20622060
///
20632061
/// # Safety
20642062
///
2065-
/// The request's associated module, memories, tables, and vmctx must have
2066-
/// already have been validated by `validate_module` for the allocator
2067-
/// configured. This is typically done during module construction for
2068-
/// example.
2063+
/// The `imports` provided must be correctly sized/typed for the module
2064+
/// being allocated.
20692065
pub(crate) unsafe fn allocate_instance(
20702066
&mut self,
20712067
kind: AllocateInstanceKind<'_>,
@@ -2078,16 +2074,20 @@ at https://bytecodealliance.org/security.
20782074
AllocateInstanceKind::Module(_) => self.engine().allocator(),
20792075
AllocateInstanceKind::Dummy { allocator } => allocator,
20802076
};
2081-
let handle = allocator.allocate_module(InstanceAllocationRequest {
2082-
id,
2083-
runtime_info,
2084-
imports,
2085-
store: StorePtr::new(self.traitobj()),
2086-
#[cfg(feature = "wmemcheck")]
2087-
wmemcheck: self.engine().config().wmemcheck,
2088-
pkey: self.get_pkey(),
2089-
tunables: self.engine().tunables(),
2090-
})?;
2077+
// SAFETY: this function's own contract is the same as
2078+
// `allocate_module`, namely the imports provided are valid.
2079+
let handle = unsafe {
2080+
allocator.allocate_module(InstanceAllocationRequest {
2081+
id,
2082+
runtime_info,
2083+
imports,
2084+
store: StorePtr::new(self.traitobj()),
2085+
#[cfg(feature = "wmemcheck")]
2086+
wmemcheck: self.engine().config().wmemcheck,
2087+
pkey: self.get_pkey(),
2088+
tunables: self.engine().tunables(),
2089+
})?
2090+
};
20912091

20922092
let actual = match kind {
20932093
AllocateInstanceKind::Module(module_id) => {

crates/wasmtime/src/runtime/trampoline/memory.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ unsafe impl InstanceAllocatorImpl for SingleMemoryInstance<'_> {
165165
self.ondemand.decrement_core_instance_count();
166166
}
167167

168-
unsafe fn allocate_memory(
168+
fn allocate_memory(
169169
&self,
170170
request: &mut InstanceAllocationRequest,
171171
ty: &wasmtime_environ::Memory,
@@ -201,7 +201,7 @@ unsafe impl InstanceAllocatorImpl for SingleMemoryInstance<'_> {
201201
.deallocate_memory(memory_index, allocation_index, memory)
202202
}
203203

204-
unsafe fn allocate_table(
204+
fn allocate_table(
205205
&self,
206206
req: &mut InstanceAllocationRequest,
207207
ty: &wasmtime_environ::Table,

crates/wasmtime/src/runtime/vm/instance.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,13 @@ impl Instance {
270270
///
271271
/// It is assumed the memory was properly aligned and the
272272
/// allocation was `alloc_size` in bytes.
273-
fn new(
273+
///
274+
/// # Safety
275+
///
276+
/// The `req.imports` field must be appropriately sized/typed for the module
277+
/// being allocated according to `req.runtime_info`. Additionally `memories`
278+
/// and `tables` must have been allocated for `req.store`.
279+
unsafe fn new(
274280
req: InstanceAllocationRequest,
275281
memories: PrimaryMap<DefinedMemoryIndex, (MemoryAllocationIndex, Memory)>,
276282
tables: PrimaryMap<DefinedTableIndex, (TableAllocationIndex, Table)>,

crates/wasmtime/src/runtime/vm/instance/allocator.rs

Lines changed: 15 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -253,13 +253,7 @@ pub unsafe trait InstanceAllocatorImpl {
253253
fn decrement_core_instance_count(&self);
254254

255255
/// Allocate a memory for an instance.
256-
///
257-
/// # Unsafety
258-
///
259-
/// The memory and its associated module must have already been validated by
260-
/// `Self::validate_memory` (or transtively via
261-
/// `Self::validate_{module,component}`) and passed that validation.
262-
unsafe fn allocate_memory(
256+
fn allocate_memory(
263257
&self,
264258
request: &mut InstanceAllocationRequest,
265259
ty: &wasmtime_environ::Memory,
@@ -282,12 +276,7 @@ pub unsafe trait InstanceAllocatorImpl {
282276
);
283277

284278
/// Allocate a table for an instance.
285-
///
286-
/// # Unsafety
287-
///
288-
/// The table and its associated module must have already been validated by
289-
/// `Self::validate_module` and passed that validation.
290-
unsafe fn allocate_table(
279+
fn allocate_table(
291280
&self,
292281
req: &mut InstanceAllocationRequest,
293282
table: &wasmtime_environ::Table,
@@ -409,10 +398,10 @@ pub trait InstanceAllocator: InstanceAllocatorImpl {
409398
/// Note that the returned instance must still have `.initialize(..)` called
410399
/// on it to complete the instantiation process.
411400
///
412-
/// # Unsafety
401+
/// # Safety
413402
///
414-
/// The request's associated module, memories, tables, and vmctx must have
415-
/// already have been validated by `Self::validate_module`.
403+
/// The `request` provided must be valid, e.g. the imports within are
404+
/// correctly sized/typed for the instance being created.
416405
unsafe fn allocate_module(
417406
&self,
418407
mut request: InstanceAllocationRequest,
@@ -432,15 +421,14 @@ pub trait InstanceAllocator: InstanceAllocatorImpl {
432421
let mut tables = PrimaryMap::with_capacity(num_defined_tables);
433422

434423
match (|| {
435-
// SAFETY: validation of tables/memories is a contract of this
436-
// function.
437-
unsafe {
438-
self.allocate_memories(&mut request, &mut memories)?;
439-
self.allocate_tables(&mut request, &mut tables)?;
440-
}
424+
self.allocate_memories(&mut request, &mut memories)?;
425+
self.allocate_tables(&mut request, &mut tables)?;
441426
Ok(())
442427
})() {
443-
Ok(_) => Ok(Instance::new(request, memories, tables, &module.memories)),
428+
// SAFETY: memories/tables were just allocated from the store within
429+
// `request` and this function's own contract requires that the
430+
// imports are valid.
431+
Ok(_) => unsafe { Ok(Instance::new(request, memories, tables, &module.memories)) },
444432
Err(e) => {
445433
// SAFETY: these were previously allocated by this allocator
446434
unsafe {
@@ -475,12 +463,7 @@ pub trait InstanceAllocator: InstanceAllocatorImpl {
475463

476464
/// Allocate the memories for the given instance allocation request, pushing
477465
/// them into `memories`.
478-
///
479-
/// # Unsafety
480-
///
481-
/// The request's associated module and memories must have previously been
482-
/// validated by `Self::validate_module`.
483-
unsafe fn allocate_memories(
466+
fn allocate_memories(
484467
&self,
485468
request: &mut InstanceAllocationRequest,
486469
memories: &mut PrimaryMap<DefinedMemoryIndex, (MemoryAllocationIndex, Memory)>,
@@ -496,10 +479,7 @@ pub trait InstanceAllocator: InstanceAllocatorImpl {
496479
.defined_memory_index(memory_index)
497480
.expect("should be a defined memory since we skipped imported ones");
498481

499-
// SAFETY: validation of the memory from this allocator is itself a
500-
// contract of this function.
501-
let memory =
502-
unsafe { self.allocate_memory(request, ty, request.tunables, Some(memory_index))? };
482+
let memory = self.allocate_memory(request, ty, request.tunables, Some(memory_index))?;
503483
memories.push(memory);
504484
}
505485

@@ -533,12 +513,7 @@ pub trait InstanceAllocator: InstanceAllocatorImpl {
533513

534514
/// Allocate tables for the given instance allocation request, pushing them
535515
/// into `tables`.
536-
///
537-
/// # Unsafety
538-
///
539-
/// The request's associated module and tables must have previously been
540-
/// validated by `Self::validate_module`.
541-
unsafe fn allocate_tables(
516+
fn allocate_tables(
542517
&self,
543518
request: &mut InstanceAllocationRequest,
544519
tables: &mut PrimaryMap<DefinedTableIndex, (TableAllocationIndex, Table)>,
@@ -554,10 +529,7 @@ pub trait InstanceAllocator: InstanceAllocatorImpl {
554529
.defined_table_index(index)
555530
.expect("should be a defined table since we skipped imported ones");
556531

557-
// SAFETY: the contract here is that the table has been validated by
558-
// this allocator which is a contract of this function itself.
559-
let table =
560-
unsafe { self.allocate_table(request, table, request.tunables, def_index)? };
532+
let table = self.allocate_table(request, table, request.tunables, def_index)?;
561533
tables.push(table);
562534
}
563535

crates/wasmtime/src/runtime/vm/instance/allocator/on_demand.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ unsafe impl InstanceAllocatorImpl for OnDemandInstanceAllocator {
110110

111111
fn decrement_core_instance_count(&self) {}
112112

113-
unsafe fn allocate_memory(
113+
fn allocate_memory(
114114
&self,
115115
request: &mut InstanceAllocationRequest,
116116
ty: &wasmtime_environ::Memory,
@@ -154,7 +154,7 @@ unsafe impl InstanceAllocatorImpl for OnDemandInstanceAllocator {
154154
// Normal destructors do all the necessary clean up.
155155
}
156156

157-
unsafe fn allocate_table(
157+
fn allocate_table(
158158
&self,
159159
request: &mut InstanceAllocationRequest,
160160
ty: &wasmtime_environ::Table,

crates/wasmtime/src/runtime/vm/instance/allocator/pooling.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -622,7 +622,7 @@ unsafe impl InstanceAllocatorImpl for PoolingInstanceAllocator {
622622
self.live_core_instances.fetch_sub(1, Ordering::AcqRel);
623623
}
624624

625-
unsafe fn allocate_memory(
625+
fn allocate_memory(
626626
&self,
627627
request: &mut InstanceAllocationRequest,
628628
ty: &wasmtime_environ::Memory,
@@ -663,7 +663,7 @@ unsafe impl InstanceAllocatorImpl for PoolingInstanceAllocator {
663663
self.merge_or_flush(queue);
664664
}
665665

666-
unsafe fn allocate_table(
666+
fn allocate_table(
667667
&self,
668668
request: &mut InstanceAllocationRequest,
669669
ty: &wasmtime_environ::Table,

0 commit comments

Comments
 (0)