Skip to content

Commit 104a477

Browse files
fix extern spec bug in 'from_raw_parts_mut' to explicitly require alignment and non-overflowing (#51)
1 parent 3bc4a94 commit 104a477

3 files changed

Lines changed: 51 additions & 30 deletions

File tree

flux_support/src/flux_ptr.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -359,9 +359,9 @@ pub fn mem_slices_to_raw_ptrs(flash: &[u8], ram: &mut [u8]) -> Pair<SlicesToRaw,
359359
}
360360

361361
#[flux_rs::trusted(reason = "flux wrappers")]
362-
#[flux_rs::sig(fn (_, usize[@len]) -> &mut [T][len])]
363-
pub fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] {
364-
unsafe { core::slice::from_raw_parts_mut(data, len) }
362+
#[flux_rs::sig(fn (FluxPtr[@ptr], usize[@t_size], usize[@len], usize[@w_size]) -> &mut [T][len * t_size] requires ptr % w_size == 0 && ptr + len * t_size <= u32::MAX)]
363+
pub fn from_raw_parts_mut<'a, T>(data: FluxPtr, t_size: usize, len: usize, w_size: usize) -> &'a mut [T] {
364+
unsafe { core::slice::from_raw_parts_mut(data.unsafe_as_ptr() as *mut T, len) }
365365
}
366366

367367
#[flux_rs::trusted(reason = "flux wrappers")]

kernel/src/allocator.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,8 @@ impl<R: RegionDescriptor + Display + Copy> AppMemoryAllocator<R> {
457457
b.memory_start >= unallocated_memory_start &&
458458
valid_size(b.memory_start + b.memory_size) &&
459459
b.memory_start > 0 &&
460-
b.memory_size >= initial_kernel_memory_size
460+
b.memory_size >= initial_kernel_memory_size &&
461+
(b.memory_start + b.memory_size) - b.kernel_break == initial_kernel_memory_size
461462
}, ()>
462463
requires
463464
valid_size(R::size(ram_regions.fst) + initial_kernel_memory_size) &&
@@ -525,7 +526,8 @@ impl<R: RegionDescriptor + Display + Copy> AppMemoryAllocator<R> {
525526
app.breaks.memory_start >= mem_start &&
526527
valid_size(app.breaks.memory_start + app.breaks.memory_size) &&
527528
app.breaks.memory_start > 0 &&
528-
app.breaks.memory_size >= initial_kernel_memory_size
529+
app.breaks.memory_size >= initial_kernel_memory_size &&
530+
(app.breaks.memory_start + app.breaks.memory_size) - app.breaks.kernel_break == initial_kernel_memory_size
529531
}, AllocateAppMemoryError>
530532
requires valid_size(mem_start + mem_size) && flash_start + flash_size < mem_start
531533
)]

kernel/src/process_standard.rs

