LINUX.ORG.RU

Разбил лицо фейспалмом от openssl

 , ,


1

1

Пытались отладить программу которая работает с openssl.

Вывод: разработчики openssl говнокодеры и идиоты

#1

На новых версиях valgrind он просто не может терпеть весь тот ужас что написан в openssl и вылетает сразу. Баг висит уже год в confirmed, ничего делать никто не собирается: https://bugs.launchpad.net/ubuntu/ source/valgrind/ bug/1574437

#2

Пытались сейчас отладить на другом valgrind'е. Все, что возвращается из SSL_read valgrind считает неинициализированными значениями и генерирует тысячи предупреждений. Исследовали. Оказывается что надо пересобрать openssl с флагами -DPURIFY и -DPEDANTIC, потому что *openssl использует неинициализированные значения для получения рендома*. Нашли в configure (дело под слакой) флаг purify ставящий соответствующие флаги. Сюрприз! Он конфликтует с linux-elf. ПОлезли в исходники с надеждой посмотреть сильно ли плохо будет если мы просто проставим флаг -DPURIFY. Сюрприз№2:

#ifndef PURIFY /* purify complains */
        /* DO NOT REMOVE THE FOLLOWING CALL TO MD_Update()! */
        if (!MD_Update(&m,buf,j)) 
            goto err; 
        /* We know that line may cause programs such as 
           purify and valgrind to complain about use of 
           uninitialized data.  */ 
#endif
ОНИ ЗНАЮТ, НО ИМ П***Й! ТО ЧТО ЭТО ПОДЕЛИЕ НЕ ДАЕТ ОТЛАДИТЬ ПРОГРАММУ ИМ ТОЖЕ П***Й! АААААА!!!

Выдохнул. Если что - перенесите в толксы.

★★

Увы, всё так. Имел несчастье писать код с использованием openssl, адское говнокодище. Список дыр в этом поделии весьма фееричен. Поэтому и понаделали форков (кстати, попробуй какой-нить libressl). Но одну из проблем форки не решают: они пытаются сохранить чрезвычайно костыльный API, поэтому кодить с ними не легче.

true_admin ★★★★★ ()

На новых версиях valgrind он просто не может терпеть весь тот ужас

попробуй drmemory

потому что *openssl использует неинициализированные значения для получения рендома

Это широко известный в узких кругах факт, см. CVE-2008-0166 https://github.com/g0tmi1k/debian-ssh#the-bug

SZT ★★★ ()

Вывод: разработчики openssl говнокодеры и идиоты

Не стоит так сразу сгоряча судить. Может это ради какой-то хитрой закладки в интересах АНБ.

tim239 ()

Падает valgrind, а виноват почему-то openssl

у меня valgrind-3.10.1 не падает, ворнинги про неинициализированные значения можно игнорировать, definitely lost в моём коде находило, всё пучком

Harald ★★★★★ ()

1) Крэш валгринда - это баг исключительно валгринда и никак иначе.

2) Конкретно вот эти неинициализированные переменные - это так и должно быть. Это не баг. Кретины-мейнтейнеры в debian как-то героически «пофиксили» эту «багу», и в результате получили серьёзную уязвимость. Собственно именно после этого забавного инцидента, авторы openssl и добавили коммент про DO NOT REMOVE. -DPURIFY можно включать только для целей запуска под анализаторами. Если включить при сборке на продакшене, то будет та же проблема с безопасностью, которую получили в дебиане.

mironov_ivan ★★★★★ ()
Последнее исправление: mironov_ivan (всего исправлений: 1)
Ответ на: комментарий от PPP328

Если отладчик при попытке работы с каким-то кодом падает - это хреновый отладчик. Антиотладочные приемы в проприетарщине и то до такого отладчики не доводят.

Но идея рандома из неинициализированных значений попахивает говном. Мощненько так разит, я бы сказал.

Вот окажутся они на системе, где malloc будет всегда возвращаться зануленный блок памяти - и всё, пирдуха.

