Збой RAND_bytes у OpenVPN: памылка бібліятэкі або адсутны вузел
Збой RAND_bytes можа азначаць адхіленую крыніцу энтрапіі або вузел, схаваны турмой. Прачытайце чаргу памылак і прадстаўленне працэсу, перш чым ствараць прылады.
RAND_bytes() failed — гэта сцвярджэнне пра адзін лакальны прымітыў, а не пра ўліковы запіс, загадзя размеркаваны ключ ці аддалены порт. Дзве цалкам розныя няспраўнасці даюць той самы радок і пакідаюць розныя сляды. Адна — крыптаграфічны бэкенд, які адмаўляецца выдаваць байты; іншая — працэс, які не дасягае крыніцы энтрапіі, для якой пабудаваны яго код. Каб іх адрозніць, патрэбны адно чытанне чаргі памылак і адзін позірк на прадстаўленне файлавай сістэмы працэсу, замкнёнага ў турме, і гэтая праверка павінна папярэднічаць усему, што ствараецца пад /dev.
Што адрознівае значэнне, якое вяртаецца
Дакументаваны кантракт адрознівае тры вынікі, а не два: 1 пры поспеху, -1 калі загружаны метад RAND не падтрымлівае запыту, і 0 пры іншых збоях, прычым тлумачэнне застаецца ў чарзе памылак. Даведка RAND_bytes дадае пункт, які лёгка прапусціць: стандартны генератар атрымлівае пачатковае значэнне з аперацыйнай сістэмы на платформах, якія падтрымліваюцца, і калі гэта запаўненне не ўдаецца, ён застаецца ў стане памылкі, а не вяртае прадказальныя байты.
Толькі адно з гэтых лікаў апісвае асяроддзе. -1 — гэта пытанне зборкі, пастаўшчыка ці функцыі, бо код запатрабаваў тое, чаго актыўная рэалізацыя не прапануе. 0 са скаргай на запаўненне — пытанне асяроддзя, бо генератар зусім не змог атрымаць энтрапію. Само лік ніколі не кажа, якое з двух, і назва функцыі таксама.
Калі схаваны вузел прылады — сапраўдная прычына
Абмежаваная служба бачыць іншае дрэва, чым абалонка, у якой вы друкуеце. Турмы chroot, вобразы кантэйнераў і ўзмоцненыя файлы модуляў рэгулярна прапануюць /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 са стандартнымі мажорным і мінорным нумарамі вузла дае той самы вынік ва ўстаноўках, дзе мантаванне немагчымае. Пашырэнне пясочніцы, даванне доступу да ўсіх сімвольных прылад або выключэнне PrivateDevices мяняюць кропкавае выпраўленне на пастаянную рэгрэсію бяспекі.
Дэман энтрапіі не замяняе гэтае выпраўленне. Пакеты накшталт haveged мяняюць тое, як сілкуецца пул ядра; яны не могуць стварыць шлях, які замкнёнаму працэсу дазволена адкрыць. Устаноўка аднаго можа палепшыць графік стану, пакуль выклік open усё яшчэ церпіць няўдачу. Трымайце дзве праблемы асобна, інакш наступны збой зноў спішуць на няправільны слой.
Правярайце генератар і тунель асобна
Перазапуск — адзіная праверка, якая выкарыстоўвае тую самую канфігурацыю, той самы файл модуля і тое самае абмежаванне, што прывялі да збою. Выканайце яго, потым чытайце найсвежыя запісы журнала, а не выбарку з папярэдняга запуску.
sudo systemctl restart openvpn-server@lab
sudo journalctl -u openvpn-server@lab --since -5min --no-pager | grep -iE 'rand|entropy|Initialization Sequence'
Шукайце ў гэтым вывадзе дзве асобныя рэчы: знікненне паведамлення пра выпадковую крыніцу і дасягненне тунэлем звычайнай адзнакі запуску. Генератар, які зноў працуе, прыбірае адзін лакальны збой і нічога не кажа пра ідэнтычнасць сервера, уліковыя даныя ці маршрутызацыю. Праверце гэта той самай кліенцкай канфігурацыяй, якая раней церпяла няўдачу, каб вынік быў параўнальным, а не проста лепшым.