GN⁺: 64비트 time_t 전환의 위험성
(blogs.gentoo.org)64비트 time_t
로의 전환 위험성
- 32비트
time_t
타입 사용으로 인해 2038년에 32비트 애플리케이션이 오류를 일으킬 가능성이 있음 -
time_t
를 64비트 타입으로 변경하는 것이 해결책으로 제시됨 - Musl은 이미 전환 완료, glibc는 옵션으로 지원, Debian 등 여러 배포판은 전환 완료
- Gentoo와 같은 소스 기반 배포판은 전환이 어려움
Large File Support로 돌아가기
- 32비트 아키텍처는 파일 오프셋을 지정하는
off_t
와 inode 번호를 지정하는ino_t
를 32비트로 사용 - 이로 인해 2 GiB 이상의 파일을 열 수 없고, inode 번호가 32비트 범위를 초과하는 파일을 열 수 없음
- Large File Support 도입으로 이 문제를 해결, glibc에서는 여전히 선택 사항
- time64 지원을 위해 LFS 사용이 필요
어떤 ABI를 사용하는가?
- 세 가지 가능한 서브-ABI:
- 32비트 타입을 사용하는 원래의 ABI
- 64비트
off_t
와ino_t
, 32비트time_t
를 사용하는 LFS - LFS + 64비트
time_t
를 사용하는 time64
- glibc 빌드는 세 가지 변형과 호환 가능하지만, API에서 이러한 타입을 사용하는 라이브러리는 호환되지 않음
왜 ABI 변경이 나쁜가?
- 32비트 타입을 64비트 타입으로 교체하는 것은 호환성을 깨뜨림
- 구조체의 경우,
time_t
가 포함된 구조체는 필드 위치가 변경되어 잘못된 필드를 읽거나 쓸 수 있음 - 함수 매개변수의 경우, 스택에 전달되는 매개변수의 위치가 변경되어 잘못된 매개변수를 읽거나 쓸 수 있음
- 이러한 문제는 런타임 오류와 보안 문제를 야기할 수 있음
어떻게 안전하게 만들 수 있는가?
- 세 가지 아이디어:
- 새로운 ABI를 구분하기 위해 플랫폼 튜플(
CHOST
) 변경 - 새로운 ABI를 위해 libdir 변경
- 서로 다른 서브-ABI를 사용하는 바이너리가 링크되지 않도록 바이너리 수준의 ABI 구분 도입
- 새로운 ABI를 구분하기 위해 플랫폼 튜플(
플랫폼 튜플 변경
- 플랫폼 튜플은 툴체인이 타겟팅하는 플랫폼을 식별
- 새로운 ABI를 도입하기 위해 벤더 필드를 변경하거나 libc 필드에 추가 ABI 명세를 추가
- 예:
i686-gentoo_t64-linux-gnu
,i686-pc-linux-gnut64
libdir 변경
- libdir은 라이브러리 설치 디렉토리의 기본 이름
- time64 변형을 위해 libdir 값을 변경하여 새로운 libdir에 time64 라이브러리를 설치
- 이로 인해 time64 실행 파일이 time32 라이브러리를 링크하지 않도록 방지
- Portage의
preserved-libs
기능을 사용하여 기존 라이브러리를 보존
바이너리 호환성 보장
- 서로 다른 ABI를 사용하는 바이너리를 혼합할 수 없음
- ELF 클래스, 머신 식별자, 플래그 필드 등을 사용하여 호환성 확인
- time32와 time64 시스템을 구분하기 위해 새로운 ELF 노트 섹션 추가 고려
오래된 사전 빌드 애플리케이션
- 오래된 사전 빌드 애플리케이션은 시스템 라이브러리와의 호환성 문제와 y2k38 문제에 직면
- 멀티리브 레이아웃을 사용하여 호환성 문제 해결 가능
- y2k38 문제는 시스템 시간을 조작하거나 VM을 사용하는 방법으로 해결 가능
GN⁺의 정리
- 2038년 이후 32비트
time_t
를 사용하는 애플리케이션이 오류를 일으킬 가능성이 있음 - 64비트
time_t
로 전환이 필요하지만, 이는 ABI 변경을 수반하여 복잡한 문제를 야기함 - 플랫폼 튜플 변경, libdir 변경, 바이너리 호환성 보장을 통해 안전한 전환 경로를 제공할 수 있음
- 오래된 사전 빌드 애플리케이션은 별도의 호환성 문제와 y2k38 문제를 해결해야 함
Hacker News 의견
-
Gentoo는 패키지를 설치하지 않고 빌드하는 옵션이 부족함
- Gentoo는 패키지 빌드와 설치가 한 단계로 이루어짐
- ABI 변경 시 업데이트 중에 시스템이 쉽게 깨질 수 있음
- 64비트
time_t
문제는 널리 알려진 ABI 변경의 예시임
-
.so
버전 관리를 통해 ABI 변경을 처리하는 방법-
.so
파일은 버전 번호를 포함함 - 패키지 자체가 내부적으로 버전 번호를 관리함
- 64비트
time_t
를 지원하려면 상속된 ABI를 제어할 수 있는 추가 구성 요소가 필요함
-
-
Mac OS X에서
off_t
와ino_t
를 처리한 방법- 기존 호출과 구조체는 그대로 유지됨
- 새로운 호출과 타입에
64
접미사가 추가됨 - 빌드 시 컴파일된 바이너리가 실행될 최소 OS 버전을 지정할 수 있음
-
Debian은 64비트
time_t
로 전환하는 데 어려움을 겪었음- 소스 기반 배포판은 더 어려운 전환 과정을 겪음
-
32비트 유닉스 시스템에서
time_t
를 unsigned 32비트로 대체한 경험- 2038년 이후 68년을 더 사용할 수 있게 됨
- 유닉스 에포크 이전의 날짜를 표현할 수 없음
-
FreeBSD에서 amd64 포트를 할 때 64비트
time_t
를 도입한 경험- 32비트 함수 인자가 64비트로 자동 변환됨
- 초기부터 64비트
time_t
를 사용하여 문제를 피함 - tzcode가 64비트 안전하지 않아서 일부 문제를 겪음
-
BSD 매뉴얼 페이지의 "Bugs" 섹션에 있는 농담
- "You can tune a file system, but you can't tune a fish."
-
소스 기반 배포판 대신 Debian 같은 비소스 기반 배포판으로 전환하고 싶다는 의견
-
32비트
time_t
와 64비트time_t
의 구조체 오프셋 차이- 64비트 타입에서는
b
가 64비트 정렬이 필요하여 패딩이 추가됨
- 64비트 타입에서는
-
C에서 타입 별칭이 나중에 변경될 가능성을 제공한다고 생각했지만, 실제로는 그렇지 않음
-
문제를 빨리 해결하는 것이 좋다는 의견
- OpenBSD는 모든 아키텍처에서 64비트
time_t
를 사용함
- OpenBSD는 모든 아키텍처에서 64비트