Pinkbyte ★★★★★ ()
Последнее исправление: Pinkbyte (всего исправлений: 2)
Ответ на: комментарий от Harald

но что делать на системах, где нет тру-источника случайных чисел?

Даже явный псевдослучайный rand лучше чем использование неинициализированной переменной. Потому что чёрт его знает как завтра компилятор тебе соптимизирует undefined behaviour.

Pinkbyte ★★★★★ ()
Ответ на: комментарий от Pinkbyte

Потому что чёрт его знает как завтра компилятор тебе соптимизирует undefined behaviour.

воот, значит это чуть более рандомно, чем предсказуемый выхлоп rand() :)

Harald ★★★★★ ()
Ответ на: комментарий от Pinkbyte

Но идея рандома из неинициализированных значений попахивает говном. Мощненько так разит, я бы сказал.

Вот окажутся они на системе, где malloc будет всегда возвращаться зануленный блок памяти - и всё, пирдуха.

Насколько я помню, там всё сложнее, чем просто «рандом из неинициализированной» памяти. Вот не наврать бы сейчас, потому как сам уже не помню... Вроде бы там было два места, где вызывалась сабжевая функция, и неинициализированный буфер там был только на одном вызове (и использовался он только если никаких других источников рандома нет), а на другом - нормальный рандом откуда-то ещё (скорее всего из /dev/urandom, который обычно лучше того, что можно изобразить в юзерспейсе). А в дебиане то ли неправильно поняли вывод валгринда, то ли решили пофиксить сразу вообще всё, то ли как то ещё переклинило голову у них, и они закомментили оба вызова.

mironov_ivan ★★★★★ ()
Последнее исправление: mironov_ivan (всего исправлений: 1)
Ответ на: комментарий от SZT

попробуй drmemory

Оно есть под линукс? Я, честно говоря, считал, что это «аналог valgrind для винды».

P.S. Посмотрел - точно есть. Занятно.

hobbit ★★★★★ ()
Последнее исправление: hobbit (всего исправлений: 1)
Ответ на: комментарий от mironov_ivan

Так я и не утверждаю, что они только на это полагаются. Ясен пень, что используется что-то еще, более вменяемое. Но, если грубо, в поиске случайных элементов сложение двух псевдослучайных величин не всегда даёт более «случайную» в результате.

Проблема именно в том, что то, что они берут за якобы случайную величину на некоторых платформах может равняться нулю всегда.

Вспоминается один комикс xkcd на эту тему

Pinkbyte ★★★★★ ()
Ответ на: комментарий от Harald

Если он его во всех вызовах всегда оптимизирует в нуль то будет не очень хорошо.

Вспоминаю генератор случайных чисел в паскале, который если не дергать функцией ЕМНИП srand(), то он будет всегда в пределах процесса выдавать одну и ту же последовательность псевдослучайных чисел.

Так это еще ничего(хотя для криптографии это уже швах) - они там хотя бы разные.

Pinkbyte ★★★★★ ()
Ответ на: комментарий от mironov_ivan

2) Конкретно вот эти неинициализированные переменные - это так и должно быть. Это не баг

Нет, так быть не должно. Брать рандом из неинициализированных переменных это очень плохая идея.

SZT ★★★ ()
Ответ на: комментарий от SZT

Брать рандом из неинициализированных переменных это очень плохая идея.

Но если его не пытаться оттуда брать, то лучше от этого тоже не станет. А если там всё-таки хоть немного рандома там есть, то станет хуже. Там же явно есть какие-то проверки на тему качества данных из этого неинициализированного участка, и если там нули, например, то они просто не будут учитываться.

mironov_ivan ★★★★★ ()
Ответ на: комментарий от mironov_ivan

Там же явно есть какие-то проверки на тему качества данных из этого неинициализированного участка

Вот в этом я очень не уверен. Если бы там такие проверки были, дебиановцы не смогли бы так легко это сломать. Покажите ссылку на код, который это качество каким-то образом проверяет

