diff mbox series

Config.in: introduce BR2_TIME_BITS_64 option for Y2038 compatibility

Message ID 20221012215008.2918444-1-thomas.petazzoni@bootlin.com
State Accepted
Headers show
Series Config.in: introduce BR2_TIME_BITS_64 option for Y2038 compatibility | expand

Commit Message

Thomas Petazzoni Oct. 12, 2022, 9:50 p.m. UTC
Y2038 is now almost only 15 years away, and embedded systems built
today are potentially going to still be operational in 15 years, and
even though they are supposed to receive updates by then, we all know
how things go, and potentially some of these embedded systems will not
receive any update.

In 2038, the signed 32-bit representation of time_t used on 32-bit
architectures will overflow, causing all time-related functions to go
back in time in a surprising way.

The Linux kernel has already been modified to support a 64-bit
representation of time_t on 32-bit architectures, but from a C library
perspective, the situation varies:

 - glibc uses this 64-bit time_t representation on 32-bit systems
   since glibc 2.34, but only if -D_TIME_BITS=64 is
   specified. Therefore, this commit adds an option to add this flag
   globally to the build, when glibc is the C library and the
   architecture is not 64-bit.

 - musl uses unconditionally a 64-bit time_t representation on 32-bit
   systems since musl 1.2.0. So there is nothing to do here since
   Buildroot has been using a musl >= 1.2.0, used since Buildroot
   2020.05. No Buildroot option is needed here.

 - uClibc-ng does not support a 64-bit time_t representation on 32-bit
   systems, so systems using uClibc-ng will not be Y2038 compliant, at
   least for now. No Buildroot option is needed here.

It should be noted that being Y2038-compliant will only work if all
application/library code is correct. For example if an
application/library stores a timestamp in an "int" instead of using
the proper time_t type, then the mechanisms described above will not
fix this, and the application/library will continue to be broken in
terms of Y2038 support.

Possible discussions points about this patch:

 - Should we have an option at all, or should we unconditionally pass
   -D_TIME_BITS=64, like we have been doing for _FILE_OFFSET_BITS=64
   for quite some time. The reasoning for having an option is that
   the mechanism is itself opt-in in glibc, and generally relatively
   new, so it seemed logical for now to make it optional as well in
   Buildroot.

 - Should we show something (a Config.in comment?) in the musl and
   uClibc-ng case to let the user know that the code is Y2038
   compliant (musl) or not Y2038 compliant (uClibc-ng). Or should this
   discussion be part of the Buildroot documentation?

Signed-off-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
---
 Config.in           | 16 ++++++++++++++++
 package/Makefile.in |  3 +++
 2 files changed, 19 insertions(+)

Comments

Robert Hancock Oct. 12, 2022, 11:49 p.m. UTC | #1
On Wed, 2022-10-12 at 23:50 +0200, Thomas Petazzoni via buildroot
wrote:
> Y2038 is now almost only 15 years away, and embedded systems built
> today are potentially going to still be operational in 15 years, and
> even though they are supposed to receive updates by then, we all know
> how things go, and potentially some of these embedded systems will
> not
> receive any update.
> 
> In 2038, the signed 32-bit representation of time_t used on 32-bit
> architectures will overflow, causing all time-related functions to go
> back in time in a surprising way.
> 
> The Linux kernel has already been modified to support a 64-bit
> representation of time_t on 32-bit architectures, but from a C
> library
> perspective, the situation varies:
> 
>  - glibc uses this 64-bit time_t representation on 32-bit systems
>    since glibc 2.34, but only if -D_TIME_BITS=64 is
>    specified. Therefore, this commit adds an option to add this flag
>    globally to the build, when glibc is the C library and the
>    architecture is not 64-bit.
> 
>  - musl uses unconditionally a 64-bit time_t representation on 32-bit
>    systems since musl 1.2.0. So there is nothing to do here since
>    Buildroot has been using a musl >= 1.2.0, used since Buildroot
>    2020.05. No Buildroot option is needed here.
> 
>  - uClibc-ng does not support a 64-bit time_t representation on 32-
> bit
>    systems, so systems using uClibc-ng will not be Y2038 compliant,
> at
>    least for now. No Buildroot option is needed here.
> 
> It should be noted that being Y2038-compliant will only work if all
> application/library code is correct. For example if an
> application/library stores a timestamp in an "int" instead of using
> the proper time_t type, then the mechanisms described above will not
> fix this, and the application/library will continue to be broken in
> terms of Y2038 support.
> 
> Possible discussions points about this patch:
> 
>  - Should we have an option at all, or should we unconditionally pass
>    -D_TIME_BITS=64, like we have been doing for _FILE_OFFSET_BITS=64
>    for quite some time. The reasoning for having an option is that
>    the mechanism is itself opt-in in glibc, and generally relatively
>    new, so it seemed logical for now to make it optional as well in
>    Buildroot.

