Skip to content

Commit 2f73167

Browse files
committed
feat: implement stack protection
1 parent 217006f commit 2f73167

17 files changed

Lines changed: 520 additions & 558 deletions

File tree

src/arch/aarch64/kernel/mod.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,16 @@ pub mod serial;
1414
mod start;
1515
pub mod systemtime;
1616

17-
use alloc::alloc::{Layout, alloc};
1817
use core::arch::global_asm;
1918
use core::sync::atomic::{AtomicPtr, AtomicU32, Ordering};
2019
use core::{ptr, str};
21-
20+
use hermit_sync::InterruptTicketMutex;
2221
use memory_addresses::PhysAddr;
2322

2423
use crate::arch::aarch64::kernel::core_local::*;
25-
use crate::arch::aarch64::mm::paging::{BasePageSize, PageSize};
2624
use crate::config::*;
2725
use crate::env;
26+
use crate::mm::stack_alloc::{allocate_stack, StackAllocation};
2827

2928
#[repr(align(8))]
3029
pub(crate) struct AlignedAtomicU32(AtomicU32);
@@ -34,6 +33,7 @@ pub(crate) struct AlignedAtomicU32(AtomicU32);
3433
/// It also synchronizes initialization of CPU cores.
3534
pub(crate) static CPU_ONLINE: AlignedAtomicU32 = AlignedAtomicU32(AtomicU32::new(0));
3635

36+
pub static CURRENT_STACK: InterruptTicketMutex<Option<StackAllocation>> = InterruptTicketMutex::new(None);
3737
pub(crate) static CURRENT_STACK_ADDRESS: AtomicPtr<u8> = AtomicPtr::new(ptr::null_mut());
3838

3939
#[cfg(target_os = "none")]
@@ -105,10 +105,9 @@ fn finish_processor_init() {
105105
debug!("Initialized processor {}", core_id());
106106

107107
// Allocate stack for the CPU and pass the addresses.
108-
let layout = Layout::from_size_align(KERNEL_STACK_SIZE, BasePageSize::SIZE as usize).unwrap();
109-
let stack = unsafe { alloc(layout) };
110-
assert!(!stack.is_null());
111-
CURRENT_STACK_ADDRESS.store(stack, Ordering::Relaxed);
108+
let stack = allocate_stack(KERNEL_STACK_SIZE);
109+
CURRENT_STACK_ADDRESS.store(stack.stack_start().as_mut_ptr(), Ordering::Relaxed);
110+
let _ = CURRENT_STACK.lock().insert(stack);
112111
}
113112

