Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stack overflow protection #1764

Merged
merged 8 commits into from
Oct 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions artiq/compiler/kernel.ld
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,7 @@ SECTIONS
. = ALIGN(4);
_end = .;
}

. = ALIGN(0x1000);
_sstack_guard = .;
}
2 changes: 1 addition & 1 deletion artiq/firmware/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions artiq/firmware/bootloader/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use board_misoc::slave_fpga;
#[cfg(has_ethmac)]
use board_misoc::{clock, ethmac, net_settings};
use board_misoc::uart_console::Console;
use riscv::register::{mcause, mepc};
use riscv::register::{mcause, mepc, mtval};

fn check_integrity() -> bool {
extern {
Expand Down Expand Up @@ -522,7 +522,8 @@ pub extern fn main() -> i32 {
pub extern fn exception(_regs: *const u32) {
let pc = mepc::read();
let cause = mcause::read().cause();
panic!("{:?} at PC {:#08x}", cause, u32::try_from(pc).unwrap())
let mtval = mtval::read();
panic!("{:?} at PC {:#08x}, trap value {:#08x}", cause, u32::try_from(pc).unwrap(), mtval);
}

#[no_mangle]
Expand Down
7 changes: 5 additions & 2 deletions artiq/firmware/ksupport/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use proto_artiq::{kernel_proto, rpc_proto};
use kernel_proto::*;
#[cfg(has_rtio_dma)]
use board_misoc::csr;
use riscv::register::{mcause, mepc};
use riscv::register::{mcause, mepc, mtval};

fn send(request: &Message) {
unsafe { mailbox::send(request as *const _ as usize) }
Expand Down Expand Up @@ -493,11 +493,13 @@ pub unsafe fn main() {
let _end = library.lookup(b"_end").unwrap();
let __modinit__ = library.lookup(b"__modinit__").unwrap();
let typeinfo = library.lookup(b"typeinfo");
let _sstack_guard = library.lookup(b"_sstack_guard").unwrap();

LIBRARY = Some(library);

ptr::write_bytes(__bss_start as *mut u8, 0, (_end - __bss_start) as usize);

board_misoc::pmp::init_stack_guard(_sstack_guard as usize);
board_misoc::cache::flush_cpu_dcache();
board_misoc::cache::flush_cpu_icache();

Expand Down Expand Up @@ -530,7 +532,8 @@ pub unsafe fn main() {
pub extern fn exception(_regs: *const u32) {
let pc = mepc::read();
let cause = mcause::read().cause();
panic!("{:?} at PC {:#08x}", cause, u32::try_from(pc).unwrap())
let mtval = mtval::read();
panic!("{:?} at PC {:#08x}, trap value {:#08x}", cause, u32::try_from(pc).unwrap(), mtval);
}

#[no_mangle]
Expand Down
14 changes: 13 additions & 1 deletion artiq/firmware/libboard_misoc/riscv32ima/boot.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use super::cache;
use super::{cache, pmp};
use riscv::register::*;

pub unsafe fn reset() -> ! {
llvm_asm!(r#"
Expand All @@ -16,3 +17,14 @@ pub unsafe fn jump(addr: usize) -> ! {
"# : : "r"(addr) : : "volatile");
loop {}
}

pub unsafe fn start_user(addr: usize) -> ! {
pmp::enable_user_memory();
mstatus::set_mpp(mstatus::MPP::User);
mepc::write(addr);
llvm_asm!(
"mret"
: : : : "volatile"
);
unreachable!()
}
1 change: 1 addition & 0 deletions artiq/firmware/libboard_misoc/riscv32ima/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pub mod cache;
pub mod boot;
pub mod pmp;
55 changes: 55 additions & 0 deletions artiq/firmware/libboard_misoc/riscv32ima/pmp.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
use riscv::register::{pmpaddr0, pmpaddr1, pmpaddr2, pmpaddr3, pmpcfg0};

static mut THREAD_DEPTH: u8 = 0;

const PMP_L : usize = 0b10000000;
const PMP_NAPOT: usize = 0b00011000;
const PMP_X : usize = 0b00000100;
const PMP_W : usize = 0b00000010;
const PMP_R : usize = 0b00000001;
const PMP_OFF : usize = 0b00000000;

#[inline(always)]
pub unsafe fn init_stack_guard(guard_base: usize) {
pmpaddr2::write((guard_base >> 2) | ((0x1000 - 1) >> 3));
pmpcfg0::write((PMP_L | PMP_NAPOT) << 16);
}

#[inline(always)]
pub fn enable_user_memory() {
pmpaddr3::write((0x80000000 - 1) >> 3);
pmpcfg0::write((PMP_L | PMP_NAPOT | PMP_X | PMP_W | PMP_R) << 24);
}

#[inline(always)]
pub unsafe fn push_pmp_region(addr: usize) {
let pmp_addr = (addr >> 2) | ((0x1000 - 1) >> 3);
match THREAD_DEPTH {
// Activate PMP0 when switching from main stack to thread
0 => {
pmpaddr0::write(pmp_addr);
pmpcfg0::write(PMP_NAPOT);
}

// Temporarily activate PMP1 when spawning a thread from a thread
// The thread should swap back to the main stack very soon after init
1 => {
pmpaddr1::write(pmp_addr);
pmpcfg0::write(PMP_NAPOT << 8 | PMP_NAPOT);
}

// Thread *running* another thread should not be possible
_ => unreachable!()
}
THREAD_DEPTH += 1;
}

#[inline(always)]
pub unsafe fn pop_pmp_region() {
THREAD_DEPTH -= 1;
match THREAD_DEPTH {
0 => pmpcfg0::write(PMP_OFF),
1 => pmpcfg0::write(PMP_NAPOT),
_ => unreachable!()
}
}
2 changes: 1 addition & 1 deletion artiq/firmware/runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,6 @@ riscv = { version = "0.6.0", features = ["inline-asm"] }

[dependencies.fringe]
git = "https://git.m-labs.hk/M-Labs/libfringe.git"
rev = "9748bb"
rev = "3ecbe5"
default-features = false
features = ["alloc"]
26 changes: 22 additions & 4 deletions artiq/firmware/runtime/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use core::cell::RefCell;
use core::convert::TryFrom;
use smoltcp::wire::IpCidr;

use board_misoc::{csr, ident, clock, spiflash, config, net_settings};
use board_misoc::{csr, ident, clock, spiflash, config, net_settings, pmp, boot};
#[cfg(has_ethmac)]
use board_misoc::ethmac;
#[cfg(has_drtio)]
Expand All @@ -40,7 +40,7 @@ use proto_artiq::{mgmt_proto, moninj_proto, rpc_proto, session_proto, kernel_pro
#[cfg(has_rtio_analyzer)]
use proto_artiq::analyzer_proto;

use riscv::register::{mcause, mepc};
use riscv::register::{mcause, mepc, mtval};

mod rtio_clocking;
mod rtio_mgt;
Expand Down Expand Up @@ -247,10 +247,15 @@ pub extern fn main() -> i32 {
extern {
static mut _fheap: u8;
static mut _eheap: u8;
static mut _sstack_guard: u8;
}
ALLOC.add_range(&mut _fheap, &mut _eheap);

logger_artiq::BufferLogger::new(&mut LOG_BUFFER[..]).register(startup);
pmp::init_stack_guard(&_sstack_guard as *const u8 as usize);

logger_artiq::BufferLogger::new(&mut LOG_BUFFER[..]).register(||
boot::start_user(startup as usize)
);

0
}
Expand Down Expand Up @@ -285,6 +290,18 @@ pub extern fn exception(regs: *const TrapFrame) {
mcause::Trap::Interrupt(source) => {
info!("Called interrupt with {:?}", source);
},

mcause::Trap::Exception(mcause::Exception::UserEnvCall) => {
unsafe {
if (*regs).a7 == 0 {
pmp::pop_pmp_region()
} else {
pmp::push_pmp_region((*regs).a7)
}
}
mepc::write(pc + 4);
},

mcause::Trap::Exception(e) => {
println!("Trap frame: {:x?}", unsafe { *regs });

Expand All @@ -302,7 +319,8 @@ pub extern fn exception(regs: *const TrapFrame) {
}

hexdump(u32::try_from(pc).unwrap());
panic!("exception {:?} at PC 0x{:x}", e, u32::try_from(pc).unwrap())
let mtval = mtval::read();
panic!("exception {:?} at PC 0x{:x}, trap value 0x{:x}", e, u32::try_from(pc).unwrap(), mtval)
}
}
}
Expand Down
5 changes: 4 additions & 1 deletion artiq/firmware/runtime/runtime.ld
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,11 @@ SECTIONS
_ebss = .;
} > runtime

.stack (NOLOAD) : ALIGN(16)
.stack (NOLOAD) : ALIGN(0x1000)
{
_sstack_guard = .;
. += 0x1000;
_estack = .;
. += 0x10000;
_fstack = . - 16;
} > runtime
Expand Down
3 changes: 2 additions & 1 deletion artiq/firmware/runtime/sched.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ impl Thread {
let spawned = io.spawned.clone();
let sockets = io.sockets.clone();

let stack = OwnedStack::new(stack_size);
// Add a 4k stack guard to the stack of any new threads
let stack = OwnedStack::new(stack_size + 4096);
ThreadHandle::new(Thread {
generator: Generator::unsafe_new(stack, |yielder, _| {
f(Io {
Expand Down
15 changes: 12 additions & 3 deletions artiq/firmware/satman/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ extern crate board_artiq;
extern crate riscv;

use core::convert::TryFrom;
use board_misoc::{csr, ident, clock, uart_logger, i2c};
use board_misoc::{csr, ident, clock, uart_logger, i2c, pmp};
#[cfg(has_si5324)]
use board_artiq::si5324;
#[cfg(has_wrpll)]
Expand All @@ -18,7 +18,7 @@ use board_artiq::{spi, drtioaux};
use board_artiq::drtio_routing;
#[cfg(has_hmc830_7043)]
use board_artiq::hmc830_7043;
use riscv::register::{mcause, mepc};
use riscv::register::{mcause, mepc, mtval};

mod repeater;
#[cfg(has_jdcg)]
Expand Down Expand Up @@ -449,6 +449,14 @@ const SI5324_SETTINGS: si5324::FrequencySettings

#[no_mangle]
pub extern fn main() -> i32 {
extern {
static mut _sstack_guard: u8;
}

unsafe {
pmp::init_stack_guard(&_sstack_guard as *const u8 as usize);
}

clock::init();
uart_logger::ConsoleLogger::register();

Expand Down Expand Up @@ -662,7 +670,8 @@ pub extern fn exception(_regs: *const u32) {
}

hexdump(u32::try_from(pc).unwrap());
panic!("exception {:?} at PC 0x{:x}", cause, u32::try_from(pc).unwrap())
let mtval = mtval::read();
panic!("exception {:?} at PC 0x{:x}, trap value 0x{:x}", cause, u32::try_from(pc).unwrap(), mtval)
}

#[no_mangle]
Expand Down
4 changes: 3 additions & 1 deletion artiq/firmware/satman/satman.ld
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,10 @@ SECTIONS
_ebss = .;
} > main_ram

.stack (NOLOAD) : ALIGN(16)
.stack (NOLOAD) : ALIGN(0x1000)
{
_sstack_guard = .;
. += 0x1000;
_estack = .;
. += 0x10000;
_fstack = . - 16;
Expand Down
26 changes: 13 additions & 13 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.