There's some chance of software being broken by enabling this, with
either a compile or runtime failure. For example, applications that
assume sizeof(time_t) == sizeof(long) would work on 32-bit platforms
with a 32-bit time and 64-bit platforms with a 64-bit time, but fail
with a 64-bit time on 32-bit. I believe I've seen this when trying to
build software with that option, so turning this on unconditionally
might be unwise, unless  some build tests of the supported packages
have been done..

> 
>  - Should we show something (a Config.in comment?) in the musl and
>    uClibc-ng case to let the user know that the code is Y2038
>    compliant (musl) or not Y2038 compliant (uClibc-ng). Or should
> this
>    discussion be part of the Buildroot documentation?
> 
> Signed-off-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
> ---
>  Config.in           | 16 ++++++++++++++++
>  package/Makefile.in |  3 +++
>  2 files changed, 19 insertions(+)
> 
> diff --git a/Config.in b/Config.in
> index 3c57c591a8..46c80fe2f0 100644
> --- a/Config.in
> +++ b/Config.in
> @@ -753,6 +753,22 @@ config BR2_PER_PACKAGE_DIRECTORIES
>  
>  endmenu
>  
> +config BR2_TIME_BITS_64
> +       bool "Build Y2038-ready code"
> +       depends on BR2_TOOLCHAIN_USES_GLIBC && !BR2_ARCH_IS_64
> +       help
> +         This option will pass -D_TIME_BITS=64 in the compiler flags
> +         to ensure the glibc C library uses a 64-bit representation
> +         for time_t and other time types, which ensures that
> +         programs/libraries will correctly handle time past year
> +         2038.
> +
> +         Notes:
> +           - This option only has an effect with glibc >= 2.34.
> +           - The musl C library since its version 1.20 is
> +             unconditionally Y2038 compliant.
> +           - The uClibc-ng library is not Y2038 compliant.
> +
>  comment "Security Hardening Options"
>  
>  config BR2_PIC_PIE_ARCH_SUPPORTS
> diff --git a/package/Makefile.in b/package/Makefile.in
> index 43d214bcbe..59d88bb97e 100644
> --- a/package/Makefile.in
> +++ b/package/Makefile.in
> @@ -163,6 +163,9 @@ TARGET_HARDENED += -D_FORTIFY_SOURCE=2
>  endif
>  
>  TARGET_CPPFLAGS += -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -
> D_FILE_OFFSET_BITS=64
> +ifeq ($(BR2_TIME_BITS_64),y)
> +TARGET_CPPFLAGS += -D_TIME_BITS=64
> +endif
>  TARGET_CFLAGS = $(TARGET_CPPFLAGS) $(TARGET_ABI)
> $(TARGET_OPTIMIZATION) $(TARGET_DEBUGGING) $(TARGET_HARDENED)
>  TARGET_CXXFLAGS = $(TARGET_CFLAGS)
>  TARGET_FCFLAGS = $(TARGET_ABI) $(TARGET_OPTIMIZATION)
> $(TARGET_DEBUGGING)
Peter Korsgaard Oct. 13, 2022, 8:27 a.m. UTC | #2
>>>>> "Thomas" == Thomas Petazzoni <thomas.petazzoni@bootlin.com> writes:

 > Y2038 is now almost only 15 years away, and embedded systems built
 > today are potentially going to still be operational in 15 years, and
 > even though they are supposed to receive updates by then, we all know
 > how things go, and potentially some of these embedded systems will not
 > receive any update.

