Year 2038 problem in the Linux kernel
Solving the Year 2038 problem in the Linux kernel
Year 2038 Problem
Linux에서 시간이 표현되는 방식으로 인해, 부호형 32 비트 숫자는 2038년 1월 19일 03:14:07 이후의 시간을 지원할 수 없다는 문제다.
Y2038, Y2K38, Y2.038K, Unix Millennium Bug 라고도 불린다.
Y2K38의 원인
이 문제는 대부분의 C 프로그램이 time.h 라이브러리를 사용하기 때문에 발생한다.
#include <time.h>
time_t time(time_t *tloc);
이 라이브러리는 시간 값을 저장하기 위한 표준 4 바이트 형식을 설정하고 시간 값을 변환, 표시 및 계산하기위한 여러 기능을 제공한다. 부호형 4 바이트 정수의 최대 값은 2,147,483,647로, 이때 Y2K38 가 발생한다. 부호형 4 바이트 정수가 음수로 롤오버되기 전의 최대 시간 값은 2,147,483,647이며, 이는 GMT 2038년 1월 19일 03:14:07 이다.
이 날에 time.h를 사용하는 모든 C 프로그램은 날짜 계산에 문제가 발생한다. C 프로그램의 높은 이식성으로 인해 임베디드 소프트웨어에서도 많이 사용되기 때문에 Y2K38 문제는 컴퓨터뿐만 아니라 많은 임베디드 시스템에도 영향을 미친다.
Y2K38의 영향
Y2K38 문제로 인해 해당 날짜 또는 그 이전에 일부 컴퓨터 소프트웨어가 실패 할 수 있다. 시스템 시간을 부호형 32비트 정수로 저장하며, POSIX 시간 표기법을 따르는 모든 소프트웨어 및 시스템에 영향을 미친다. ( POSIX 시간 표기법은 시간을 1970년 1월 1일 자정 UTC 이후 경과된 초 시간을 이용하여 표현한다.)
위와 같은 상황에서 표현할 수 있는 최대 시간은 2038년 1월 19일 03:14:07 이다.
이 이후의 시간은 음수로 저장되어 2038년이 아닌 1901년의 날짜로 해석된다. 대부분의 프로그램이 2038년에, 또는 그에 근접한 시기에 영향을 받겠지만, 미래 날짜를 다루는 프로그램은 훨씬 빨리 문제에 부딪칠 것이다. 예를 들어, 20년 뒤의 요일을 계산하는 프로그램은 2038년 보다 20년 전인 2018년 이전에 수정해야 한다.
AOLserver 소프트웨어 문제
2006년 5월에 발생한 AOLserver 소프트웨어의 문제는 최초로 나타난 2038년 문제의 예다. AOL 서버 시스템의 초기 설계에서는 단순히 임의의 시간 초과 날짜를 지정하여 처리했으며, 서버의 기본 구성은 요청이 10억 초 후에 time out이 되도록 지정했다. 하지만 2006년 5월 12일 21:27:28 부터 10억 초 (약 32 년) 이후에는 문제가 되는 날짜를 초과한다. 따라서 time out 계산이 오버플로우되고 과거의 날짜가 반환되어 소프트웨어가 중단되었다.
해결 방안
- 비부호형 32 비트
time_t
부호형 32비트 정수 표현을 비부호형으로 변환할 경우, 최상위 비트를 부호로 표현할 필요가 없다. 따라서 부호형일 때는 최대 2,147,483,647까지 표현 가능한 반면에, 비부호형일 때 최대 4,294,967,295까지 표현이 가능하다.
하지만 time_t
는 날짜와 시간을 저장하는 데만 사용되는 것이 아니라 많은 응용에서 시간/날짜 차이를 저장하는 데에도 사용하기 때문에, 문제가 발생할 수 있으며, 1970년 이전 날짜를 다루는 응용은 수행할 수 없다. 만약 비부호형으로 바꾼다 해도, 이 문제는 2106년 2월 7일 06:23:15 로 지연될 것이다.
- 부호형 64 비트
time_t
64 비트 프로그램에서 time_t
는 날짜와 시간을 기원 후 2,920억까지 나타낼 수 있으며, 이는 현재 예상 우주 나이의 약 20 배다.
2038년의 모든 PC에 64 비트 CPU가 있더라도 하위 호환성으로 인해 이전의 32 비트 프로그램이 많이 실행되며 이로 인해 문제가 발생할 수 있다.
‘잘 작성된 프로그램’은 새로운 버전의 라이브러리로 간단히 재 컴파일 할 수 있다. 이는 전체 시간을 자체적인 시간 type 및 function으로 캡슐화하기 때문에 가능한 것이다. 하지만 임베디드의 경우 이러한 칩을 정확히 찾아내기 매우 어렵고, 발견하더라도 위성 및 기타 많은 우주 장비에서 이러한 칩을 제거하는 것은 비현실적이다.
time_t
데이터 형식의 정의를 64 비트로 변경하면 소프트웨어 및 데이터 저장소의 이진 호환성이 손상될 수 있고. 이진 시간 표현을 처리하는 모든 코드에 영향을 줄 수 있다.
- NetBSD의 해결 방안
NetBSD 6.0 Release (October, 2012)부터 NetBSD는 32 비트 및 64 비트 아키텍처에 모두 64 비트 time_t
를 사용한다. 또한 이진 호환성 계층을 통해 이전 NetBSD Release 로 컴파일 된 응용 프로그램에서 32 비트 time_t
를 지원할 수 있다.
-
리눅스 커널 기반 해결 방안
4.1. Replace unsafe value / structure
32 비트 ABI
time_t
(struct timespec
,struct timeval
과 같은 관련 데이터 구조)를 사용하는 대신, 64 비트인timespec64
,ktime_t
를 사용하도록 변경한다.struct timespec { time_t tv_sec; /* seconds */ long tv_nsec; /* nanosecond */ }; struct timeval { time_t tv_sec; /* seconds */ suseconds_t tv_usec; /* microseconds */ };
timespec
,timeval
구조,time_t
를 사용하여 Y2K38 문제를 겪는다.
typedef __s64 time64_t; struct timespec64 { time64_t tv_sec; /* seconds */ long tv_nsec; /* nanoseconds */ }; union ktime { s64 tv64; }; typedef union ktime ktime_t;
- timespec64, ktime_t 구조, 64-bit signed int형을 사용하여 Y2K38 문제를 해소할 수 있다.
4.2. System call 64-bit
time_t
변환time_t
또는timespec
,timeval
등 파생 데이터 구조를 파라미터로 전달하는 System call (ioctl 제외)이 있는데, 이time_t
를 64 비트로 확장하기 위해선 새로운 System call로 교체하고 이전 버전과의 호환성을 유지해야 한다.따라서 모든 System call을 64 비트로 변경하면서, 호환성을 유지하기 위해 CONFIG_COMPAT_TIME를 도입한다.
CONFIG_COMPAT_TIME은 32 비트 호환 모드를 가진 64 비트 아키텍처와 새로운 System call 을 제공하도록 확장된 모든 32 비트 아키텍처에서 세팅된다.
4.3. Filesystem Timestamps리눅스 파일 시스템인 EXT4는 “extra” 비트를 통해 timestamp를 확장한다. “extra” 32 비트 내에서 하위 2 비트는 32 비트 초 필드를 34 비트로 확장하는데 사용하고 상위 30 비트는 나노 초 timestamp의 정확도를 제공하는 데 사용한다. 때문에 timestamp는 2446년 5월까지 오버플로우 되지 않는다.
하지만, 아래의 함수에서, Y2K38 문제로부터 안전하지 않은 CURRENT_TIME_SEC 의 사용으로 인해 Y2K38 문제를 겪게 된다.
struct timespec ext4_current_time(struct inode *inode) { return (inode->i_sb->s_time_gran < NSEC_PER_SEC) ? current_fs_time(inode->i_sb) : CURRENT_TIME_SEC; }
- 2016년 linux kernel git에는 ext4_current_time()이 삭제되고 current_time()이 대체되었다. [12]
4.4. Use Monotonic clock instead of Wall time
Monotonic clock은 시스템이 부팅할 때 0부터 시작하며 증가하는 반면, Wall clock은 실세계 시간을 나타낸다.
재부팅 없이 시스템이 100 년 동안 유지되지는 않을 것으로 예상하기 때문에, Monotonic clock 를 사용하여 얻은 시간의 실제 범위는 항상 32 비트 값 범위 안에 있다.
32-bit Computer에서의 Y2K38
Y2K38 문제는 32비트 컴퓨터를 사용하는 경우 뿐만 아니라, 시스템 내에서 time 필드가 어떻게 저장되는지에 달려 있다. 32 비트 timestamp와 함께 32 비트 유닉스 시스템을 사용하는 경우, Y2K38의 영향을 받는다.
아래는 32 비트 시스템에서 64 비트 유닉스 timestamp를 사용하는 예제다.
typedef long long time64_t;
time64_t mktime64 (struct tm *t);
struct tm *localtime64_r (const time64_t *t, struct tm *p);
OpenBSD 5.5에서는 32비트 플랫폼에서도 64비트로 시간 값을 처리해서 Y2K38에서 벗어나도록 했다. 하지만 이로 인해 ABI가 바뀌어, OpenBSD 5.4의 실행 파일과 라이브러리를 실행시킬 수 없다. 또한 일부 네트워크 프로토콜, 파일 형식은 내부적으로 32비트로 시간을 저장하는데, 이를 단시일 내에 모두 64비트로 전환할 수 있다는 보장이 없다.
Linux Kernel 5.6에서의 Y2K38
Linux Kernel 5.6 Release 에서는, 모든 time_t의 유저들을 다시 검토하여 커널이 장기적으로 유지 관리 가능한 상태인지 확인하고, time_t에 대한 모든 참조를 안전한 대안으로 대체하여 Y2K38 문제를 해소했다.
Bergmann은 User Space 응용 프로그램은 최신 Linux Kernel System call을 사용해야 하며, GNU C Library 2.32 및 Musl libc 1.2를 사용하여 64 비트 time_t에 대해 User Space를 빌드해야 한다고 발표했다. 다음은 Y2K38 문제 해소를 위한 몇 가지 주의 사항이다.
-
System call 인터페이스를 직접 사용하는 응용 프로그램은 기존 System call 대신, Linux 5.1에 추가된 time64 System call을 사용하도록 포팅해야 한다.
-
Kernel uapi.h의 복사본 또는 그 내용을 사용하는 응용 프로그램, 특히 sound/asound.h, xfs/xfs_fs.h, linux/input.h, linux/elfcore.h, linux/sockios.h, linux/timex.h 및 linux/can/bcm.h 의 경우에는 Linux 5.6 버전으로 업데이트해야 한다.
-
나머지 인터페이스 중 일부는 호환되지 않아, 64 비트 time_t를 전달할 수 없으므로 CLOCK_MONOTONIC 시간 또는 비부호형 32 비트 timestamp를 사용하도록 구성해야 한다.
-
64 비트 시스템에 존재하는 모든 y2K38 문제는 32 비트 시스템에도 똑같이 적용되며. 특히 부호형 32 비트 timestamp가 있는 파일 시스템 (ext4, ext2, xfs, ufs)에 영향을 미친다.
참고문헌
[1] Amit Kumar, “Y2K38”, January 2011
[5] Christopher B. Browne’s Home Page - The 2038 Problem
[6] Jonathan Corbet, 2038 is closer than it seems, May 2014
[7] SZ Lin, y2038 issue, July 2016
[8] [시간
[9] The Open Group Publications Catalog <sys/time.h>
[10] time64.h - include/linux/time64.h - Linux source code (v4.7)
[11] [Y2038] [RFC 03/37] y2038: introduce CONFIG_COMPAT_TIME
[12] The Linux Kernel- ext4 Data Structure and Algorithms 4. Dynamic Structure
[13] ext4: use current_time() for inode timestamps
[14] If I set a 32-bit computer to the year 2038, will it be affected by the Year 2038 bug?
[15] 64 bit unix timestamp conversion
[16] Linux Kernel 5.6 Released! Here are the Main New Features