우분투 26.10이 cp·mv·rm을 Rust로 작성된 uutils 구현으로 전환하면서, 기본 coreutils 세트의 Rust 이행을 100% 마무리했다. 26.04 LTS에서 이 세 명령만 GNU 버전으로 남겨 뒀던 이유였던 TOCTOU(time-of-check to time-of-use) 계열 문제가 업스트림에서 해결된 데 따른 조치다.
사용자가 체감하는 기능 차이는 사실상 없다. uutils는 GNU와의 드롭인 호환을 목표로 하고, 차이가 발견되면 버그로 취급한다. 바뀌는 건 "무엇이 실행되는가"가 아니라 "어떤 언어로 쓰인 코드가 루트 권한으로 파일을 옮기는가"다.
솔직히 말하면 나는 이 전환을 처음 들었을 때 회의적이었다. cp와 rm은 지난 40년간 지구상에서 가장 많이 호출된 프로그램 축에 든다. 잘 돌아가는 걸 왜 다시 쓰나. 그런데 26.04 사이클에서 정확히 그 "잘 돌아가는" 명령들이 TOCTOU 때문에 보류됐다는 사실이, 역설적으로 다시 쓸 이유를 설명해 준다. 오래됐다는 건 안전하다는 뜻이 아니라 오래 검증됐다는 뜻이고, 그 검증이 메모리 안전까지 보장하지는 않는다.
무엇이 바뀌었나
26.04 LTS는 ls·cat·chmod·du 등 대부분을 이미 uutils로 옮긴 상태였지만, 파일을 실제로 이동·삭제하는 cp·mv·rm은 GNU 버전을 유지했다. 이유는 uutils 쪽 구현에서 발견된 TOCTOU 문제들이었다. 파일 상태를 검사한 시점과 실제로 조작하는 시점 사이의 틈을 노려 심볼릭 링크를 바꿔치기하는 고전적인 공격 패턴이다. 업스트림에서 이 문제들이 정리되면서 26.10에서 전환이 마무리됐고, GNU coreutils는 원하면 설치해 쓰는 옵트인 위치로 물러난다.
rm -rf나 cp -r는 디렉터리 트리를 재귀적으로 순회하면서 stat 호출과 실제 조작을 반복한다. 그 사이에 공격자가 경로의 한 구성요소를 심볼릭 링크로 바꾸면, 의도한 대상이 아닌 곳을 지우거나 덮어쓸 수 있다. 그래서 현대 구현은 openat·unlinkat 계열의 디렉터리 fd 기반 API로 경로 재해석 자체를 막는다.호환성 — 진짜 문제는 플래그가 아니라 출력 포맷이다
드롭인 호환을 목표로 한다고 해도, 실무에서 깨지는 지점은 대개 두 곳이다. 첫째는 에러 메시지 문자열, 둘째는 사람이 읽기 좋게 만든 출력 포맷이다. 스크립트가 ls -l의 컬럼 위치나 df의 헤더 문구를 파싱하고 있다면, 구현이 바뀔 때 조용히 오작동한다. 종료 코드와 stdout/stderr 분리 규칙은 대체로 잘 맞지만, 문자열 파싱은 원래부터 취약한 관행이었다.
왜 지금 다시 쓰는가 — 메모리 안전의 비용 편익
C로 쓰인 유틸리티의 취약점 상당수는 버퍼 경계와 수명 관리에서 나온다. Rust는 이 부류를 컴파일 단계에서 잡는다. 그렇다고 Rust가 논리 버그나 경쟁 상태를 없애 주지는 않는다. 실제로 이번에 문제가 됐던 TOCTOU는 메모리 안전성과는 별개의, 설계 차원의 문제였다. 이 구분을 뭉개면 "Rust로 다시 썼으니 안전하다"는 잘못된 안심으로 이어진다.
- 메모리 관련 취약점 클래스의 구조적 제거
- 현대적 테스트·퍼징 인프라 위에서의 유지보수
- 기여자 확보가 쉬운 코드베이스
- 경쟁 상태·TOCTOU 같은 설계 결함
- GNU 확장 플래그의 미세한 동작 차이
- 수십 년치 엣지 케이스 경험의 재축적 기간
서버 운영자 관점에서의 판단
26.10은 9개월 지원의 중간 릴리스다. 프로덕션 서버를 이 버전으로 바로 옮길 팀은 많지 않다. 실질적으로 중요한 시점은 다음 LTS다. 26.10은 그 LTS에 들어갈 결정을 미리 실험하는 무대이고, 지금 피드백을 남기지 않으면 LTS에서 그대로 받게 된다. 사내에 배포 스크립트·백업 파이프라인이 많다면, 이번 사이클에 CI 러너 하나만 26.10으로 바꿔 돌려 보는 것만으로 충분한 예방 접종이 된다.
# 지금 확인해 볼 수 있는 가장 싼 실험
docker run --rm -it ubuntu:26.10 bash -lc '
cp --version | head -1; # uutils 표기 확인
ls --version | head -1;
rm --help | head -5
'
# 내 스크립트가 출력 문자열을 파싱하는지 색출
grep -rnE "(ls|df|du|stat) .*\| *(awk|cut|sed)" ./scripts
출처
- OMG! Ubuntu, "Ubuntu 26.10 completes transition to Rust-based coreutils" (2026-09) — https://www.omgubuntu.co.uk/2026/09/ubuntu-2610-rust-coreutils-complete
- Phoronix, "Ubuntu 26.10 Moves cp, mv & rm Over To Rust Coreutils" — https://www.phoronix.com/news/Ubuntu-Completes-Rust-Coreutils
- heise online, "Ubuntu completes Rust transition" — https://www.heise.de/en/news/Ubuntu-completes-Rust-transition-11456680.html
자주 묻는 질문
우분투 26.10에서 GNU coreutils를 계속 쓸 수 있나요?
쓸 수 있습니다. 기본 세트가 uutils로 바뀐 것이고 GNU 구현은 옵트인으로 남습니다. 필요하면 GNU coreutils 패키지를 설치해 우선순위를 조정하면 됩니다. 다만 기본값이 바뀐 만큼, 새로 만드는 컨테이너 이미지나 신규 서버는 uutils 기준으로 검증해 두는 편이 낫습니다.
cp·mv·rm이 26.04에서는 왜 빠져 있었나요?
uutils 구현에서 TOCTOU(검사 시점과 사용 시점의 불일치) 계열 문제가 발견됐기 때문입니다. 파일 상태를 확인한 뒤 실제로 조작하기 전에 경로가 바뀌면 의도하지 않은 대상이 삭제·복사될 수 있습니다. 업스트림에서 해당 문제들이 수정되면서 26.10에서 전환이 마무리됐습니다.
기존 쉘 스크립트가 깨질 가능성이 있나요?
플래그 호환은 목표 수준으로 맞춰져 있어 대부분 그대로 동작합니다. 위험한 건 출력 문자열을 파싱하는 스크립트입니다. 에러 메시지 문구나 컬럼 정렬에 의존하는 코드는 구현이 바뀔 때 조용히 틀어질 수 있으니, LC_ALL=C 고정과 파싱 제거를 권합니다.
Rust로 다시 썼다고 해서 보안 문제가 사라지나요?
아닙니다. 메모리 안전성 관련 취약점 클래스는 크게 줄지만, 경쟁 상태·권한 검사 누락·논리 오류는 언어와 무관합니다. 이번에 보류 사유였던 TOCTOU 자체가 메모리 안전과 별개인 설계 문제였다는 점이 그 증거입니다.
서버를 26.10으로 올려야 하나요?
26.10은 단기 지원 릴리스라 프로덕션 전면 도입 대상은 아닙니다. 대신 CI 러너나 테스트 컨테이너를 26.10으로 하나 돌려 보면서 다음 LTS에 대비하는 방식을 권합니다. 문제를 지금 발견하면 LTS 전환 때 비용이 훨씬 싸집니다.

댓글 0