Thanks for picking this up! This has been on my todo list for a while as well!.


 > In 2038, the signed 32-bit representation of time_t used on 32-bit
 > architectures will overflow, causing all time-related functions to go
 > back in time in a surprising way.

 > The Linux kernel has already been modified to support a 64-bit
 > representation of time_t on 32-bit architectures, but from a C library
 > perspective, the situation varies:

 >  - glibc uses this 64-bit time_t representation on 32-bit systems
 >    since glibc 2.34, but only if -D_TIME_BITS=64 is
 >    specified. Therefore, this commit adds an option to add this flag
 >    globally to the build, when glibc is the C library and the
 >    architecture is not 64-bit.

 >  - musl uses unconditionally a 64-bit time_t representation on 32-bit
 >    systems since musl 1.2.0. So there is nothing to do here since
 >    Buildroot has been using a musl >= 1.2.0, used since Buildroot
 >    2020.05. No Buildroot option is needed here.

 >  - uClibc-ng does not support a 64-bit time_t representation on 32-bit
 >    systems, so systems using uClibc-ng will not be Y2038 compliant, at
 >    least for now. No Buildroot option is needed here.

 > It should be noted that being Y2038-compliant will only work if all
 > application/library code is correct. For example if an
 > application/library stores a timestamp in an "int" instead of using
 > the proper time_t type, then the mechanisms described above will not
 > fix this, and the application/library will continue to be broken in
 > terms of Y2038 support.

 > Possible discussions points about this patch:

 >  - Should we have an option at all, or should we unconditionally pass
 >    -D_TIME_BITS=64, like we have been doing for _FILE_OFFSET_BITS=64
 >    for quite some time. The reasoning for having an option is that
 >    the mechanism is itself opt-in in glibc, and generally relatively
 >    new, so it seemed logical for now to make it optional as well in
 >    Buildroot.

I was hoping we could just do it unconditionally, given that musl does
it already.

Failing that, I would think we could at least make it default y.


 >  - Should we show something (a Config.in comment?) in the musl and
 >    uClibc-ng case to let the user know that the code is Y2038
 >    compliant (musl) or not Y2038 compliant (uClibc-ng). Or should this
 >    discussion be part of the Buildroot documentation?

Having a notice about this in the documentation certainly cannot
harm. I'm not sure it makes sense to have it in Config.in.
Thomas Petazzoni Oct. 13, 2022, 2:39 p.m. UTC | #3
On Wed, 12 Oct 2022 23:49:37 +0000
Robert Hancock <robert.hancock@calian.com> wrote:

> There's some chance of software being broken by enabling this, with
> either a compile or runtime failure. For example, applications that
> assume sizeof(time_t) == sizeof(long) would work on 32-bit platforms
> with a 32-bit time and 64-bit platforms with a 64-bit time, but fail
> with a 64-bit time on 32-bit. I believe I've seen this when trying to
> build software with that option, so turning this on unconditionally
> might be unwise, unless  some build tests of the supported packages
> have been done..

There will definitely be build testing: our autobuilders are testing
24/7 random configurations of Buildroot. So as soon as we introduce
this option, there would be builds with BR2_TIME_BITS_64=y enabled,
which would raise build issues if there's any.

Of course, the more tricky part are runtime issues, which are
essentially impossible to detect until someone runs into the problem.

Best regards,

Thomas
Romain Naour Feb. 6, 2023, 8:25 p.m. UTC | #4
Hello Thomas,

Le 13/10/2022 à 16:39, Thomas Petazzoni via buildroot a écrit :
> On Wed, 12 Oct 2022 23:49:37 +0000
> Robert Hancock <robert.hancock@calian.com> wrote:
> 
>> There's some chance of software being broken by enabling this, with
>> either a compile or runtime failure. For example, applications that
>> assume sizeof(time_t) == sizeof(long) would work on 32-bit platforms
>> with a 32-bit time and 64-bit platforms with a 64-bit time, but fail
>> with a 64-bit time on 32-bit. I believe I've seen this when trying to
>> build software with that option, so turning this on unconditionally
>> might be unwise, unless  some build tests of the supported packages
>> have been done..
> 
> There will definitely be build testing: our autobuilders are testing
> 24/7 random configurations of Buildroot. So as soon as we introduce
> this option, there would be builds with BR2_TIME_BITS_64=y enabled,
> which would raise build issues if there's any.
> 
> Of course, the more tricky part are runtime issues, which are
> essentially impossible to detect until someone runs into the problem.

We already tried to enable BR2_TIME_BITS_64 back in March 2022 but we had to
revert it due to build issues with packages like glibc:

