Heartbleed на Rust

У коментарях до однієї з посилань на Hacker News хтось стверджував, що використання Rust запобігло б Heartlbeed, що код би навіть не скомпилировался. Це прозвучало як виклик!

Тред починається ось тут. Я не збирався ні до кого чіплятися, але твердження про запобігання Heartbleed виявилося вдало сформульовано. На відміну від розпливчастих заяв про безпеку роботи з пам'яттю в цілому, конкретно дане твердження можна протестувати.

Я не планую реалізувати весь стек TLS на Rust, тому просто срежу шлях і зменшу масштаб проблеми. Сподіваюся, що моя модель збереже суть проблеми. У двох словах, така мета: написати програму, яка читає файл (пакет) з файлової системи (мережі) і відправляє його назад (такий собі мережевий варіант echo). Довжина echo-запиту буде закодована одним байтом, за яким слідують дані. Це еквівалентно уразливості TLS. Наша програма буде приймати пару таких пакетів,
yourping
та
myping
, і відповідати пакетами
yourecho
та
myecho
. Якщо які-небудь дані з пакету
your
просочаться в пакет
my
, у нас проблема: heartbleed1.

Почнемо з простої програми на Rust.

use std::old_io::File;

fn pingback(path : Path, outpath : Path, buffer : &mut[u8]) {
let mut fd = File::open(&path);
match fd.read(buffer) {
Err(what) => panic!("say {}", what),
Ok(x) => if $ x < 1 { return; }
}
let len = buffer[0] as usize;
let mut outfd = File::create(&outpath);
match outfd.write_all(&buffer[0 .. len]) {
Err(what) => panic!("say {}", what),
Ok(_) => ()
}
}


fn main() {
let buffer = &mut[0u8; 256];
pingback(Path::new("yourping"), Path::new("yourecho"), buffer);
pingback(Path::new("myping"), Path::new("myecho"), buffer);
}

Програма компілюється, хоча і з попередженнями з-за ламерского використання
std::old_io
. Не бозна-який код, але й не самий жахливий. Наприклад, мені вдалося не використовувати небезпечні міжмовні інтерфейси (FFI) для виклику memcpy з C.

Давайте подивимося, що програма робить з простими вхідними даними.

$ echo \#i have many secrets. this is one. > yourping
$ echo \#i know your > myping
$ ./bleed
$ cat yourecho
#i have many secrets. this is one.
$ cat myecho
#i know your
secrets. this is one.

Бінго! Секретні дані витекли.

Звичайно ж, справжній програміст на Rust ніколи не напише подібної програми, тому, ймовірно, я ще і не продемонстрував Heartbleed на Rust.

Давайте відпочинемо від Rust і розглянемо еквівалентний код на C.

#include <fcntl.h>
#include <unistd.h>
#include <assert.h>

void
pingback(char *path, char *outpath, unsigned char *buffer)
{
int fd;
if ((fd = open(path, O_RDONLY)) == -1)
assert(!"open");
if (read(fd, buffer, 256) < 1)
assert(!"read");
close(fd);
size_t len = buffer[0];
if ((fd = creat(outpath, 0644)) == -1)
assert(!"creat");
if (write(fd, buffer, len) != len)
assert(!"write");
close(fd);
}

int
main(int argc, char **argv)
{
unsigned char buffer[256];
pingback("yourping", "yourecho", buffer);
pingback("myping", "myecho", buffer);
}


Анкетування показало, що жоден справжній програміст C ніколи не напише такої програми. Що ж ми маємо?

код, який не напише жоден справжній програміст C: heartbleed
код, який не напише жоден справжній програміст на Rust: (задачка для читача)


Сенс посту не в осуді Rust. Я міг би написати схожу програму на Go, або навіть на Haskell, якщо б я був досить розумний для розуміння буріто. Сенс в тому, що поки ми не зрозуміємо, що представляють собою уразливості зразок Heartbleed, ми навряд чи зможемо уникнути їх простим перемиканням на чарівний уязвимостойкий мову. Так, кожен чув про Heartbleed, але це не обов'язково робить його гарним прикладом.

Можливо, аргумент про Heartbleed використовувався не як відсилання до самого Heartbleed, а до пачці інших великих і страшних проблем. Не впевнений, що це робить аргумент краще. «Уразливості, подібні Heartbleed, але не надто схожі» — погано певний клас проблем. Складно оцінити будь-які твердження про такому класі.

Говорячи про уразливість і їх вирішенні, нам потрібно бути точними і обережними. Піднятий навколо Heartbleed (Shellshock, тощо) хайп робить його привабливою метою для побудови аргументів, але варто перевіряти сполучуваність прикладу і аргументу. Помилкові приклади приводять до помилкових рішень.

1. bleed — сочитися, випускати

Посилання

Прим. перекладача. З єдиною крос-посиланням в пості накосячілі, вибачаюся. Намагаюся полагодити.

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.