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的特殊性

TAG: 64Alpine32Linuxtime