See:
http://lists.busybox.net/pipermail/buildroot/2022-March/638105.html

https://git.buildroot.net/buildroot/commit/?id=dd170f0cbad729dba4193b2b20e3de0a7010d485

I'll try to look again.

Best regards,
Romain


> 
> Best regards,
> 
> Thomas
Romain Naour Feb. 6, 2023, 10:06 p.m. UTC | #5
Le 06/02/2023 à 21:25, Romain Naour a écrit :
> Hello Thomas,
> 
> Le 13/10/2022 à 16:39, Thomas Petazzoni via buildroot a écrit :
>> On Wed, 12 Oct 2022 23:49:37 +0000
>> Robert Hancock <robert.hancock@calian.com> wrote:
>>
>>> There's some chance of software being broken by enabling this, with
>>> either a compile or runtime failure. For example, applications that
>>> assume sizeof(time_t) == sizeof(long) would work on 32-bit platforms
>>> with a 32-bit time and 64-bit platforms with a 64-bit time, but fail
>>> with a 64-bit time on 32-bit. I believe I've seen this when trying to
>>> build software with that option, so turning this on unconditionally
>>> might be unwise, unless  some build tests of the supported packages
>>> have been done..
>>
>> There will definitely be build testing: our autobuilders are testing
>> 24/7 random configurations of Buildroot. So as soon as we introduce
>> this option, there would be builds with BR2_TIME_BITS_64=y enabled,
>> which would raise build issues if there's any.
>>
>> Of course, the more tricky part are runtime issues, which are
>> essentially impossible to detect until someone runs into the problem.
> 
> We already tried to enable BR2_TIME_BITS_64 back in March 2022 but we had to
> revert it due to build issues with packages like glibc:
> 
> See:
> http://lists.busybox.net/pipermail/buildroot/2022-March/638105.html
> 
> https://git.buildroot.net/buildroot/commit/?id=dd170f0cbad729dba4193b2b20e3de0a7010d485
> 
> I'll try to look again.

The issue has been reported to zlib upstream project back in 2019 [1] and a pull
request has been sent by Khem Raj on 2 Jan 2023 [2].

Reading one of the comment about libreELEC project "2038 proof" [3] we can
notice it requires a lot of patches in several packages:

glibc: dont build target with _TIME_BITS or _FILE_OFFSET_BITS for arm…
eventlircd: support -D_TIME_BITS=64 for 64-bit time
lirc: support -D_TIME_BITS=64 for 64-bit time
zlib: support -D_TIME_BITS=64 for 64-bit time
dvb-apps: support-time-bits-64.patch
tslib: support -D_TIME_BITS=64 for 64-bit time
libretro-fbneo: dont build target with _TIME_BITS or _FILE_OFFSET_BIT…
mariadb: dont build target with _TIME_BITS or _FILE_OFFSET_BITS for a…

In the end, enabling -D_FILE_OFFSET_BITS=64 and -D_TIME_BITS=64" onto all
packages has been reverted [4] since it introduced several regression.

After making a lot of effort and spending a lot of time, the libreELEC
maintainer just give up:

"TBH I tink we should not pursue the 32bit userland Y2038 issue further until
glibc comes up with a better solution that doesn't break ABIs.

Moving to 64bit (rather realistic within the next 10 years) or to another libc
(not so much realistic) are all better options than the mess glibc created - it
purely worked for them but pretty much no one else and almost every distribution
abandoned the glibc approach so I think we should do the same."

Thoughts?

[1] https://github.com/madler/zlib/issues/447
[2] https://github.com/madler/zlib/pull/764
[3] https://github.com/LibreELEC/LibreELEC.tv/pull/6727
[4] https://github.com/LibreELEC/LibreELEC.tv/pull/7173

Best regards,
Romain


> 
> Best regards,
> Romain
> 
> 
>>
>> Best regards,
>>
>> Thomas
>
Thomas Petazzoni Oct. 1, 2023, 7:15 p.m. UTC | #6
On Wed, 12 Oct 2022 23:50:08 +0200
Thomas Petazzoni via buildroot <buildroot@buildroot.org> wrote:

