3 ms·
If you can make a truly enormous stack array you can sometimes skip past the end of the stack onto the heap (or another section of memory). Then any writes to t
by muricula 8y ago
If you can make a truly enormous stack array you can sometimes skip past the end of the stack onto the heap (or another section of memory). Then any writes to the array which the program thinks are going to the stack are actually going to the heap. This is sometimes known as stack clashing.
- saagarjha 8y agoIs this something you can do in Rust?
- eridius 8y agoI haven't tried, but maybe with something like let huge_ary: [u8; 2097152 /* 2MiB */] = unsafe { ::std::mem::uninitialized() }; // hopefully huge_ary has bumped the stack pointer past any guard pages // and any further stack values will overwrite the heap
- saagarjha 8y agoWell, you're doing unsafe things there, so all bets are off.
- eridius 8y agoYou might be able to hack it by saying something like let huge_ary: [u8; 2097152]; if false_value_compiler_cant_prove_is_false { huge_ary = [0; 2097152]; } // hopefully huge_ary has reserved space on the stack despite not being initialized // and so any further stack values would overwrite the heap
- hyperman1 8y agoWhy do you need the if construction? The stack grows downards (at least on x86_64), and clearing with zeroes in general starts at the first adress (even if this isnt guaranteed). So the CPU sees a write 2097152 bytes below the last used stack location. Which might be in the heap if ther is no stack protection. Then again, 2Mb is nothing on a 64 bit processor, so I don't think the chanse of hitting the heap is very big.
- eridius 8y agoOverwriting the heap is pointless if you immediately crash due to hitting the guard page(s). The point is to move the stack pointer without actually writing anything, so you can then write what you want into the heap without crashing. The 2Mib was assuming you've already pushed the stack to its limit and are sitting just above the guard page(s). You could replace that with whatever size you think is appropriate.
- estebank 8y agoYou'll get error[E0381]: borrow of possibly uninitialized variable: `huge_ary` --> src/main.rs:6:7 | 6 | bar(&huge_ary); | ^^^^^^^^^ use of possibly uninitialized `huge_ary` https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=49d82e946bd933ff8af80a4ed2345c1e https://play.rust-lang.org/?version=nightly&mode=debug&editi...
- eridius 8y agoYou're not supposed to use the array, it's just supposed to exist on the stack. I'm not sure how to ensure the stack space isn't reclaimed; maybe we can do something with declaring it up top, then putting the `if` that initializes it later on, and hope the compiler still reserves the stack space for huge_ary ahead of stack for other variables?
- kam 8y agoAt least on x86-64, Rust inserts stack probes to ensure that it can't skip over the guard pages at the end of the stack. Last I saw, it was waiting on LLVM support to add this for some other platforms, though.