Skip to content

Commit 453dc2d

Browse files
monitor: report potential stack overflows
Still not 100% ideal as sometimes stack overflows occur multiple pages out-of-bounds of the stack region, but this should be able to catch some of them and save time debugging. Signed-off-by: Ivan-Velickovic <i.velickovic@unsw.edu.au>
1 parent 1d36453 commit 453dc2d

File tree

3 files changed

+33
-19
lines changed

3 files changed

+33
-19
lines changed

monitor/src/main.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@ seL4_Word tcbs[MAX_TCBS];
9494
seL4_Word scheduling_contexts[MAX_TCBS];
9595
seL4_Word notification_caps[MAX_TCBS];
9696

97+
/* For reporting potential stack overflows, keep track of the stack regions for each PD. */
98+
seL4_Word pd_stack_addrs[MAX_PDS];
99+
97100
struct region {
98101
uintptr_t paddr;
99102
uintptr_t size_bits;
@@ -916,6 +919,12 @@ static void monitor(void)
916919
#error "Unknown architecture to print a VM fault for"
917920
#endif
918921

922+
seL4_Word fault_addr = seL4_GetMR(seL4_VMFault_Addr);
923+
seL4_Word stack_addr = pd_stack_addrs[badge];
924+
if (fault_addr < stack_addr && fault_addr >= stack_addr - 0x1000) {
925+
puts("MON|ERROR: potential stack overflow, fault address within one page outside of stack region\n");
926+
}
927+
919928
break;
920929
}
921930
default:

tool/microkit/src/main.rs

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use std::mem::size_of;
3131
use std::path::{Path, PathBuf};
3232
use util::{
3333
bytes_to_struct, comma_sep_u64, comma_sep_usize, json_str, json_str_as_bool, json_str_as_u64,
34-
struct_to_bytes,
34+
monitor_serialise_u64_vec, struct_to_bytes,
3535
};
3636

3737
// Corresponds to the IPC buffer symbol in libmicrokit and the monitor
@@ -453,6 +453,7 @@ struct BuiltSystem {
453453
ntfn_caps: Vec<u64>,
454454
pd_elf_regions: Vec<Vec<Region>>,
455455
pd_setvar_values: Vec<Vec<u64>>,
456+
pd_stack_addrs: Vec<u64>,
456457
kernel_objects: Vec<Object>,
457458
initial_task_virt_region: MemoryRegion,
458459
initial_task_phys_region: MemoryRegion,
@@ -1362,6 +1363,7 @@ fn build_system(
13621363
// Here we create a memory region/mapping for the stack for each PD.
13631364
// We allocate the stack at the highest possible virtual address that the
13641365
// kernel allows us.
1366+
let mut pd_stack_addrs = Vec::with_capacity(system.protection_domains.len());
13651367
for pd in &system.protection_domains {
13661368
let stack_mr = SysMemoryRegion {
13671369
name: format!("STACK:{}", pd.name),
@@ -1380,6 +1382,8 @@ fn build_system(
13801382
text_pos: None,
13811383
};
13821384

1385+
pd_stack_addrs.push(stack_map.vaddr);
1386+
13831387
extra_mrs.push(stack_mr);
13841388
pd_extra_maps.get_mut(pd).unwrap().push(stack_map);
13851389
}
@@ -2865,6 +2869,7 @@ fn build_system(
28652869
ntfn_caps: notification_caps,
28662870
pd_elf_regions,
28672871
pd_setvar_values,
2872+
pd_stack_addrs,
28682873
kernel_objects,
28692874
initial_task_phys_region,
28702875
initial_task_virt_region,
@@ -3529,30 +3534,17 @@ fn main() -> Result<(), String> {
35293534
&bootstrap_invocation_data,
35303535
)?;
35313536

3532-
let mut tcb_cap_bytes = vec![0; (1 + built_system.tcb_caps.len()) * 8];
3533-
for (i, cap) in built_system.tcb_caps.iter().enumerate() {
3534-
let start = (i + 1) * 8;
3535-
let end = start + 8;
3536-
tcb_cap_bytes[start..end].copy_from_slice(&cap.to_le_bytes());
3537-
}
3538-
let mut sched_cap_bytes = vec![0; (1 + built_system.sched_caps.len()) * 8];
3539-
for (i, cap) in built_system.sched_caps.iter().enumerate() {
3540-
let start = (i + 1) * 8;
3541-
let end = start + 8;
3542-
sched_cap_bytes[start..end].copy_from_slice(&cap.to_le_bytes());
3543-
}
3544-
let mut ntfn_cap_bytes = vec![0; (1 + built_system.ntfn_caps.len()) * 8];
3545-
for (i, cap) in built_system.ntfn_caps.iter().enumerate() {
3546-
let start = (i + 1) * 8;
3547-
let end = start + 8;
3548-
ntfn_cap_bytes[start..end].copy_from_slice(&cap.to_le_bytes());
3549-
}
3537+
let tcb_cap_bytes = monitor_serialise_u64_vec(&built_system.tcb_caps);
3538+
let sched_cap_bytes = monitor_serialise_u64_vec(&built_system.sched_caps);
3539+
let ntfn_cap_bytes = monitor_serialise_u64_vec(&built_system.ntfn_caps);
3540+
let pd_stack_addrs_bytes = monitor_serialise_u64_vec(&built_system.pd_stack_addrs);
35503541

35513542
monitor_elf.write_symbol("fault_ep", &built_system.fault_ep_cap_address.to_le_bytes())?;
35523543
monitor_elf.write_symbol("reply", &built_system.reply_cap_address.to_le_bytes())?;
35533544
monitor_elf.write_symbol("tcbs", &tcb_cap_bytes)?;
35543545
monitor_elf.write_symbol("scheduling_contexts", &sched_cap_bytes)?;
35553546
monitor_elf.write_symbol("notification_caps", &ntfn_cap_bytes)?;
3547+
monitor_elf.write_symbol("pd_stack_addrs", &pd_stack_addrs_bytes)?;
35563548
// We do MAX_PDS + 1 due to the index that the monitor uses (the badge) starting at 1.
35573549
let mut pd_names_bytes = vec![0; (MAX_PDS + 1) * PD_MAX_NAME_LENGTH];
35583550
for (i, pd) in system.protection_domains.iter().enumerate() {

tool/microkit/src/util.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,19 @@ pub unsafe fn bytes_to_struct<T>(bytes: &[u8]) -> &T {
181181
&body[0]
182182
}
183183

184+
/// Serialise an array of u64 to a Vector of bytes. Pads the Vector of bytes
185+
/// such that the first entry is empty.
186+
pub fn monitor_serialise_u64_vec(vec: &[u64]) -> Vec<u8> {
187+
let mut bytes = vec![0; (1 + vec.len()) * 8];
188+
for (i, value) in vec.iter().enumerate() {
189+
let start = (i + 1) * 8;
190+
let end = start + 8;
191+
bytes[start..end].copy_from_slice(&value.to_le_bytes());
192+
}
193+
194+
bytes
195+
}
196+
184197
#[cfg(test)]
185198
mod tests {
186199
// Note this useful idiom: importing names from outer (for mod tests) scope.

0 commit comments

Comments
 (0)