Skip to content

Commit dd3fbc8

Browse files
committed
Verify zeroed stack with dynamic stack frames
1 parent 3bfa93f commit dd3fbc8

File tree

3 files changed

+28
-4
lines changed

3 files changed

+28
-4
lines changed

programs/sbf/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ rust-v0:
2020
cp -r target/sbpf-solana-solana/release/* target/deploy
2121

2222
rust-v1:
23-
cargo +solana build --release --target sbpfv1-solana-solana --workspace ; \
23+
cargo +solana build --release --target sbpfv1-solana-solana --workspace --features dynamic-frames ; \
2424
cp -r target/sbpfv1-solana-solana/release/* target/deploy
2525

2626
.PHONY: rust-v0

programs/sbf/rust/invoke/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,6 @@ crate-type = ["cdylib"]
1919

2020
[lints]
2121
workspace = true
22+
23+
[features]
24+
dynamic-frames = []

programs/sbf/rust/invoke/src/lib.rs

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
#![allow(unreachable_code)]
44
#![allow(clippy::arithmetic_side_effects)]
55

6+
#[cfg(feature = "dynamic-frames")]
7+
use solana_program::program_memory::sol_memcmp;
68
use {
79
solana_program::{
810
account_info::AccountInfo,
@@ -1456,19 +1458,38 @@ fn process_instruction<'a>(
14561458
heap[8..pos].fill(42);
14571459

14581460
// Check that the stack is zeroed too.
1459-
//
1461+
let stack = unsafe {
1462+
slice::from_raw_parts_mut(
1463+
MM_STACK_START as *mut u8,
1464+
MAX_CALL_DEPTH * STACK_FRAME_SIZE,
1465+
)
1466+
};
1467+
1468+
#[cfg(not(feature = "dynamic-frames"))]
14601469
// We don't know in which frame we are now, so we skip a few (10) frames at the start
14611470
// which might have been used by the current call stack. We check that the memory for
14621471
// the 10..MAX_CALL_DEPTH frames is zeroed. Then we write a sentinel value, and in the
14631472
// next nested invocation check that it's been zeroed.
1464-
let stack =
1465-
unsafe { slice::from_raw_parts_mut(MM_STACK_START as *mut u8, 0x100000000) };
1473+
//
1474+
// When we don't have dynamic stack frames, the stack grows from lower addresses
1475+
// to higher addresses, so we compare accordingly.
14661476
for i in 10..MAX_CALL_DEPTH {
14671477
let stack = &mut stack[i * STACK_FRAME_SIZE..][..STACK_FRAME_SIZE];
14681478
assert!(stack == &ZEROS[..STACK_FRAME_SIZE], "stack not zeroed");
14691479
stack.fill(42);
14701480
}
14711481

1482+
#[cfg(feature = "dynamic-frames")]
1483+
// When we have dynamic frames, the stack grows from the higher addresses, so we
1484+
// compare from zero until the beginning of a function frame.
1485+
// We have 64 * 4096 = 262.144 bytes of stack space, and we consider around 4096
1486+
// already used by the current function and previous calls. We are considering a
1487+
// little less than 63 * 4096 = 258.048 bytes to be zeroed.
1488+
{
1489+
assert_eq!(sol_memcmp(stack, &ZEROS, 257900), 0);
1490+
stack[..257900].fill(42);
1491+
}
1492+
14721493
// Recurse to check that the stack and heap are zeroed.
14731494
//
14741495
// We recurse until we go over max CPI depth and error out. Stack and heap allocations

0 commit comments

Comments
 (0)