天天看點

glibc在預設情況下并未妥善解決Y2038問題

由于 Y2038 問題, Linux Kernel 早在幾年前就已經切換到 64 位 time_t,而且發行版 Alpine 3.13 時也跳到了 64 位 time_t。不過近日,Alpine 安全團隊主管 Ariadne Conill 發文表示 GNU libc 2.34 在支援 64 位 time_t 上存在缺陷,可能在過渡過程中産生障礙。

glibc在預設情況下并未妥善解決Y2038問題

Alpine 安全團隊主管 Ariadne Conill,圖檔來自于 Twitter

如果你密切關注 Linux 領域的發展和動向,肯定了解 2038 年錯誤(Year2038 bug)。這個問題之是以會存在,是由于到了 2038 年 1 月 19 日那天,可以用 Unix 帶符号的 32 位整數時間格式表示的最新時間是 03:14:07 UTC。

可以用 Unix 帶符号的 32 位整數時間格式來表示的最新時間是 2038 年 1 月 19 日 03:14:07 UTC,這是 1970 年 1 月 1 日之後過了 2147483647 秒。過了那個時間後,由于整數溢出,時間值将作為負數來存儲,系統會将日期讀為 1901 年 12 月 13 日,而不是 2038 年 1 月 19 日。

Alpine 作業系統是一個面向安全的輕型 Linux 發行版。它不同于通常 Linux 發行版,Alpine 采用了 musl libc 和 busybox 以減小系統的體積和運作時資源消耗,但功能上比 busybox 又完善的多,是以得到開源社群越來越多的青睐。

在博文中,Conill 表示在 Alpine 使用的 musl C 庫以及許多其他 UNIX C 庫實作中,time_t 在新代碼中總是 64 位的,并且為需要舊的 32 位函數的代碼提供了相容性存根(compatibility stubs)。當代碼随着時間的推移被重建時,它将自動成為符合 Y2038 标準的代碼,而無需任何努力。

微軟在 msvcrt 中又前進了一步:你預設得到 64 位的 time_t,但如果你在編譯時定義了 _USE_32BIT_TIME_T 宏,你仍然可以通路舊的 32 位函數。需要注意的是,上面描述的兩種方法都引入了零摩擦,以獲得正确的東西。

GNU 項目為過渡到新的 ABI 所采取的方法正好相反:你必須明确要求新的功能,否則你将永遠得不到它。這種方法為将來改變預設值留下了可能性,但到目前為止,他們從未這樣做過。

這可以從大檔案支援擴充中觀察到,需要處理大于 2GiB 的檔案,你必須總是用 -D_FILE_OFFSET_BITS=64 來建構你的代碼。同樣,如果你在一個 32 位系統上,而你沒有用 -D_TIME_BITS=64 來建構你的應用程式,它将不會使用符合 Y2038 的 ABI 來建構。

這是最糟糕的方式。考慮一下庫:如果一個依賴關系是用 -D_TIME_BITS=64 建構的,而另一個依賴關系沒有,并且它們需要互相交換結構 timespec 或類似的東西,怎麼辦?那麼,在這種情況下,你的程式很可能會崩潰或出現奇怪的行為,因為你在編譯的程式中沒有持續使用相同的結構 timespec。

幸運的是,如果你的目标是32位系統,而且你想處理大于2GiB的檔案,或者有信心你的代碼在2038年還能繼續工作,有一些Linux發行版是建立在Musl之上的,比如Alpine,這将使你不必處理GNU libc的特殊性

繼續閱讀