[devel] Взгляд на флуктуации getrandom()
Vitaly Lipatov
lav на altlinux.ru
Вт Фев 11 00:15:24 MSK 2020
Три года назад (февраль 2017) в glibc 2.25 появилась
(https://sourceware.org/glibc/wiki/Release/2.25) реализация функций
getrandom и getentropy.
Расскажу, как продолжение этой истории выглядит со стороны, сейчас, по
прошествии времени.
Во-первых, эта реализация появлялась в glibc слишком долго. До этого
момента в glibc была только игрушечная random(), которую можно было
только для учебных программ использовать.
И вот после того, как в 2014 году в ядре 3.17 появилась getrandom
(https://lwn.net/Articles/606141/), такую функцию, а ещё и getentropy
(для совместимости с BSD) решили добавить и в glibc. Причём только для
ядра Linux, просто обёртку вокруг ядерного вызова. Вроде как для
потребностей проекта LibreSSL.
Желая избежать проблем с дескрипторами на открытый /dev/urandom, в glibc
решили не реализовывать fallback на случай отсутствия getrandom в ядре
(https://lwn.net/Articles/711013/), хотя первоначально такое предложение
и было (https://www.sourceware.org/bugzilla/show_bug.cgi?id=17252). До
этого я видел в glibc карусель обходных путей для fcntl-вызовов F_GETLK
и F_SETLK, поэтому такая прямота обёртки даже удивляет.
После сборки 05.04.2017 glibc версии 2.25 в Сизиф стали появляться
ошибки с python (достаточно неожиданные и с трудом понятые как
использование glibc 2.25 на старом ядре (openvz 2.6.32):
https://bugzilla.altlinux.org/show_bug.cgi?id=33356
https://bugzilla.altlinux.org/show_bug.cgi?id=33355
И сегодня ещё gnucash на ядре openvz 2.6.32 неожиданно падает,
положившись на boost:
https://bugzilla.altlinux.org/show_bug.cgi?id=38068
А boost по-простому вызывает getentropy, если glibc >= 2.25
#elif BOOST_LIB_C_GNU >= BOOST_VERSION_NUMBER(2, 25, 0) &&
!defined(BOOST_UUID_RANDOM_PROVIDER_FORCE_POSIX)
# define BOOST_UUID_RANDOM_PROVIDER_GETENTROPY
# define BOOST_UUID_RANDOM_PROVIDER_NAME getentropy
Хотя в странном решении от glibc задумано, что при возврате ENOSYS нужно
самому искать обходные пути. Что в ряде проектов и делают:
https://github.com/getdnsapi/getdns/blob/develop/src/compat/getentropy_linux.c
https://github.com/libressl-portable/openbsd/blob/master/src/lib/libcrypto/arc4random/getentropy_linux.c
Путаница с getrandom, который пляшет между ядром Linux и glibc, вполне
докатилась до boost, где долго обсуждали проблему:
https://github.com/boostorg/uuid/issues/92
выключали использование getentropy на Linux:
https://github.com/boostorg/uuid/pull/97
в итоге всё равно boost (проверялось на 1.72) пытается использовать
функцию из glibc и не имеет fallback.
Проблема была актуальной и плавающей на RHEL 7.2 с его ядро 3.10
соответствующих сборок.
Также пострадало и Qt5, работа которых на ядрах до 3.17 жёстко запрещена
указанием соответствующего свойства бинарника
https://bugzilla.altlinux.org/show_bug.cgi?id=35297
https://github.com/flathub/flathub/issues/805
Мне ощущается, что появление системного вызова getrandom (которому к
тому же когда-то не повезло быть портированным в стабильные ядра), а
впоследствии и функции getrandom в glibc — это хороший пример, насколько
осмотрительным нужно быть при добавлении новых вызовов, а особенно —
насколько информативными должна быть информация об их появлениях.
К сожалению, такая реализация в glibc может быть и (потоко)безопаснее,
но породила много путаного кода в различных библиотеках, тогда как
призвана была решить проблемы.
В общем-то, цена прогресса.
--
С уважением,
Виталий Липатов,
ALT Linux Team
Подробная информация о списке рассылки Devel