Doba kamenná, doba bronzová, doba unixová
Uvnitř unixových operačních systémů (často i jinde) je čas měřený od počátku doby unixové (Unix epoch), tj. od 1. ledna 1970 00:00:00 UTC(Coordinated Universal Time). Unixové hodiny neukazují běžně používané roky, měsíce, týdny, dny, hodiny a minuty. Unixové hodiny (volání funce time()) ukazují počet sekund od počátku doby unixové. Každý den se tak číslo na unixových hodinách zvýší o 86400 (1 den x 24 hodin x 60 minut x 60 sekund). Samozřejmě existují funkce (ctime()) pro převod sekund na běžně používané datum a obráceně.
Kam s časem?
Když programátor potřebuje pracovat s časem, uloží jej (počet sekund) do nějaké proměnné. Proměnná by měla být deklarována jako time_t, často se ale stává, že ji programátoři deklarují jako signed int nebo signed long. Velikost všech třech typů je obvykle 32 bitů. Protože první bit zleva slouží k uložení znaménka (0 představuje kladné číslo a 1 představuje číslo záporné), lze k uložení počtu sekund využít pouze zbylých 31 bitů. V proměnné tak lze ukládat hodnoty od –231 do 231 – 1, tj. od –2147483648 do 2147483647, tj. do 01111111|11111111|11111111|11111111, tj. do 19. ledna 2038 03:14:07 UTC.
19. 1. 2038 03:14:07 UTC – konec doby unixové?
Pokud by se v současných systémech nic nezměnilo, tak by se 19. ledna 2038 v 03:14:08 unixové hodiny, a tím pádem i všechny aplikace tyto hodiny využívající, zbláznily. Na hodinách by se zobrazilo číslo –2147483648, tj. 10000000|00000000|00000000|00000000, tj. 13. prosince 1901 20:45:52.
Jak zabránit katastrofě?
Řešení je „jednoduché“. K uložení času stačí použít více bitů. V hlavičkovém souboru postačí změnit definici time_t z 32 bitů na 64 bitů a programy opětovně přeložit. Pokud ale programátor místo time_t natvrdo použil signed int nebo signed long, přeložení programu nepomůže, je nutné do něj sáhnout a příslušné deklarace změnit. Řešením by mohl být přechod na 64bitovou architekturu. Opět je ale nutné programy přeložit. K tomu jsou však nezbytné jejich zdrojové kódy. Myslíte si, že když se v roce 2038 zblázní nějaký třicet let spolehlivě fungující systém, že se programátorům povede nalézt třicet let staré zdrojové kódy? Nejenom Linux se dostává také do nepočítačů, tj. například do různých jednoúčelových zařízení, majících docela velkou šanci dožít se roku 2038. Pokud ráno 19. ledna 2038 zjistíte, že se nezapnulo automatické topení, bude to možná tím, že „topič“ má ještě půlnoc. Jeho hodiny se zbláznily, ukazují o šest a půl hodiny míň. To, že jsou pozadu o 137 let, není na displeji vidět. Z hlediska topení se jedná o nepodstatnou informaci.
Je váš systém připraven na Y2.038K?
Z www.2038.org lze stáhnout primitivní program napsaný v perlu, jímž lze jednoduše základní Y2.038K kompatibilitu systému otestovat.
Slavit lze i podle unixových hodin
Pokud vám k nalezení důvodu oslavy nepostačuje klasický kalendář, zkuste využít unixových hodin.
9. 9. 2001 01:46:40 UTC
V neděli 9. září 2001 v 01:46:40 ukazovaly unixové hodiny přesně 1000000000 sekund, tj. jednu miliardu sekund. O jednu nulu míň, tj. sto milionů sekund, ukazovaly 3. března 1973 v 09:46:40.
10. 1. 2004 13:37:04 UCT
V sobotu 10. 1. 2004 ve 13:37:04 UTC uběhlo od 1. 1. 1970 00:00:00 přesně 1 073 741 824 sekund. V desítkové soustavě toto číslo nevypadá nikterak zajímavě. Mnohem zajímavější je to v soustavě dvojkové. Číslo 01000000|00000000|00000000|00000000, tj. 230, tj. jednička a třicet nul, bylo opravdu skvělým důvodem k oslavě. Do tohoto přelomového okamžiku stačilo pro uložení aktuálního času 30 bitů. Od tohoto okamžiku jich musí být 31.
Kde je login?
Uživatelé Source Mage GNU/Linux přihlašující se k systému ve znakovém módu po 230 sekundách od 1. 1. 1970, tj. například v sobotu 10. ledna 2004 odpoledne, byli nemile překvapeni. K systému se nemohli vůbec přihlásit. Místo přihlašovací výzvy „login: " bylo na obrazovce zobrazeno pouze několik divných hlášení ‚init: respawning: "tty1“ too fast: quenching entry‘.
Simpleinit-MSB
Jednalo se o chybu initu Simpleinit-MSB v části zabezpečující opětovné spouštění procesů (respawn). Simpleinit-MSB je inicializační model založený na initu Simpleinit. Jeho autor, Matthias Benkmann, přidal do Simpleinit několik, správcem Simpleinit odmítaných, vlastností.
getty ⇒ login ⇒ bash
Init si při spouštění procesů, jež mají neustále běžet, zapamatuje jejich čísla (PID). Průběžně pak sleduje, zda procesy s těmito čísly pořád běží. Pokud některý z nich neběží, je initem opětovně spuštěn. Tato vlastnost je využívána u procesů getty. Init spustí getty (obvykle šestkrát) zobrazující na konsole „login:“. Po zadání přihlašovacího jména se proces getty změní na proces login (voláním jádra exec()), který po uživateli požaduje heslo. Po správném jméně a hesle se proces login dále změní na proces bash. Všechny tři procesy (getty, login, bash) mají pořád stejné číslo. Po odhlášení uživatele, tj. po ukončení shellu, je proces s tímto číslem ukončen. Poté, co to init zjistí, je proces getty opětovně spuštěn.
Nový proces getty není obvykle spuštěn dříve než několik sekund po spuštění předchozího procesu getty. Cílem je zpomalit případného útočníka zkoušejícího hesla. Chyba v Simpleinit-MSB způsobila, že už první getty byl považován za příliš rychlý. Žádný getty proto spuštěn nebyl.
Jaká chyba? Vždyť vše krásně funguje.
Mnoho uživatelů Source Mage tuto závažnou chybu vůbec nezaregistrovalo. Činnost systémů nabíhajících přímo do grafického módu nebyla chybou ovlivněna. Vzdálený přístup k systémům (ssh, telnet) i všechny síťové služby (apache, postfix, samba) také bezchybně fungovaly.
Oprava chyby z hlediska vývojářů, podpora uživatelů
Chybu Simpleinit-MSB opravil Source Mage Net Guru jedním řádkem v spellu. Místo signed long byla použita proměnná signed long long. Source Mage Video Guru přidal tuto „záplatu“ do grimoire už 10. ledna 2004 v 15:06 UTC.
V 15:37 byla zpráva o chybě i s příslušnou záplatou zaslána do diskusního listu SM-Users. Na webových stránkách Source Mage se řešení problému objevilo v 15:56.
V neděli 11. ledna v 06:53 byla do diskusního listu zaslána informaceo nové verzi Simpleinit-MSB. Simpleinit-MSB verze 1.2 byl do grimoire přidán v 13:42 téhož dne.
Oprava chyby z hlediska uživatelů
Řešení problému bylo jednoduché. Stačilo aktualizovat grimoire a spustit cast -c simpleinit-msb. Jak ale aktualizovat grimoire nebo spouštět příkazy, když se do systému nelze přihlásit?
Místo initu shell
Jak je vidět, nejenom při testování různých initů se hodí, že při zavádění lze linuxovému jádru předat cestu k jinému initu. Jako init lze použít také shell (init=/bin/sh) a tím vlastní init i celou spouštěcí sekvenci zcela obejít a získat přístup k shellu. Pak už stačí pouze ručně připojit disky, spustit síť, aktualizovat grimoire a vykouzlit nový Simpleinit-MSB.
Instalační / záchranné CD také nefungovalo
Uživatelé, kteří se rozhodli Source Mage nainstalovat, zjistili, že instalační CD nefunguje, protože nefungoval na něm umístěný Simpleinit-MSB. Možná si někteří o Source Mage pomysleli své, instalační CD vyhodili a začali se rozhlížet po jiné linuxové distribuci. Ti, kteří se nevzdali, nalezli v diskusním listu, v diskusním fóru nebo na irc stručný návod: před vlastní instalací je nutné v SETUPu počítače vrátit čas před 10. leden 2004.
V neděli 11. ledna bylo vydáno aktualizované instalační CD pro PPC a 16. ledna i pro i386 platformu. S novou verzí CD už není nutné zahajovat instalaci úpravou času v hardware počítače. :-))
Přetečení proměnné
Při programování v jazyce C je nutno myslet také na možnosti proměnných. Některé operace prováděné s proměnnou mohou způsobit její přetečení. Když se například číslo 1073741823 uložené v proměnné signed long vynásobí deseti, výsledkem nebude číslo 10737418230, ale pouze 2147483638. Číslo 10737418230 se prostě do signed long nevejde a proměnná přeteče. Správného výsledku by bylo dosaženo, kdyby byla proměnná deklarována například jako signed long long.
1073741823
00|00111111|11111111|11111111|11111111
10737418230
10|01111111|11111111|11111111|11110110
2147483638
00|01111111|11111111|11111111|11110110
Autor Simpleinit-MSB na přetečení proměnné nemyslel a proměnnou signed long obsahující počet sekund právě deseti násobil. Proměnná přetékala už dávno před 10. lednem 2004, shodou okolností to ale nevadilo. Výsledek byl sice zcela chybný, byl ale kladný. Při násobení čísla 1073741824 deseti se však na prvním bitu zleva objeví jednička a z čísla 10737418240 se rázem stane –2147483648. Se zápornou hodnotou nebylo v programu simpleinit.c počítáno.
1073741824
00|01000000|00000000|00000000|00000000
10737418240
10|10000000|00000000|00000000|00000000
–2147483648
00|10000000|00000000|00000000|00000000
Nejenom svobodný software
V sobotu 10. ledna 2004 nepřestal fungovat pouze Simpleinit-MSB. Mnoho uživatelů CAD systému Pro/ENGINEER Wildfire společnosti PTC bylo nuceno přerušit práci, protože Pro/ENGINEER také přestal fungovat. Společnosti PTC si chybu – aktuální čas již brzy překročí „věčnost“ – uvědomila 12. prosince 2003 (Timeout FAQ). Záplaty tak byly k dispozici již před 10. lednem 2004. Dodnes jsou však aktualizovány.