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 — сочиться, испускать

Ссылки

ссылка на оригинал статьи http://habrahabr.ru/post/249537/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *