Skip to content

Commit 8b21c11

Browse files
committed
feat: implement stack protection
1 parent 28c7089 commit 8b21c11

16 files changed

Lines changed: 510 additions & 554 deletions

File tree

src/arch/aarch64/kernel/scheduler.rs

Lines changed: 23 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,15 @@ 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::mm::stack_alloc::{allocate_stack, StackAllocation};
1918

2019
#[derive(Debug)]
2120
#[repr(C, packed)]
@@ -94,156 +93,48 @@ pub(crate) struct State {
9493
pub x30: u64,
9594
}
9695

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),
96+
pub struct TaskStacks {
97+
kernel_stack: StackAllocation,
98+
user_stack: Option<StackAllocation>,
11499
}
115100

116101
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-
122102
pub fn new(size: usize) -> Self {
123103
let user_stack_size = if size < KERNEL_STACK_SIZE {
124104
KERNEL_STACK_SIZE
125105
} else {
126106
size.align_up(BasePageSize::SIZE as usize)
127107
};
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();
145108

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-
);
109+
let kernel_stack = allocate_stack(DEFAULT_STACK_SIZE);
110+
let user_stack = allocate_stack(user_stack_size);
153111

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);
112+
TaskStacks {
113+
kernel_stack, user_stack: Some(user_stack)
167114
}
168-
169-
TaskStacks::Common(CommonStack {
170-
virt_addr,
171-
phys_addr,
172-
total_size,
173-
})
174115
}
175116

176117
pub fn from_boot_stacks() -> TaskStacks {
177118
let stack = VirtAddr::from_ptr(CURRENT_STACK_ADDRESS.load(Ordering::Relaxed));
178119
debug!("Using boot stack {stack:p}");
179120

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-
}
189-
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
195-
}
196-
}
197-
}
121+
let kernel_stack = unsafe {
122+
StackAllocation::new_external(stack, KERNEL_STACK_SIZE)
123+
};
198124

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,
125+
Self {
126+
kernel_stack, user_stack: None
203127
}
204128
}
205129

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-
}
130+
#[inline(always)]
131+
pub fn get_user_stack(&self) -> Option<&StackAllocation> {
132+
self.user_stack.as_ref()
211133
}
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-
);
225134

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-
}
135+
#[inline(always)]
136+
pub fn get_kernel_stack(&self) -> &StackAllocation {
137+
&self.kernel_stack
247138
}
248139
}
249140

@@ -288,10 +179,7 @@ impl TaskFrame for Task {
288179
}
289180

290181
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;
182+
let mut stack = self.stacks.get_kernel_stack().top_of_stack();
295183

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

315203
// Set the task's stack pointer entry to the stack we have just crafted.
316204
self.last_stack_pointer = stack;
205+
self.user_stack_pointer = self.stacks.get_user_stack().unwrap().top_of_stack();
317206

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;
323207
(*state).sp_el0 = self.user_stack_pointer.as_u64();
324208
}
325209
}

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>,

0 commit comments

Comments
 (0)