SZT ★★★ ()
Ответ на: комментарий от SZT

Вот в этом я очень не уверен. Если бы там такие проверки были, дебиановцы не смогли бы так легко это сломать. Покажите ссылку на код, который это качество каким-то образом проверяет

Я полагаю, что это делает именно тот код, который они закомментили =). Потому что если вообще никакие данные никуда не передаются, то и проверять в общем-то нечего.

Единственная проблема тут - это отсутствие проверки случайности результата (а не входных данных). Но я в теме почти не разбираюсь, так что хз можно ли это реализовать. К тому же, в случае дебиана, какой-то источник рандома там всё же оставался. Его было достаточно для того, чтобы генерируемые ключи были достаточно разными, чтобы косяк долго не замечали.

mironov_ivan ★★★★★ ()
Последнее исправление: mironov_ivan (всего исправлений: 1)
Ответ на: комментарий от mironov_ivan

Да, рандом еще можно получить кучей разных способов. Например, можно получать через clock_gettime() время и брать каждый раз последний бит от наносекунд

struct timespec {
    time_t   tv_sec;        /* seconds */
    long     tv_nsec;       /* nanoseconds */
};
Притом вызвать этот код n-ное количество раз, между вызовами запуская sleep() в многопоточной среде.

SZT ★★★ ()
Ответ на: комментарий от SZT

И ещё раз: дебианопроблема возникла не из-за того, что закомментили получение рандома из неинициализированной памяти, а из-за того, что вместе с этим закомментировали получение рандома из более надёжного источника.

Я не вижу ничего плохого в том, что openssl пытается получить энтропию из всех доступных источников, где она в принципе может быть.

А у конкретно метода с clock_gettime() и sleep() есть как минимум очевидный недостаток, который делает этот метод неюзабельным для openssl - это медленно. Гораздо лучше делать это отдельным системным процессом и фидить полученные данные в /dev/random. А openssl уже будет читать /dev/random или /dev/urandom (если надо гарантированно неблокирующее чтение). А ещё есть штуки вроде haveged.

mironov_ivan ★★★★★ ()
Последнее исправление: mironov_ivan (всего исправлений: 1)
Ответ на: комментарий от SZT

Это уже дополнительное хардваре, которого может не быть.

И вообще тема куда-то ушла от изначального обсуждения говнокода в валгринде и опенссл...

mironov_ivan ★★★★★ ()
Последнее исправление: mironov_ivan (всего исправлений: 1)
Ответ на: комментарий от mironov_ivan

Это уже дополнительное хардваре, которого может не быть.

А что тогда конкретно есть? Ну вот предположим что есть какое-то устройство, которе читает показания с какого-то датчика и отправляет результат по UART. В таком случае, если показания датчика в последнем бите достаточно случайны, например мы меряем скорость ветра на улице, и эта скорость непостоянна, то можно брать последний бит из скорости ветра, и его использовать. А если ветра вообще нет, то и отсылать ничего не стоит.

SZT ★★★ ()
Последнее исправление: SZT (всего исправлений: 1)
Ответ на: комментарий от PPP328

В https://bugs.launchpad.net/ubuntu/ source/valgrind/ bug/1574437 чинить понадобилось не обработку неинициализированных данных, а поддержку AVX инструкций в valgrind: http://valgrind.10908.n7.nabble.com/vex-r3213-trunk-priv-ir-opt-c-td56288.html

Это ошибка valgrind, а не openssl.

sf ★★ ()
Ответ на: комментарий от hippi90

*openssl использует неинициализированные значения для получения рендома*

Сам спросил, сам ответил. Так задумано, это фича.

Это хреновая практика, а не фича.

andreyu ★★★★★ ()

потому что *openssl использует неинициализированные значения для получения рендома*

Уже не использует. Исправлено год назад в версии 1.1.0. Текущая стабильная версия OpenSSL не так уж и плоха с точки зрения качества кода. Над ней работают full-time несколько разработчиков, в итоге много чего было переписано.

anonymous ()