Lines changed: 44 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1318,6 +1318,9 @@ impl<C: 'static + Chip> ProcessStandard<'_, C> {
13181318
// Make room for grant pointers.
13191319
let grant_ptr_size = mem::size_of::<GrantPointerEntry>();
13201320
let grant_ptrs_num = kernel.get_grant_count_and_finalize();
1321+
if grant_ptr_size == 0 || usize::MAX / grant_ptr_size < grant_ptrs_num {
1322+
return Err((ProcessLoadError::NotEnoughMemory, remaining_memory));
1323+
}
13211324
let grant_ptrs_offset = grant_ptrs_num * grant_ptr_size;
13221325

13231326
// Initial size of the kernel-owned part of process memory can be
@@ -1332,7 +1335,12 @@ impl<C: 'static + Chip> ProcessStandard<'_, C> {
13321335
// `sizeof(usize)` bytes.
13331336
let upper_bound = (u32::MAX / 4) as usize;
13341337
let usize_size = core::mem::size_of::<usize>();
1335-
let callbacks_offset = Self::CALLBACKS_OFFSET;
1338+
let callbacks_len = Self::CALLBACK_LEN;
1339+
let task_size = core::mem::size_of::<Task>();
1340+
if task_size == 0 || usize::MAX / task_size < callbacks_len {
1341+
return Err((ProcessLoadError::NotEnoughMemory, remaining_memory));
1342+
}
1343+
let callbacks_offset = task_size * callbacks_len;
13361344
let process_struct_offset = Self::PROCESS_STRUCT_OFFSET;
13371345

13381346
if !(process_struct_offset < isize_into_usize(isize::MAX)
@@ -1342,7 +1350,9 @@ impl<C: 'static + Chip> ProcessStandard<'_, C> {
13421350
&& callbacks_offset < upper_bound
13431351
&& 0 < usize_size
13441352
&& usize_size <= 8
1345-
&& grant_ptrs_offset < upper_bound)
1353+
&& grant_ptrs_offset < upper_bound
1354+
&& callbacks_offset % usize_size == 0
1355+
&& grant_ptrs_offset % usize_size == 0)
13461356
{
13471357
return Err((ProcessLoadError::NotEnoughMemory, remaining_memory));
13481358
}
@@ -1582,52 +1592,68 @@ impl<C: 'static + Chip> ProcessStandard<'_, C> {
15821592
// Calling `wrapping_sub` is safe here, as we've factored in an optional
15831593
// padding of at most `sizeof(usize)` bytes in the calculation of
15841594
// `initial_kernel_memory_size` above.
1585-
let mut kernel_memory_break = app_memory_alloc.memory_end();
1595+
let memory_end = app_memory_alloc.memory_end();
1596+
let actual_kernel_break = app_memory_alloc.kernel_break();
1597+
let mut kernel_memory_break = memory_end;
15861598

1599+
// aligned to 4 bytes
15871600
kernel_memory_break =
15881601
kernel_memory_break.wrapping_sub(kernel_memory_break.as_usize() % usize_size);
15891602

15901603
// Now that we know we have the space we can setup the grant pointers.
1591-
// kernel_memory_break = kernel_memory_break.offset(-(grant_ptrs_offset as isize)); // VTOCK TODO: Something about usize cast to isize here?
1604+
let grant_ptrs_offset = usize_into_isize(grant_ptrs_offset);
1605+
kernel_memory_break = kernel_memory_break.offset(-grant_ptrs_offset);
15921606

15931607
// This is safe, `kernel_memory_break` is aligned to a word-boundary,
15941608
// and `grant_ptrs_offset` is a multiple of the word size.
1595-
#[allow(clippy::cast_ptr_alignment)]
15961609
// Set all grant pointers to null.
1597-
let grant_pointers = core::slice::from_raw_parts_mut(
1598-
kernel_memory_break.unsafe_as_ptr() as *mut GrantPointerEntry,
1610+
let grant_pointers: &mut [GrantPointerEntry] = flux_support::from_raw_parts_mut(
1611+
kernel_memory_break,
1612+
grant_ptr_size,
15991613
grant_ptrs_num,
1614+
usize_size,
16001615
);
16011616
for grant_entry in grant_pointers.iter_mut() {
16021617
grant_entry.driver_num = 0;
16031618
grant_entry.grant_ptr = FluxPtr::null_mut();
16041619
}
1620+
// would be nice to have a start addr for grant_pointers but we'll trust its kernel_memory_break
1621+
// assert we aren't overflowing the end of memory
1622+
flux_support::assert(
1623+
kernel_memory_break.as_usize() + grant_pointers.len() <= memory_end.as_usize(),
1624+
);
1625+
let grant_entry_checkpoint = kernel_memory_break;
16051626

16061627
// Now that we know we have the space we can setup the memory for the
16071628
// upcalls.
16081629
let callbacks_isize = usize_into_isize(callbacks_offset);
16091630
kernel_memory_break = kernel_memory_break.offset(-callbacks_isize);
16101631

1611-
// This is safe today, as MPU constraints ensure that `memory_start`
1612-
// will always be aligned on at least a word boundary, and that
1613-
// memory_size will be aligned on at least a word boundary, and
1614-
// `grant_ptrs_offset` is a multiple of the word size. Thus,
1615-
// `kernel_memory_break` must be word aligned. While this is unlikely to
1616-
// change, it should be more proactively enforced.
1617-
//
1618-
// TODO: https://github.com/tock/tock/issues/1739
1619-
#[allow(clippy::cast_ptr_alignment)]
16201632
// Set up ring buffer for upcalls to the process.
16211633
let upcall_buf = flux_support::from_raw_parts_mut(
1622-
kernel_memory_break.unsafe_as_ptr() as *mut Task,
1623-
Self::CALLBACK_LEN,
1634+
kernel_memory_break,
1635+
task_size,
1636+
callbacks_len,
1637+
usize_size,
16241638
);
1639+
// assert we aren't overflowing the start of the grant entries
1640+
flux_support::assert(
1641+
kernel_memory_break.as_usize() + upcall_buf.len() <= grant_entry_checkpoint.as_usize(),
1642+
);
1643+
let upcall_buf_checkpoint = kernel_memory_break;
16251644
let tasks = RingBuffer::new(upcall_buf);
16261645

16271646
// Last thing in the kernel region of process RAM is the process struct.
16281647
let process_struct_offset = usize_into_isize(process_struct_offset);
16291648
kernel_memory_break = kernel_memory_break.offset(-process_struct_offset);
16301649
let process_struct_memory_location = kernel_memory_break;
1650+
flux_support::assert(
1651+
process_struct_memory_location.as_usize() + isize_into_usize(process_struct_offset)
1652+
<= upcall_buf_checkpoint.as_usize(),
1653+
);
1654+
1655+
// assert we don't allocate past the kernel memory break the allocator set up
1656+
flux_support::assert(kernel_memory_break >= actual_kernel_break);
16311657

16321658
// Create the Process struct in the app grant region.
16331659
// Note that this requires every field be explicitly initialized
@@ -1683,13 +1709,6 @@ impl<C: 'static + Chip> ProcessStandard<'_, C> {
16831709
});
16841710

16851711
// Handle any architecture-specific requirements for a new process.
1686-
//
1687-
// NOTE! We have to ensure that the start of process-accessible memory
1688-
// (`app_memory_start`) is word-aligned. Since we currently start
1689-
// process-accessible memory at the beginning of the allocated memory
1690-
// region, we trust the MPU to give us a word-aligned starting address.
1691-
//
1692-
// TODO: https://github.com/tock/tock/issues/1739
16931712
match process.stored_state.map(|stored_state| {
16941713
chip.userspace_kernel_boundary().initialize_process(
16951714
memory_start,

0 commit comments

Comments
 (0)