Linux|glibc在默认情况下并未妥善解决Y2038问题

由于 Y2038 问题,Linux Kernel 早在几年前就已经切换到 64 位 time_t,而且发行版 Alpine 3.13 时也跳到了 64 位 time_t 。不过近日,Alpine 安全团队主管 Ariadne Conill 发文表示 GNU libc 2.34 在支持 64 位 time_t 上存在缺陷,可能在过渡过程中产生障碍 。
Linux|glibc在默认情况下并未妥善解决Y2038问题
文章图片

Alpine 安全团队主管 Ariadne Conill,图片来自于 Twitter

如果你密切关注 Linux 领域的发展和动向,肯定了解 2038 年错误(Year2038 bug) 。这个问题之所以会存在,是由于到了 2038 年 1 月 19 日那天,可以用 Unix 带符号的 32 位整数时间格式表示的最新时间是 03:14:07 UTC 。
【Linux|glibc在默认情况下并未妥善解决Y2038问题】可以用 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 。

推荐阅读