|
1 | | -###################### |
2 | | -How to Fix Y2K38 Issue |
3 | | -###################### |
| 1 | +########################## |
| 2 | +How to prevent Y2K38 issue |
| 3 | +########################## |
4 | 4 |
|
5 | 5 | ************************ |
6 | | -What is the Y2K38 Issue? |
| 6 | +What is the Y2K38 issue? |
7 | 7 | ************************ |
8 | 8 |
|
9 | | -The Y2K38 issue is a bug which prevents a date from exceeding 03:14:07 UTC on January 19, 2038, on 32-bit systems. This |
10 | | -is because the structures used to store the date experience an integer overflow when the date is set beyond the mentioned |
11 | | -one. This causes the system to crash. |
| 9 | +The Y2K38 issue is a time computing problem that prevents 32-bit systems from representing |
| 10 | +dates beyond 03:14:07 UTC on January 19, 2038. On 32-bit platforms, the UNIX time is stored |
| 11 | +as a signed 32-bit integer (``time_t``) counting seconds since the UNIX epoch |
| 12 | +(00:00:00 UTC on January 1, 1970). This integer overflows at 2,147,483,647 (0x7FFFFFFF), |
| 13 | +wrapping to a large negative value and causing the system to interpret the time as a date in 1901. |
12 | 14 |
|
13 | 15 | For more information, see: https://en.wikipedia.org/wiki/Year_2038_problem |
14 | 16 |
|
15 | | -There are new data structures that are used on 32-bit systems to store date/time in longer fields, thereby avoiding the |
16 | | -overflow and the crash. However, since setting and displaying date/time uses multiple software components (such as the |
17 | | -kernel, glibc etc), **all** code on a filesystem must be Y2K38-compliant (i.e. all code must be using the new data |
18 | | -structures and functions) for the filesystem to be Y2K38-friendly. If any piece of software uses the older structures |
19 | | -and functions, it makes the whole filesystem vulnerable. |
| 17 | +The fix requires updates at every layer of the software stack: kernel, C library (glibc), |
| 18 | +and all userspace applications. If any component lacks Y2K38 support, the entire |
| 19 | +system is vulnerable. |
20 | 20 |
|
21 | | -To understand how the problem was fixed in Scarthgap filesystem, refer: |
22 | | -https://static.sched.com/hosted_files/osseu2024/8b/EOSS%20Vienna%202024%20-%20Surviving%20Y2038.pdf |
| 21 | +******************** |
| 22 | +Y2K38 issue resolved |
| 23 | +******************** |
23 | 24 |
|
24 | | -******************************* |
25 | | -Building a Y2K38-friendly Image |
26 | | -******************************* |
| 25 | +**The current SDK release uses the Scarthgap filesystem, which has the Y2K38 issue resolved.** |
27 | 26 |
|
28 | | -In SDK 9.3, TI's 32-bit platforms are still based on Kirkstone filesystem, which is NOT Y2K38-friendly. The Y2K38 issue |
29 | | -is fixed in OE-core Scarthgap, on which the next release will be based. |
| 27 | +TI's 32-bit platforms (AM335x, AM437x) now use OE-core Scarthgap, which includes all |
| 28 | +necessary fixes applied at every software layer. The filesystem images provided in this SDK |
| 29 | +are Y2K38-compliant by default. |
30 | 30 |
|
31 | | -Until then, if a Y2K38-friendly filesystem is required, obtain a :file:`tisdk-thinlinux-image` from the latest |
32 | | -`cicd.scarthgap.x`: |
| 31 | +How Yocto/OpenEmbedded ensures Y2K38 compliance |
| 32 | +=============================================== |
33 | 33 |
|
34 | | -.. ifconfig:: CONFIG_part_variant in ('AM335X') |
| 34 | +Starting with Yocto Nanbield 4.3 (eventually in Scarthgap 5.0), OE-core builds all packages with |
| 35 | +the following compile-time defines enabled globally: |
35 | 36 |
|
36 | | - https://software-dl.ti.com/cicd-report/linux/index.html?section=platform&platform=am335x |
| 37 | +.. code-block:: c |
37 | 38 |
|
38 | | -.. ifconfig:: CONFIG_part_variant in ('AM437X') |
| 39 | + #define _TIME_BITS 64 |
| 40 | + #define _FILE_OFFSET_BITS 64 |
39 | 41 |
|
40 | | - https://software-dl.ti.com/cicd-report/linux/index.html?section=platform&platform=am437x |
| 42 | +``_TIME_BITS=64`` instructs glibc to use a 64-bit ``time_t`` on 32-bit platforms, making |
| 43 | +all time-related types and functions (``struct timespec``, ``struct timeval``, ``time()``, |
| 44 | +``clock_gettime()``, etc.) Y2K38-safe. ``_FILE_OFFSET_BITS=64`` enables large file support |
| 45 | +(files >2 GB). Yocto enables both flags together to ensure a consistent 64-bit ABI across |
| 46 | +the system. |
41 | 47 |
|
42 | | -The above images are based on the 6.6 Kernel and Scarthgap filesystem, and thus has the Y2K38 issue fixed. |
| 48 | +Since all packages in the distribution are rebuilt with these defines, the entire filesystem |
| 49 | +is consistently Y2K38-safe. |
43 | 50 |
|
44 | | -.. note:: |
45 | | - While the above images are Y2K38-friendly, it must be ensured that even the code introduced to it from other sources |
46 | | - is Y2K38-friendly. Any code that is not Y2K38-friendly will break the Y2K38-compatibility of the filesystem. Thus it |
47 | | - is important to be intentional about writing Y2K38-friendly code, and to test this code to ensure that the final |
48 | | - image remains Y2K38-friendly. |
| 51 | +This approach requires: |
49 | 52 |
|
50 | | -To build a Y2K38-friendly image on the 6.6 Kernel and Scarthgap filesystem baseline, follow the "Build Instructions" |
51 | | -section present in the above link. |
| 53 | +- **glibc 2.34 or later**: introduces support for ``_TIME_BITS=64`` on 32-bit architectures |
| 54 | +- **Linux kernel 5.6 or later**: completes full 64-bit time syscall support |
| 55 | + (``clock_gettime64``, ``clock_settime64``, etc.) required by glibc on 32-bit systems |
| 56 | + |
| 57 | +The Scarthgap filesystem satisfies both requirements (includes glibc 2.39 and kernel 6.6). |
| 58 | + |
| 59 | +Ensuring your code is Y2K38-friendly |
| 60 | +==================================== |
| 61 | + |
| 62 | +While the SDK images are Y2K38-friendly, any code introduced from external sources must also be |
| 63 | +Y2K38-compliant. Code that is not Y2K38-compliant will break the Y2K38-compatibility of the filesystem. |
| 64 | + |
| 65 | +When building applications or libraries to run on the SDK filesystem, ensure the following compile-time |
| 66 | +defines are set: |
| 67 | + |
| 68 | +.. code-block:: c |
| 69 | +
|
| 70 | + #define _TIME_BITS 64 |
| 71 | + #define _FILE_OFFSET_BITS 64 |
| 72 | +
|
| 73 | +Or equivalently, pass these flags to the compiler: |
| 74 | + |
| 75 | +.. code-block:: console |
| 76 | +
|
| 77 | + $ CFLAGS="-D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64" make |
| 78 | +
|
| 79 | +With ``_TIME_BITS=64`` set, standard time functions (``time()``, ``clock_gettime()``, |
| 80 | +``localtime()``, etc.) automatically use 64-bit time internally (no API changes are |
| 81 | +required). However, audit your code for: |
| 82 | + |
| 83 | +- ``time_t`` casts or assignments that assume a 32-bit (4-byte) size |
| 84 | +- Hard-coded UNIX timestamps or future dates as raw integer constants |
| 85 | +- Use of ``sizeof(time_t)`` in serialization/protocol code |
| 86 | + |
| 87 | +****************************** |
| 88 | +How to verify Y2K38 compliance |
| 89 | +****************************** |
| 90 | + |
| 91 | +.. warning:: |
| 92 | + |
| 93 | + Set the date back to the correct value after testing. Running with an incorrect system clock |
| 94 | + can disrupt services such as NTP, certificate validation, and cron jobs. |
| 95 | + |
| 96 | +Check ``sizeof(time_t)`` |
| 97 | +======================== |
| 98 | + |
| 99 | +The quickest way to verify a binary is Y2K38-safe is to check the size of ``time_t`` at |
| 100 | +compile time or runtime: |
| 101 | + |
| 102 | +.. code-block:: c |
| 103 | +
|
| 104 | + #include <stdio.h> |
| 105 | + #include <time.h> |
| 106 | + int main(void) { |
| 107 | + printf("sizeof(time_t): %zu\n", sizeof(time_t)); |
| 108 | + return 0; |
| 109 | + } |
| 110 | +
|
| 111 | +- Compiled **without** ``_TIME_BITS=64``: ``sizeof(time_t)`` = 4 (32-bit, **not Y2K38-safe**) |
| 112 | +- Compiled **with** ``_TIME_BITS=64``: ``sizeof(time_t)`` = 8 (64-bit, **Y2K38-safe**) |
| 113 | + |
| 114 | +Test with a post-2038 date |
| 115 | +========================== |
| 116 | + |
| 117 | +You can also test whether your system handles dates beyond 2038 correctly by temporarily |
| 118 | +setting the system clock past January 19, 2038. |
| 119 | + |
| 120 | +**Test procedure:** |
| 121 | + |
| 122 | +#. Save the current date: |
| 123 | + |
| 124 | + .. code-block:: console |
| 125 | +
|
| 126 | + $ date |
| 127 | + Tue Jan 19 03:00:00 UTC 2038 |
| 128 | +
|
| 129 | +#. Set the clock past the Y2K38 boundary: |
| 130 | + |
| 131 | + .. code-block:: console |
| 132 | +
|
| 133 | + $ date -s "2038-01-20 00:00:00" |
| 134 | +
|
| 135 | +#. Verify the system handles the date correctly: |
| 136 | + |
| 137 | + .. code-block:: console |
| 138 | +
|
| 139 | + $ date |
| 140 | + Wed Jan 20 00:00:00 UTC 2038 |
| 141 | + $ date +%s |
| 142 | + 2147558400 |
| 143 | +
|
| 144 | + On a Y2K38-safe system, ``date +%s`` returns a value greater than ``2147483647`` |
| 145 | + (0x7FFFFFFF) without overflow or sign error. |
| 146 | + |
| 147 | +#. Restore the correct date: |
| 148 | + |
| 149 | + .. code-block:: console |
| 150 | +
|
| 151 | + $ date -s "<correct-date>" |
| 152 | +
|
| 153 | +**On a non-Y2K38-safe system**, setting the date past the boundary may cause: |
| 154 | + |
| 155 | +- ``date`` to report a date in 1901 (signed overflow wraps to negative epoch) |
| 156 | +- System services to crash or behave unexpectedly |
| 157 | +- ``date +%s`` to return a small or negative value |
0 commit comments