114113
pub fn boot_next_processor() {

src/arch/aarch64/kernel/scheduler.rs

Lines changed: 29 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,16 @@ use core::sync::atomic::Ordering;
66
use aarch64_cpu::asm::barrier::{SY, isb};
77
use aarch64_cpu::registers::*;
88
use align_address::Align;
9-
use free_list::{PageLayout, PageRange};
10-
use memory_addresses::{PhysAddr, VirtAddr};
9+
use memory_addresses::VirtAddr;
1110

1211
use crate::arch::aarch64::kernel::CURRENT_STACK_ADDRESS;
1312
use crate::arch::aarch64::kernel::core_local::core_scheduler;
14-
use crate::arch::aarch64::mm::paging::{BasePageSize, PageSize, PageTableEntryFlags};
15-
use crate::mm::{FrameAlloc, PageAlloc, PageRangeAllocator};
13+
use crate::arch::aarch64::mm::paging::{BasePageSize, PageSize};
1614
use crate::scheduler::PerCoreSchedulerExt;
1715
use crate::scheduler::task::{Task, TaskFrame};
1816
use crate::{DEFAULT_STACK_SIZE, KERNEL_STACK_SIZE};
17+
use crate::arch::kernel::CURRENT_STACK;
18+
use crate::mm::stack_alloc::{allocate_stack, StackAllocation};
1919

2020
#[derive(Debug)]
2121
#[repr(C, packed)]
@@ -94,156 +94,52 @@ pub(crate) struct State {
9494
pub x30: u64,
9595
}
9696

97-
pub struct BootStack {
98-
/// Stack for kernel tasks
99-
stack: VirtAddr,
100-
}
101-
102-
pub struct CommonStack {
103-
/// Start address of allocated virtual memory region
104-
virt_addr: VirtAddr,
105-
/// Start address of allocated virtual memory region
106-
phys_addr: PhysAddr,
107-
/// Total size of all stacks
108-
total_size: usize,
109-
}
110-
111-
pub enum TaskStacks {
112-
Boot(BootStack),
113-
Common(CommonStack),
97+
pub struct TaskStacks {
98+
kernel_stack: StackAllocation,
99+
user_stack: Option<StackAllocation>,
114100
}
115101

116102
impl TaskStacks {
117-
/// Size of the debug marker at the very top of each stack.
118-
///
119-
/// We have a marker at the very top of the stack for debugging (`0xdeadbeef`), which should not be overridden.
120-
pub const MARKER_SIZE: usize = 0x10;
121-
122103
pub fn new(size: usize) -> Self {
123104
let user_stack_size = if size < KERNEL_STACK_SIZE {
124105
KERNEL_STACK_SIZE
125106
} else {
126107
size.align_up(BasePageSize::SIZE as usize)
127108
};
128-
let total_size = user_stack_size + DEFAULT_STACK_SIZE;
129-
let layout = PageLayout::from_size(total_size + 3 * BasePageSize::SIZE as usize).unwrap();
130-
let page_range = PageAlloc::allocate(layout).unwrap();
131-
let virt_addr = VirtAddr::from(page_range.start());
132-
let frame_layout = PageLayout::from_size(total_size).unwrap();
133-
let frame_range = FrameAlloc::allocate(frame_layout)
134-
.expect("Failed to allocate Physical Memory for TaskStacks");
135-
let phys_addr = PhysAddr::from(frame_range.start());
136-
137-
debug!(
138-
"Create stacks at {:p} with a size of {} KB",
139-
virt_addr,
140-
total_size >> 10
141-
);
142-
143-
let mut flags = PageTableEntryFlags::empty();
144-
flags.normal().writable().execute_disable();
145109

146-
// map kernel stack into the address space
147-
crate::arch::mm::paging::map::<BasePageSize>(
148-
virt_addr + BasePageSize::SIZE,
149-
phys_addr,
150-
DEFAULT_STACK_SIZE / BasePageSize::SIZE as usize,
151-
flags,
152-
);
110+
let kernel_stack = allocate_stack(DEFAULT_STACK_SIZE);
111+
let user_stack = allocate_stack(user_stack_size);
153112

154-
// map user stack into the address space
155-
crate::arch::mm::paging::map::<BasePageSize>(
156-
virt_addr + DEFAULT_STACK_SIZE + 2 * BasePageSize::SIZE,
157-
phys_addr + DEFAULT_STACK_SIZE,
158-
user_stack_size / BasePageSize::SIZE as usize,
159-
flags,
160-
);
161-
162-
// clear user stack
163-
unsafe {
164-
(virt_addr + DEFAULT_STACK_SIZE + 2 * BasePageSize::SIZE)
165-
.as_mut_ptr::<u8>()
166-
.write_bytes(0, user_stack_size);
113+
TaskStacks {
114+
kernel_stack, user_stack: Some(user_stack)
167115
}
168-
169-
TaskStacks::Common(CommonStack {
170-
virt_addr,
171-
phys_addr,
172-
total_size,
173-
})
174116
}
175117

176118
pub fn from_boot_stacks() -> TaskStacks {
177-
let stack = VirtAddr::from_ptr(CURRENT_STACK_ADDRESS.load(Ordering::Relaxed));
178-
debug!("Using boot stack {stack:p}");
179-
180-
TaskStacks::Boot(BootStack { stack })
181-
}
182-
183-
pub fn get_user_stack_size(&self) -> usize {
184-
match self {
185-
TaskStacks::Boot(_) => 0,
186-
TaskStacks::Common(stacks) => stacks.total_size - DEFAULT_STACK_SIZE,
187-
}
188-
}
119+
let kernel_stack = if let Some(stack) = CURRENT_STACK.lock().as_ref() {
120+
stack.weak()
121+
} else {
122+
let stack = VirtAddr::from_ptr(CURRENT_STACK_ADDRESS.load(Ordering::Relaxed));
123+
debug!("Using boot stack {stack:p}");
189124

190-
pub fn get_user_stack(&self) -> VirtAddr {
191-
match self {
192-
TaskStacks::Boot(_) => VirtAddr::zero(),
193-
TaskStacks::Common(stacks) => {
194-
stacks.virt_addr + DEFAULT_STACK_SIZE + 2 * BasePageSize::SIZE
125+
unsafe {
126+
StackAllocation::new_external(stack, KERNEL_STACK_SIZE)
195127
}
196-
}
197-
}
128+
};
198129

199-
pub fn get_kernel_stack(&self) -> VirtAddr {
200-
match self {
201-
TaskStacks::Boot(stacks) => stacks.stack,
202-
TaskStacks::Common(stacks) => stacks.virt_addr + BasePageSize::SIZE,
130+
Self {
131+
kernel_stack, user_stack: None
203132
}
204133
}
205134

206-
pub fn get_kernel_stack_size(&self) -> usize {
207-
match self {
208-
TaskStacks::Boot(_) => KERNEL_STACK_SIZE,
209-
TaskStacks::Common(_) => DEFAULT_STACK_SIZE,
210-
}
135+
#[inline(always)]
136+
pub fn get_user_stack(&self) -> Option<&StackAllocation> {
137+
self.user_stack.as_ref()
211138
}
212-
}
213-
214-
impl Drop for TaskStacks {
215-
fn drop(&mut self) {
216-
// we should never deallocate a boot stack
217-
match self {
218-
TaskStacks::Boot(_) => {}
219-
TaskStacks::Common(stacks) => {
220-
debug!(
221-
"Deallocating stacks at {:p} with a size of {} KB",
222-
stacks.virt_addr,
223-
stacks.total_size >> 10,
224-
);
225139

226-
crate::arch::mm::paging::unmap::<BasePageSize>(
227-
stacks.virt_addr,
228-
stacks.total_size / BasePageSize::SIZE as usize + 3,
229-
);
230-
let range = PageRange::from_start_len(
231-
stacks.virt_addr.as_usize(),
232-
stacks.total_size + 3 * BasePageSize::SIZE as usize,
233-
)
234-
.unwrap();
235-
unsafe {
236-
PageAlloc::deallocate(range);
237-
}
238-
239-
let range =
240-
PageRange::from_start_len(stacks.phys_addr.as_usize(), stacks.total_size)
241-
.unwrap();
242-
unsafe {
243-
FrameAlloc::deallocate(range);
244-
}
245-
}
246-
}
140+
#[inline(always)]
141+
pub fn get_kernel_stack(&self) -> &StackAllocation {
142+
&self.kernel_stack
247143
}
248144
}
249145

@@ -288,10 +184,7 @@ impl TaskFrame for Task {
288184
}
289185

290186
unsafe {
291-
// Set a marker for debugging at the very top.
292-
let mut stack = self.stacks.get_kernel_stack() + self.stacks.get_kernel_stack_size()
293-
- TaskStacks::MARKER_SIZE;
294-
*stack.as_mut_ptr::<u64>() = 0xdead_beefu64;
187+
let mut stack = self.stacks.get_kernel_stack().top_of_stack();
295188

296189
// Put the State structure expected by the ASM switch() function on the stack.
297190
stack -= size_of::<State>();
@@ -314,12 +207,8 @@ impl TaskFrame for Task {
314207

315208
// Set the task's stack pointer entry to the stack we have just crafted.
316209
self.last_stack_pointer = stack;
210+
self.user_stack_pointer = self.stacks.get_user_stack().unwrap().top_of_stack();
317211

318-
// initialize user-level stack
319-
self.user_stack_pointer = self.stacks.get_user_stack()
320-
+ self.stacks.get_user_stack_size()
321-
- TaskStacks::MARKER_SIZE;
322-
*self.user_stack_pointer.as_mut_ptr::<u64>() = 0xdead_beefu64;
323212
(*state).sp_el0 = self.user_stack_pointer.as_u64();
324213
}
325214
}

src/arch/aarch64/kernel/start.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ use aarch64_cpu::asm::barrier::{SY, dsb};
1010
use hermit_entry::Entry;
1111
use hermit_entry::boot_info::RawBootInfo;
1212

13-
use crate::arch::aarch64::kernel::scheduler::TaskStacks;
1413
use crate::{KERNEL_STACK_SIZE, env};
14+
use crate::mm::stack_alloc;
1515

1616
/*
1717
* Memory types available.
@@ -102,7 +102,7 @@ pub unsafe extern "C" fn _start(boot_info: Option<&'static RawBootInfo>, cpu_id:
102102
"b {pre_init}",
103103

104104
cpu_online = sym super::CPU_ONLINE,
105-
stack_top_offset = const KERNEL_STACK_SIZE - TaskStacks::MARKER_SIZE,
105+
stack_top_offset = const KERNEL_STACK_SIZE - stack_alloc::MARKER_SIZE,
106106
current_stack_address = sym super::CURRENT_STACK_ADDRESS,
107107
pre_init = sym pre_init,
108108
)
@@ -239,7 +239,7 @@ pub(crate) unsafe extern "C" fn smp_start() -> ! {
239239

240240
mair_el1 = const mair(0x00, MT_DEVICE_nGnRnE) | mair(0x04, MT_DEVICE_nGnRE) | mair(0x0c, MT_DEVICE_GRE) | mair(0x44, MT_NORMAL_NC) | mair(0xff, MT_NORMAL),
241241
tcr_bits = const tcr_size(VA_BITS) | TCR_TG1_4K | TCR_FLAGS,
242-
stack_top_offset = const KERNEL_STACK_SIZE - TaskStacks::MARKER_SIZE,
242+
stack_top_offset = const KERNEL_STACK_SIZE - stack_alloc::MARKER_SIZE,
243243
current_stack_address = sym super::CURRENT_STACK_ADDRESS,
244244
sctlr_el1 = const SCTLR_EL1,
245245
ttbr0 = sym TTBR0,

src/arch/riscv64/kernel/core_local.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub struct CoreLocal {
1919
core_id: CoreId,
2020
/// Scheduler of the current Core.
2121
scheduler: Cell<*mut PerCoreScheduler>,
22-
/// Start address of the kernel stack
22+
/// Start address of the kernel stack (appears unused)
2323
pub kernel_stack: Cell<u64>,
2424
/// The core-local async executor.
2525
ex: StaticLocalExecutor<RawSpinMutex, RawRwSpinLock>,

src/arch/riscv64/kernel/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ use crate::config::KERNEL_STACK_SIZE;
2626
use crate::env;
2727
use crate::init_cell::InitCell;
2828
use crate::mm::{FrameAlloc, PageRangeAllocator};
29+
use crate::mm::stack_alloc::allocate_stack;
2930

3031
// Used to store information about available harts. The index of the hart in the vector
3132
// represents its CpuId and does not need to match its hart_id
@@ -148,10 +149,9 @@ pub fn boot_next_processor() {
148149

149150
{
150151
debug!("Allocating stack for hard_id {next_hart_id}");
151-
let frame_layout = PageLayout::from_size(KERNEL_STACK_SIZE).unwrap();
152-
let frame_range =
153-
FrameAlloc::allocate(frame_layout).expect("Failed to allocate boot stack for new core");
154-
let stack = ptr::with_exposed_provenance_mut(frame_range.start());
152+
153+
let stack = allocate_stack(KERNEL_STACK_SIZE).leak();
154+
let stack = ptr::with_exposed_provenance_mut(stack.stack_start().as_usize());
155155
CURRENT_STACK_ADDRESS.store(stack, Ordering::Relaxed);
156156
}
157157

0 commit comments

Comments
 (0)