RAND_bytes() failed je tvrzení o jednom místním primitivu, ne o účtu, předsdíleném klíči nebo vzdáleném portu. Dvě velmi odlišné závady vytvářejí stejný řádek a zanechávají různé stopy. Jedna je kryptografický backend, který odmítá vydávat bajty; druhá je proces, který nedosáhne na zdroj entropie, pro který byl jeho kód postaven. Oddělit je vyžaduje jedno přečtení fronty chyb a jeden pohled na souborový systém uvězněného procesu, a tato kontrola patří před vše, co se vytvoří pod /dev.

Co návratová hodnota rozlišuje

Dokumentovaný kontrakt rozlišuje tři výsledky, ne dva: 1 pro úspěch, -1 když načtená metoda RAND nepodporuje požadavek, a 0 pro ostatní selhání, přičemž vysvětlení zůstává ve frontě chyb. Reference RAND_bytes přidává bod, který lze snadno přehlédnout: výchozí generátor se na podporovaných platformách seeduje z operačního systému, a když toto seedování selže, zůstane v chybovém stavu, místo aby vracel předvídatelné bajty.

Jen jedno z těch čísel popisuje prostředí. -1 je otázka buildu, poskytovatele nebo funkce, protože kód žádal něco, co aktivní implementace nenabízí. 0 se stížností na seedování je otázka prostředí, protože generátor nemohl entropii vůbec získat. Číslo samo nikdy neřekne které, a název funkce také ne.

Kdy je skutečnou příčinou skrytý uzel zařízení

Omezená služba vidí jiný strom než shell, do kterého píšete. Chrootová vězení, obrazy kontejnerů a zpevněné unit soubory pravidelně předkládají /dev s méně uzly, než má hostitel. Pokud selhávající implementace otevírá /dev/urandom podle cesty, tento rozdíl stačí k rozbití startu, zatímco hostitel sám vypadá naprosto zdravě. Zařízení existující mimo vězení nic nedokazuje o tom, co uvězněný proces smí otevřít.

Ne každé náhodné rozhraní však potřebuje cestu. Systémové volání getrandom v Linuxu nepřijímá žádné jméno souboru ani deskriptor souboru a jeho manuálová stránka poznamenává, že tato vlastnost je užitečná právě tam, kde chroot skrývá cesty zařízení.

Vysvětlení chybějícího uzlu je tedy hypotéza o jedné větvi kódu, ne pravidlo o náhodných číslech obecně. Drží, když důkazy jmenují cestu, a je dohadem, když důkazy jmenují něco jiného.

Nejprve přečtěte frontu chyb, potom pohled procesu

Nejrychlejší způsob, jak otázku vyřešit, je přečíst, co knihovna už zaznamenala, a pak se podívat přímo na pohled uvnitř vězení. Začněte buildem OpenSSL, který služba skutečně načetla, protože zásobníky poskytovatelů se liší mezi hlavními verzemi a mezi distribucemi. Potom se zeptejte systemd, který proces běží a jaká omezení pro něj platí. Teprve když obě skutečnosti leží na stole, stojí za to vypsat uzly, které tento proces vidí.

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

Spouštějte tato čtení proti stejnému procesu, ne proti shellu, který je zrovna otevřený. Porovnávat /dev hostitele s pohledem nesouvisejícího procesu je způsob, jak se špatná závislost opraví dvakrát.

Závislost přidejte až tehdy, když ji umíte pojmenovat

Když důkazy cestu skutečně jmenují, je oprava malá: zpřístupněte tu jednu cestu uvnitř vězení a vše ostatní nechte být. Bind mount jediného uzlu obvykle stačí a mknod se standardními major a minor čísly uzlu dává stejný výsledek v instalacích, kde mount není možností. Rozšíření sandboxu, přidělení přístupu ke každému znakovému zařízení nebo vypnutí PrivateDevices vymění cílenou opravu za trvalou bezpečnostní regresi.

Entropický démon tuto opravu nenahrazuje. Balíčky jako haveged mění, jak se krmí jádrový pool; nemohou vytvořit cestu, kterou uvězněný proces smí otevřít. Instalace jednoho může vylepšit graf zdraví, zatímco volání open stále selhává. Držte oba problémy oddělené, jinak bude další selhání zase připsáno špatné vrstvě.

Ověřte generátor a tunel odděleně

Restart je jediný test, který znovu použije stejnou konfiguraci, stejný unit soubor a stejné omezení, které selhání způsobily. Spusťte ho a potom čtěte nejnovější záznamy žurnálu, ne vzorek z dřívějšího startu.

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

Hledejte v tom výstupu dvě oddělené věci: mizející zprávu o náhodném zdroji a tunel dosahující svého obvyklého startovního milníku. Generátor, který zase funguje, odstraní jednu místní závadu a neříká nic o identitě serveru, přihlašovacích údajích ani routování. Otestujte to se stejnou klientskou konfigurací, která předtím selhala, aby byl výsledek srovnatelný a ne jen lepší.

Související články