> Y2038 is now almost only 15 years away, and embedded systems built
> today are potentially going to still be operational in 15 years, and
> even though they are supposed to receive updates by then, we all know
> how things go, and potentially some of these embedded systems will not
> receive any update.
> 
> In 2038, the signed 32-bit representation of time_t used on 32-bit
> architectures will overflow, causing all time-related functions to go
> back in time in a surprising way.
> 
> The Linux kernel has already been modified to support a 64-bit
> representation of time_t on 32-bit architectures, but from a C library
> perspective, the situation varies:
> 
>  - glibc uses this 64-bit time_t representation on 32-bit systems
>    since glibc 2.34, but only if -D_TIME_BITS=64 is
>    specified. Therefore, this commit adds an option to add this flag
>    globally to the build, when glibc is the C library and the
>    architecture is not 64-bit.
> 
>  - musl uses unconditionally a 64-bit time_t representation on 32-bit
>    systems since musl 1.2.0. So there is nothing to do here since
>    Buildroot has been using a musl >= 1.2.0, used since Buildroot
>    2020.05. No Buildroot option is needed here.
> 
>  - uClibc-ng does not support a 64-bit time_t representation on 32-bit
>    systems, so systems using uClibc-ng will not be Y2038 compliant, at
>    least for now. No Buildroot option is needed here.
> 
> It should be noted that being Y2038-compliant will only work if all
> application/library code is correct. For example if an
> application/library stores a timestamp in an "int" instead of using
> the proper time_t type, then the mechanisms described above will not
> fix this, and the application/library will continue to be broken in
> terms of Y2038 support.
> 
> Possible discussions points about this patch:
> 
>  - Should we have an option at all, or should we unconditionally pass
>    -D_TIME_BITS=64, like we have been doing for _FILE_OFFSET_BITS=64
>    for quite some time. The reasoning for having an option is that
>    the mechanism is itself opt-in in glibc, and generally relatively
>    new, so it seemed logical for now to make it optional as well in
>    Buildroot.
> 
>  - Should we show something (a Config.in comment?) in the musl and
>    uClibc-ng case to let the user know that the code is Y2038
>    compliant (musl) or not Y2038 compliant (uClibc-ng). Or should this
>    discussion be part of the Buildroot documentation?
> 
> Signed-off-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
> ---
>  Config.in           | 16 ++++++++++++++++
>  package/Makefile.in |  3 +++
>  2 files changed, 19 insertions(+)

This was discussed/review during the current hackathon, and in the end
we decided to apply it, so it was pushed to master.

Thomas
diff mbox series

Patch

diff --git a/Config.in b/Config.in
index 3c57c591a8..46c80fe2f0 100644
--- a/Config.in
+++ b/Config.in
@@ -753,6 +753,22 @@  config BR2_PER_PACKAGE_DIRECTORIES
 
 endmenu
 
+config BR2_TIME_BITS_64
+	bool "Build Y2038-ready code"
+	depends on BR2_TOOLCHAIN_USES_GLIBC && !BR2_ARCH_IS_64
+	help
+	  This option will pass -D_TIME_BITS=64 in the compiler flags
+	  to ensure the glibc C library uses a 64-bit representation
+	  for time_t and other time types, which ensures that
+	  programs/libraries will correctly handle time past year
+	  2038.
+
+	  Notes:
+	    - This option only has an effect with glibc >= 2.34.
+	    - The musl C library since its version 1.20 is
+	      unconditionally Y2038 compliant.
+	    - The uClibc-ng library is not Y2038 compliant.
+
 comment "Security Hardening Options"
 
 config BR2_PIC_PIE_ARCH_SUPPORTS
diff --git a/package/Makefile.in b/package/Makefile.in
index 43d214bcbe..59d88bb97e 100644
--- a/package/Makefile.in
+++ b/package/Makefile.in
@@ -163,6 +163,9 @@  TARGET_HARDENED += -D_FORTIFY_SOURCE=2
 endif
 
 TARGET_CPPFLAGS += -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
+ifeq ($(BR2_TIME_BITS_64),y)
+TARGET_CPPFLAGS += -D_TIME_BITS=64
+endif
 TARGET_CFLAGS = $(TARGET_CPPFLAGS) $(TARGET_ABI) $(TARGET_OPTIMIZATION) $(TARGET_DEBUGGING) $(TARGET_HARDENED)
 TARGET_CXXFLAGS = $(TARGET_CFLAGS)
 TARGET_FCFLAGS = $(TARGET_ABI) $(TARGET_OPTIMIZATION) $(TARGET_DEBUGGING)