-
-
Save rexim/38c176fe4669ef83db69aca9909d7b7f to your computer and use it in GitHub Desktop.
// The Most Memory Safe Buffer Overflow in Rust! | |
// | |
// Consider all the code below under Public Domain | |
// | |
// How to build: | |
// $ rustc main.rs | |
// | |
// Wrong password: | |
// $ printf "hello\n" | ./main | |
// | |
// Right password: | |
// $ printf "password\n" | ./main | |
// | |
// Universal password: | |
// $ printf "aaaaaaaaaaaaaa\0aaaaaaaaaaaaaa\0" | ./main | |
// | |
// Support Rust Recovery Foundation: https://rustrecoveryfoundation.neocities.org/ | |
use std::io::{BufRead, Write}; | |
const BUF_CAP: usize = 15; | |
type Ptr = usize; | |
fn alloc_buffer(mem: &mut Vec::<char>, size: usize) -> Ptr { | |
let result = mem.len(); | |
for _ in 0..size { | |
mem.push(' ') | |
} | |
result | |
} | |
fn alloc_str(mem: &mut Vec<char>, s: &str) -> Ptr { | |
let result = mem.len(); | |
for c in s.chars() { | |
mem.push(c) | |
} | |
mem.push('\0'); | |
result | |
} | |
fn read_line_into_buffer(input: &mut impl BufRead, mem: &mut Vec<char>, buf: Ptr) { | |
let mut s = String::new(); | |
let n = input.read_line(&mut s).unwrap(); | |
for (i, c) in s.chars().enumerate() { | |
mem[buf + i] = c; | |
} | |
if mem[buf + n - 1] == '\n' { | |
mem[buf + n - 1] = '\0' | |
} else { | |
mem[buf + n] = '\0'; | |
} | |
} | |
fn streq(mem: &Vec<char>, mut s1: Ptr, mut s2: Ptr) -> bool { | |
while mem[s1] != '\0' && mem[s2] != '\0' { | |
if mem[s1] != mem[s2] { | |
return false; | |
} | |
s1 += 1; | |
s2 += 1; | |
} | |
mem[s1] == '\0' && mem[s2] == '\0' | |
} | |
fn main() { | |
let mut mem = Vec::<char>::new(); | |
let buffer = alloc_buffer(&mut mem, BUF_CAP); | |
let password = alloc_str(&mut mem, "password"); | |
alloc_buffer(&mut mem, BUF_CAP); | |
print!("Password: "); | |
std::io::stdout().flush().unwrap(); | |
read_line_into_buffer(&mut std::io::stdin().lock(), &mut mem, buffer); | |
if streq(&mem, buffer, password) { | |
println!("Access Granted!") | |
} else { | |
println!("Access Denied!") | |
} | |
} |
I see there are two problems, but for one of them, instead of 'buffer overflow', I think it's more like not having a
length
field in yourLinkedList
class whoseget_length
is supposed to beO(1)
. Here is my summary of what might go wrong in this example:let n = // some number not known in compile time; // We define `buf_a` to be the first 3 bytes of `v`. Other bytes are considered something else. let v: Vec<u8> = vec![0, 0, 0, 20, 20, 20]; // No! This is not actually an element of `buf_a`, we just accessed something outside of `buf_a`! let element_of_buf_a = v[3]; // No! We might get a index out of bound error! let element_of_v = v[n]; // But the compiler is fine with this code and does not even warn us!@rexim Do you think this minifies this example? I am new to Rust, so I might be wrong.
Indices in Rust specifically don't have a concept of ownership attached to them with all the corresponding consequences which you should always keep in mind.
Hmm... I am not sure what you mean, are you saying that you can not move an element out of Vec
if it is not Copy
and semantically vec[index]
actually mean copy the element out? Or that the traits backing the []
syntax(i.e. Index
IndexMut
) only gives &T
and &mut T
but not T
? Or something about index
type itself (usize
, Range
, ...)?
I will be very grateful if you can elaborate since I am still learning Rust.
@TinusgragLin yes, Index and IndexMut do in fact provide &T and &mut T.
Here is the thing about C... Depending on the situation
list[index]
may NOT segfault even whenindex >= list.length()
, which is way worse ;)