RAND_bytes v OpenVPN selhal: chyba knihovny nebo chybějící uzel
Selhání RAND_bytes může znamenat odmítnutý zdroj entropie nebo uzel skrytý vězením. Přečtěte frontu chyb a pohled procesu, než začnete vytvářet zařízení.
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ší.