RAND_bytes се провали в OpenVPN: грешка в библиотеката или липсващ възел
Провал на RAND_bytes може да означава отказан източник на ентропия или възел, скрит от затвор. Прочетете опашката с грешки и изгледа на процеса, преди да създавате устройства.
RAND_bytes() failed е твърдение за един локален примитив, а не за акаунта, предварително споделения ключ или отдалечения порт. Две много различни повреди дават същия ред и оставят различни следи. Едната е криптографски бекенд, който отказва да издава байтове; другата е процес, който не достига източника на ентропия, за който е изграден кодът му. Разграничаването им изисква едно четене на опашката с грешки и един поглед към изгледа на файловата система на затворения процес, и тази проверка трябва да предхожда всичко, което се създава под /dev.
Какво различава върнатото значение
Документираният договор различава три изхода, не два: 1 при успех, -1 когато зареденият метод RAND не поддържа заявката, и 0 при други повреди, като обяснението остава в опашката с грешки. Справката за RAND_bytes добавя точка, която лесно се пропуска: генераторът по подразбиране взема начална стойност от операционната система на поддържаните платформи, и когато това зареждане се провали, той остава в състояние на грешка, вместо да върне предвидими байтове.
Само едно от тези числа описва средата. -1 е въпрос на компилация, доставчик или функция, защото кодът е поискал нещо, което активната реализация не предлага. 0 с оплакване за зареждането е въпрос на среда, защото генераторът изобщо не е могъл да получи ентропия. Самото число никога не казва кое от двете, а името на функцията също не.
Когато скрит възел на устройство е истинската причина
Ограничена услуга вижда друго дърво от обвивката, в която пишете. Затворите chroot, образите на контейнери и затегнатите unit файлове редовно предоставят /dev с по-малко възли от този на хоста. Ако провалящата се реализация отваря /dev/urandom по име на път, тази разлика е достатъчна да счупи стартирането, докато самият хост изглежда напълно здрав. Устройство, което съществува извън затвора, не доказва нищо за това какво затвореният процес има право да отвори.
Не всеки случаен интерфейс обаче се нуждае от път. Системното извикване getrandom в Linux не приема нито име на файл, нито файлов дескриптор, и страницата му в ръководството отбелязва, че това свойство е полезно точно там, където chroot скрива пътищата до устройства.
Следователно обяснението за липсващия възел е хипотеза за един клон от кода, а не правило за случайните числа изобщо. То се държи, когато доказателствата назовават път, и е догадка, когато доказателствата назовават нещо друго.
Първо прочетете опашката с грешки, после изгледа на процеса
Най-бързият начин да решите въпроса е да прочетете какво вече е записала библиотеката и след това да погледнете директно изгледа вътре в затвора. Започнете с компилацията на OpenSSL, която услугата действително е заредила, защото стековете на доставчиците се различават между основните версии и между дистрибуциите. След това попитайте systemd кой процес работи и какви ограничения важат за него. Едва когато двата факта са на масата, си струва да се изброят възлите, които този процес вижда.
openssl version -a
systemctl show openvpn-server@lab -p MainPID -p PrivateDevices -p DevicePolicy
pid=$(systemctl show -p MainPID --value openvpn-server@lab)
sudo ls -l /proc/"$pid"/root/dev/urandom /proc/"$pid"/root/dev/random
Изпълнявайте тези четения върху същия процес, а не върху обвивката, която случайно е отворена. Сравняването на /dev на хоста с изгледа на несвързан процес е начинът, по който грешната зависимост се поправя два пъти.
Добавете зависимостта само когато можете да я назовете
Когато доказателствата наистина назовават път, поправката е малка: направете този единствен път достъпен вътре в затвора и оставете всичко друго на мира. Bind монтирането на един възел обикновено е достатъчно, а mknod със стандартните major и minor номера на възела дава същия резултат при инсталации, където монтирането не е опция. Разширяването на sandbox-а, даването на достъп до всяко символно устройство или изключването на PrivateDevices заменя целенасочена поправка с постоянна регресия в сигурността.
Демонът за ентропия не заменя тази поправка. Пакети като haveged променят как се храни ядреният басейн; те не могат да създадат път, който затвореният процес има право да отвори. Инсталирането на един може да подобри графика за здраве, докато извикването open все още се проваля. Дръжте двата проблема отделно, иначе следващият провал отново ще бъде приписан на грешния слой.
Проверете генератора и тунела поотделно
Рестартирането е единственият тест, който използва отново същата конфигурация, същия unit файл и същото ограничение, които са причинили провала. Изпълнете го и след това четете най-новите записи в журнала, а не извадка от по-ранно стартиране.
sudo systemctl restart openvpn-server@lab
sudo journalctl -u openvpn-server@lab --since -5min --no-pager | grep -iE 'rand|entropy|Initialization Sequence'
Търсете в този изход две отделни неща: съобщението за случайния източник да изчезне и тунелът да достигне обичайния си етап на стартиране. Генератор, който отново работи, премахва една локална повреда и не казва нищо за идентичността на сървъра, удостоверенията или маршрутизацията. Тествайте това със същата клиентска конфигурация, която преди се провали, за да е сравним резултатът, а не само по-добър.