RAND_bytes() failed yra teiginys apie vieną vietinį primityvą, o ne apie paskyrą, iš anksto bendrinamą raktą ar nuotolinį prievadą. Dvi labai skirtingos gedimų rūšys sukuria tą pačią eilutę ir palieka skirtingus pėdsakus. Viena – kriptografinis backend'as, atsisakantis išleisti baitus; kita – procesas, nepasiekiantis entropijos šaltinio, kuriam buvo sukurtas jo kodas. Norint juos atskirti, reikia vieno klaidų eilės skaitymo ir vieno žvilgsnio į įkalinto proceso failų sistemos vaizdą, ir šis patikrinimas turi būti prieš viską, kas sukuriama po /dev.

Ką išskiria grąžinama reikšmė

Dokumentuota sutartis išskiria tris baigtis, o ne dvi: 1 sėkmei, -1 kai įkeltas RAND metodas nepalaiko užklausos, ir 0 kitiems gedimams, paaiškinimą paliekant klaidų eilėje. RAND_bytes nuoroda prideda punktą, kurį lengva praleisti: numatytasis generatorius palaikomose platformose ima sėklą iš operacinės sistemos, o kai šis sėjimas nepavyksta, jis lieka klaidos būsenoje, o ne grąžina nuspėjamus baitus.

Tik vienas iš tų skaičių apibūdina aplinką. -1 yra kūrimo, tiekėjo ar funkcijos klausimas, nes kodas paprašė to, ko aktyvi implementacija nesiūlo. 0 su sėjimo skundu yra aplinkos klausimas, nes generatorius apskritai negalėjo gauti entropijos. Pats skaičius niekada nepasako, kuris, ir funkcijos pavadinimas taip pat ne.

Kai paslėptas įrenginio mazgas yra tikroji priežastis

Apribota tarnyba mato kitą medį nei apvalkalas, kuriame rašote. Chroot kalėjimai, konteinerių atvaizdai ir sukietinti unit failai paprastai pateikia /dev, kuriame mazgų mažiau nei pagrindinio kompiuterio. Jei nepavykstanti implementacija atidaro /dev/urandom pagal kelio pavadinimą, šio skirtumo pakanka sugadinti paleidimą, nors pats kompiuteris atrodo visiškai sveikas. Įrenginys, egzistuojantis už kalėjimo ribų, nieko neįrodo apie tai, ką įkalintam procesui leidžiama atidaryti.

Vis dėlto ne kiekvienai atsitiktinei sąsajai reikia kelio. Linux getrandom sistemos iškvietimas nepriima nei failo pavadinimo, nei failo deskriptoriaus, o jo vadovo puslapis pažymi, kad ši savybė naudinga būtent ten, kur chroot slepia įrenginių kelius.

Taigi trūkstamo mazgo paaiškinimas yra hipotezė apie vieną kodo šaką, o ne taisyklė apie atsitiktinius skaičius apskritai. Ji galioja, kai įrodymai įvardija kelią, ir yra spėjimas, kai įrodymai įvardija ką nors kita.

Pirmiausia perskaitykite klaidų eilę, tada proceso vaizdą

Greičiausias būdas išspręsti klausimą – perskaityti, ką biblioteka jau užfiksavo, ir tada tiesiogiai pažvelgti į vaizdą kalėjimo viduje. Pradėkite nuo OpenSSL kompiliacijos, kurią tarnyba iš tikrųjų įkėlė, nes tiekėjų stekai skiriasi tarp pagrindinių versijų ir tarp distribucijų. Tada paklauskite systemd, kuris procesas veikia ir kokie apribojimai jam taikomi. Tik kai abu faktai yra ant stalo, verta išvardyti mazgus, kuriuos tas procesas mato.

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

Atlikite tuos skaitymus tame pačiame procese, o ne apvalkale, kuris atsitiktinai atidarytas. Pagrindinio kompiuterio /dev lyginimas su nesusijusio proceso vaizdu yra būdas, kuriuo neteisinga priklausomybė sutvarkoma du kartus.

Pridėkite priklausomybę tik tada, kai galite ją įvardyti

Kai įrodymai tikrai įvardija kelią, taisymas nedidelis: padarykite tą vieną kelią prieinamą kalėjimo viduje ir palikite visa kita ramybėje. Vieno mazgo bind prijungimas paprastai pakanka, o mknod su standartiniais mazgo major ir minor numeriais duoda tą patį rezultatą diegimuose, kur prijungimas nėra galimybė. Smėlio dėžės išplėtimas, prieigos prie kiekvieno simbolių įrenginio suteikimas ar PrivateDevices išjungimas tikslinį pataisymą iškeičia į nuolatinę saugumo regresiją.

Entropijos demonas nepakeičia šio taisymo. Paketai kaip haveged keičia, kaip maitinamas branduolio baseinas; jie negali sukurti kelio, kurį įkalintam procesui leidžiama atidaryti. Vieno įdiegimas gali pagerinti sveikatos grafiko išvaizdą, kol atidarymo iškvietimas vis dar nepavyksta. Laikykite dvi problemas atskirai, kitaip kitas gedimas vėl bus priskirtas netinkamam sluoksniui.

Patikrinkite generatorių ir tunelį atskirai

Paleidimas iš naujo yra vienintelis testas, kuris iš naujo naudoja tą pačią konfigūraciją, tą patį unit failą ir tą patį izoliavimą, kurie sukėlė gedimą. Paleiskite jį ir tada skaitykite naujausius žurnalo įrašus, o ne ankstesnio paleidimo imtį.

sudo systemctl restart openvpn-server@lab
sudo journalctl -u openvpn-server@lab --since -5min --no-pager | grep -iE 'rand|entropy|Initialization Sequence'

Toje išvestyje ieškokite dviejų atskirų dalykų: pranešimo apie atsitiktinį šaltinį išnykimo ir tunelio pasiekto įprasto paleidimo etapo. Vėl veikiantis generatorius pašalina vieną vietinį gedimą ir nieko nesako apie serverio tapatybę, kredencialus ar maršrutizavimą. Išbandykite tai ta pačia kliento konfigūracija, kuri anksčiau nepavyko, kad rezultatas būtų palyginamas, o ne tik geresnis.

Susiję straipsniai