From c54d03e19bada1b2a230beb20992ce2b75709656 Mon Sep 17 00:00:00 2001 From: Lotte Steenbrink Date: Fri, 22 Jan 2021 10:29:21 +0100 Subject: [PATCH 01/10] add stack_overflow.rs --- advanced/firmware/src/bin/stack_overflow.rs | 30 +++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 advanced/firmware/src/bin/stack_overflow.rs diff --git a/advanced/firmware/src/bin/stack_overflow.rs b/advanced/firmware/src/bin/stack_overflow.rs new file mode 100644 index 0000000..e5930e8 --- /dev/null +++ b/advanced/firmware/src/bin/stack_overflow.rs @@ -0,0 +1,30 @@ +#![no_main] +#![no_std] + +use cortex_m::asm; +use cortex_m_rt::entry; +use panic_log as _; // panic handler + +#[entry] +fn main() -> ! { + // board initialization + dk::init().unwrap(); + + log::info!("fib(100) = {:?}", fib(100)); + + loop { + asm::bkpt(); + } +} + +#[inline(never)] +fn fib(n: u32) -> u32 { + // allocate and initialize one kilobyte of stack memory to provoke stack overflow + let _use_stack = [0xAA; 1024]; + + if n < 2 { + 1 + } else { + fib(n - 1) + fib(n - 2) // recursion + } +} From fdc56a32e25074917d92d42d051b7e7ce79a38d3 Mon Sep 17 00:00:00 2001 From: Lotte Steenbrink Date: Fri, 22 Jan 2021 10:32:51 +0100 Subject: [PATCH 02/10] start adding flip-link --- advanced/firmware/.cargo/config.toml | 7 +++++++ advanced/firmware/Cargo.toml | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/advanced/firmware/.cargo/config.toml b/advanced/firmware/.cargo/config.toml index 52f6fb6..5ccd822 100644 --- a/advanced/firmware/.cargo/config.toml +++ b/advanced/firmware/.cargo/config.toml @@ -1,3 +1,10 @@ +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +# (..) +rustflags = [ + "-C", "linker=flip-link", # adds stack overflow protection + # (..) +] + [target.thumbv7em-none-eabihf] runner = "probe-run --chip nRF52840_xxAA" rustflags = [ diff --git a/advanced/firmware/Cargo.toml b/advanced/firmware/Cargo.toml index dca67df..f7df825 100644 --- a/advanced/firmware/Cargo.toml +++ b/advanced/firmware/Cargo.toml @@ -25,11 +25,11 @@ usb2 = { git = "https://github.com/japaric/usb2" } # optimize code in both profiles [profile.dev] codegen-units = 1 -debug = 1 +debug = 2 debug-assertions = true # ! incremental = false lto = "fat" -opt-level = 'z' # ! +opt-level = 1 # ! overflow-checks = false [profile.release] From 4cdb377855b0e91ad83075236b26e1a2230b54d2 Mon Sep 17 00:00:00 2001 From: Lotte Steenbrink Date: Fri, 22 Jan 2021 12:40:17 +0100 Subject: [PATCH 03/10] provoke stack overflow more blatantly --- advanced/firmware/src/bin/stack_overflow.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/advanced/firmware/src/bin/stack_overflow.rs b/advanced/firmware/src/bin/stack_overflow.rs index e5930e8..b98ea13 100644 --- a/advanced/firmware/src/bin/stack_overflow.rs +++ b/advanced/firmware/src/bin/stack_overflow.rs @@ -10,7 +10,8 @@ fn main() -> ! { // board initialization dk::init().unwrap(); - log::info!("fib(100) = {:?}", fib(100)); + log::info!("provoking stack overflow..."); + spam(); loop { asm::bkpt(); @@ -18,13 +19,12 @@ fn main() -> ! { } #[inline(never)] -fn fib(n: u32) -> u32 { - // allocate and initialize one kilobyte of stack memory to provoke stack overflow - let _use_stack = [0xAA; 1024]; +fn spam() { + // allocate and initialize one kilobyte of stack memory to provoke stack overflow quicker + let use_stack = [0xAA; 1024]; + let addr = &use_stack as *const i32; - if n < 2 { - 1 - } else { - fib(n - 1) + fib(n - 2) // recursion - } + log::info!("address of current `use_stack`: {:?}", addr); + + spam(); // infinite recursion } From 816ab161fc93cd0c1442e6a04320bcae4f71a2ef Mon Sep 17 00:00:00 2001 From: Lotte Steenbrink Date: Fri, 22 Jan 2021 15:01:18 +0100 Subject: [PATCH 04/10] stack_overflow.rs cover up bug? --- advanced/firmware/src/bin/stack_overflow.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/advanced/firmware/src/bin/stack_overflow.rs b/advanced/firmware/src/bin/stack_overflow.rs index b98ea13..befc47b 100644 --- a/advanced/firmware/src/bin/stack_overflow.rs +++ b/advanced/firmware/src/bin/stack_overflow.rs @@ -20,11 +20,11 @@ fn main() -> ! { #[inline(never)] fn spam() { - // allocate and initialize one kilobyte of stack memory to provoke stack overflow quicker - let use_stack = [0xAA; 1024]; - let addr = &use_stack as *const i32; + // allocate and initialize one kilobyte of stack memory to provoke stack overflow + let use_stack = [0xAA_u32; 1024]; - log::info!("address of current `use_stack`: {:?}", addr); + log::info!("address of current `use_stack`: {:?}", &use_stack as *const u32); + log::info!("entering next recursive step"); spam(); // infinite recursion } From 514292aaab5fba4d4234ef569cbf88a9c8b98f41 Mon Sep 17 00:00:00 2001 From: Lotte Steenbrink Date: Fri, 22 Jan 2021 15:01:48 +0100 Subject: [PATCH 05/10] add stack_overflow exercise --- beginner/apps/src/bin/stack_overflow.rs | 30 ++++++++++++++++++++++ embedded-workshop-book/src/SUMMARY.md | 1 + embedded-workshop-book/src/installation.md | 6 +++++ 3 files changed, 37 insertions(+) create mode 100644 beginner/apps/src/bin/stack_overflow.rs diff --git a/beginner/apps/src/bin/stack_overflow.rs b/beginner/apps/src/bin/stack_overflow.rs new file mode 100644 index 0000000..e5930e8 --- /dev/null +++ b/beginner/apps/src/bin/stack_overflow.rs @@ -0,0 +1,30 @@ +#![no_main] +#![no_std] + +use cortex_m::asm; +use cortex_m_rt::entry; +use panic_log as _; // panic handler + +#[entry] +fn main() -> ! { + // board initialization + dk::init().unwrap(); + + log::info!("fib(100) = {:?}", fib(100)); + + loop { + asm::bkpt(); + } +} + +#[inline(never)] +fn fib(n: u32) -> u32 { + // allocate and initialize one kilobyte of stack memory to provoke stack overflow + let _use_stack = [0xAA; 1024]; + + if n < 2 { + 1 + } else { + fib(n - 1) + fib(n - 2) // recursion + } +} diff --git a/embedded-workshop-book/src/SUMMARY.md b/embedded-workshop-book/src/SUMMARY.md index 3a051f4..e91bab6 100644 --- a/embedded-workshop-book/src/SUMMARY.md +++ b/embedded-workshop-book/src/SUMMARY.md @@ -57,6 +57,7 @@ - [Inspecting the Descriptors](./inspecting-descriptors.md) - [Getting it Configured](./getting-device-configured.md) - [Next Steps](./advanced-next-steps.md) + - [Stack Overflow Protection](./stack-overflow-protection.md) - [References and Resources](./references-resources.md) - [Tooltips](./tooltips.md) - [Troubleshooting](./troubleshooting.md) diff --git a/embedded-workshop-book/src/installation.md b/embedded-workshop-book/src/installation.md index edaa48b..d042a4f 100644 --- a/embedded-workshop-book/src/installation.md +++ b/embedded-workshop-book/src/installation.md @@ -176,6 +176,12 @@ Leave the processes running in the background. #### Advanced workshop +```console +$ cargo install flip-link +(..) +Installed package `flip-link v0.1.2` (..) +``` + Change to the `tools` folder and run these commands: ```console From 9f3126c594c00daac3310cd67d439cfc00b4ca08 Mon Sep 17 00:00:00 2001 From: Lotte Steenbrink Date: Fri, 22 Jan 2021 15:03:27 +0100 Subject: [PATCH 06/10] add flip-link to CI --- .github/workflows/rust.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 2764f9a..968e1f2 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -65,5 +65,6 @@ jobs: - name: build and fmt advanced/firmware working-directory: ./advanced/firmware run: | + cargo install flip-link cargo build --verbose cargo fmt --all -- --check From 19af229d0b1457d103b9a16142b714137429c90e Mon Sep 17 00:00:00 2001 From: Lotte Steenbrink Date: Fri, 22 Jan 2021 15:15:11 +0100 Subject: [PATCH 07/10] respond to comments --- .github/workflows/rust.yml | 1 + advanced/firmware/Cargo.toml | 4 ++-- advanced/firmware/src/bin/stack_overflow.rs | 1 - beginner/apps/.cargo/config.toml | 7 +++++++ embedded-workshop-book/src/installation.md | 10 ++++------ 5 files changed, 14 insertions(+), 9 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 968e1f2..d25b2e6 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -59,6 +59,7 @@ jobs: - name: build and fmt beginner/apps working-directory: ./beginner/apps run: | + cargo install flip-link cargo build --verbose cargo fmt --all -- --check diff --git a/advanced/firmware/Cargo.toml b/advanced/firmware/Cargo.toml index f7df825..dca67df 100644 --- a/advanced/firmware/Cargo.toml +++ b/advanced/firmware/Cargo.toml @@ -25,11 +25,11 @@ usb2 = { git = "https://github.com/japaric/usb2" } # optimize code in both profiles [profile.dev] codegen-units = 1 -debug = 2 +debug = 1 debug-assertions = true # ! incremental = false lto = "fat" -opt-level = 1 # ! +opt-level = 'z' # ! overflow-checks = false [profile.release] diff --git a/advanced/firmware/src/bin/stack_overflow.rs b/advanced/firmware/src/bin/stack_overflow.rs index befc47b..e24c08f 100644 --- a/advanced/firmware/src/bin/stack_overflow.rs +++ b/advanced/firmware/src/bin/stack_overflow.rs @@ -25,6 +25,5 @@ fn spam() { log::info!("address of current `use_stack`: {:?}", &use_stack as *const u32); - log::info!("entering next recursive step"); spam(); // infinite recursion } diff --git a/beginner/apps/.cargo/config.toml b/beginner/apps/.cargo/config.toml index 1f11e40..be9aeec 100644 --- a/beginner/apps/.cargo/config.toml +++ b/beginner/apps/.cargo/config.toml @@ -1,3 +1,10 @@ +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +# (..) +rustflags = [ + "-C", "linker=flip-link", # adds stack overflow protection + # (..) +] + [target.thumbv7em-none-eabihf] runner = "probe-run --chip nRF52840_xxAA" rustflags = [ diff --git a/embedded-workshop-book/src/installation.md b/embedded-workshop-book/src/installation.md index d042a4f..f12dec0 100644 --- a/embedded-workshop-book/src/installation.md +++ b/embedded-workshop-book/src/installation.md @@ -143,6 +143,10 @@ Installed package `cargo-binutils v0.3.3` (..) $ cargo install probe-run (..) Installed package `probe-run v0.1.8` (..) + +$ cargo install flip-link +(..) +Installed package `flip-link v0.1.2` (..) ``` ### Workshop specific tools @@ -176,12 +180,6 @@ Leave the processes running in the background. #### Advanced workshop -```console -$ cargo install flip-link -(..) -Installed package `flip-link v0.1.2` (..) -``` - Change to the `tools` folder and run these commands: ```console From 92e61650b2cd5a7440c915693da05d47c0e9529d Mon Sep 17 00:00:00 2001 From: Lotte Steenbrink Date: Fri, 22 Jan 2021 15:18:18 +0100 Subject: [PATCH 08/10] cargo fmt --- advanced/firmware/src/bin/stack_overflow.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/advanced/firmware/src/bin/stack_overflow.rs b/advanced/firmware/src/bin/stack_overflow.rs index e24c08f..34de0a0 100644 --- a/advanced/firmware/src/bin/stack_overflow.rs +++ b/advanced/firmware/src/bin/stack_overflow.rs @@ -23,7 +23,10 @@ fn spam() { // allocate and initialize one kilobyte of stack memory to provoke stack overflow let use_stack = [0xAA_u32; 1024]; - log::info!("address of current `use_stack`: {:?}", &use_stack as *const u32); + log::info!( + "address of current `use_stack`: {:?}", + &use_stack as *const u32 + ); spam(); // infinite recursion } From 5372bfa0fef9a22bf4b5768b74dcc9e7e0d0712c Mon Sep 17 00:00:00 2001 From: Lotte Steenbrink Date: Fri, 22 Jan 2021 15:21:47 +0100 Subject: [PATCH 09/10] fix copypasta err --- advanced/firmware/src/bin/stack_overflow.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/advanced/firmware/src/bin/stack_overflow.rs b/advanced/firmware/src/bin/stack_overflow.rs index 34de0a0..04d8c0f 100644 --- a/advanced/firmware/src/bin/stack_overflow.rs +++ b/advanced/firmware/src/bin/stack_overflow.rs @@ -20,7 +20,7 @@ fn main() -> ! { #[inline(never)] fn spam() { - // allocate and initialize one kilobyte of stack memory to provoke stack overflow + // allocate and initialize 4 kilobytes of stack memory to provoke stack overflow let use_stack = [0xAA_u32; 1024]; log::info!( From a0caf5168222ddc223fc0df260debe98364ae92b Mon Sep 17 00:00:00 2001 From: Lotte Steenbrink Date: Fri, 22 Jan 2021 15:59:13 +0100 Subject: [PATCH 10/10] use use_stack, actualy add text --- advanced/firmware/src/bin/stack_overflow.rs | 12 +++-- .../src/stack-overflow-protection.md | 54 +++++++++++++++++++ 2 files changed, 61 insertions(+), 5 deletions(-) create mode 100644 embedded-workshop-book/src/stack-overflow-protection.md diff --git a/advanced/firmware/src/bin/stack_overflow.rs b/advanced/firmware/src/bin/stack_overflow.rs index 04d8c0f..da80959 100644 --- a/advanced/firmware/src/bin/stack_overflow.rs +++ b/advanced/firmware/src/bin/stack_overflow.rs @@ -11,7 +11,7 @@ fn main() -> ! { dk::init().unwrap(); log::info!("provoking stack overflow..."); - spam(); + spam(0); loop { asm::bkpt(); @@ -19,14 +19,16 @@ fn main() -> ! { } #[inline(never)] -fn spam() { +fn spam(n: u32) { // allocate and initialize 4 kilobytes of stack memory to provoke stack overflow - let use_stack = [0xAA_u32; 1024]; + let use_stack = [n; 1024]; log::info!( - "address of current `use_stack`: {:?}", + "address of current `use_stack` at recursion depth {:?}: {:?}", + use_stack[1023], // "use" use_stack to prevent it from being optimized out &use_stack as *const u32 ); - spam(); // infinite recursion + let next = n + 1; + spam(next); // infinite recursion } diff --git a/embedded-workshop-book/src/stack-overflow-protection.md b/embedded-workshop-book/src/stack-overflow-protection.md new file mode 100644 index 0000000..6a68dbc --- /dev/null +++ b/embedded-workshop-book/src/stack-overflow-protection.md @@ -0,0 +1,54 @@ +# Stack Overflow Protection + +The `firmware` crate in which we developed our advanced workshop solutions (i.e. `advanced/firmware`) uses our open-source [`flip-link`] tool for zero-cost stack overflow protection. + +This means that your application will warn you by crashing if you accidentally overreach the boundaries of your application's stack instead of running into *undefined behavior* and behaving erratically in irreproducible ways. This memory protection mechanism comes at no additional computational or memory-usage cost. + +🔎 For a detailed description of how `flip-link` and Stack Overflows in bare metal Rust in general work, please refer to the [`flip-link` README]. + +You can see this in action in the `stack_overflow.rs` file that can be found in `advanced/firmware/src/bin/`: + +``` rust +{{#include ../../advanced/firmware/src/bin/stack_overflow.rs}} +``` + +The `spam()` function allocates data on the stack until the stack boundaries are reached. + +✅ Run `stack_overflow.rs` + +You should see output similar to this: + +``` console + (...) + (HOST) INFO flashing program (32.68 KiB) + (HOST) INFO success! +──────────────────────────────────────────────────────────────────────────────── +INFO:stack_overflow -- provoking stack overflow... +INFO:stack_overflow -- address of current `use_stack` at recursion depth 0: 0x2003aec0 +INFO:stack_overflow -- address of current `use_stack` at recursion depth 1: 0x20039e50 +(...) +INFO:stack_overflow -- address of current `use_stack` at recursion depth 10: 0x20030a60 +INFO:stack_overflow -- address of current `use_stack` at recursionstack backtrace: + 0: HardFaultTrampoline + + 1: ??? +error: the stack appears to be corrupted beyond this point + (HOST) ERROR the program has overflowed its stack +``` + +❗️ `flip-link` is a third-party tool, so make sure you've installed it through `cargo install flip-link` + +To see how we've activated `flip-link`, take a look at `advanced/firmware/.cargo/config.toml`: + +``` toml +{{#include ../../advanced/firmware/.cargo/config.toml::7}} +``` + +There, we've configured `flip-link` as the linker to be used for all ARM targets. +If you'd like to use `flip-link` in your own projects, this is all you need to add! + +🔎 Note: if you try to run `stack_overflow.rs` *without* `flip-link` enabled, you might see varying behavior depending on the `rustc` version you're using, timing and pure chance. This is because undefined behavior triggered by the program may change between `rustc` releases. + + +[`flip-link`]: https://github.com/knurling-rs/flip-link +[`flip-link` README]: https://github.com/knurling-rs/flip-link/blob/main/README.md \ No newline at end of file