그렉 크로아 하트만 “왜, 리눅스 커널에 러스트인가”
리눅스커널에 러스트 코드를 병합하는 작업은 최근 수년 사이 리눅스 커뮤니티의 뜨거운 논쟁거리였다. 올해 그 마찰이 극단으로 치달아 몇몇 커널 유지관리자가 사임하기도 했다. 러스트를 도입해 리눅스의 안전성과 보안성을 높여야 한다는 입장과, 러스트와 C로 혼재된 코드를 모두 관리하면 관리 복잡성과 작업자 부담이 커진다는 입장으로 극명하게 나뉘고 있다. 현재까지 리누스 토발즈는 러스트 병합을 지지하는 입장이며, 리눅스 커널 안정화 책임자도 러스트를 옹호하는 입장이다.
이런 가운데 리눅스커널의 안정화 버전을 총괄하는 유지관리자 그렉 크로아 하트만 리눅스재단 수석 펠로우는 지난 5일 리눅스재단에서 개최한 ‘오픈소스서밋코리아2025’ 기조연설에서 러스트를 왜 리눅스커널에 사용해야 하는지 설명했다.
그는 “리눅스커널에서 러스트는 코드를 더 쉽게 작성하게 하고, 유지관리자의 검토를 더 쉽게 해주며, 보안성을 개선해준다”고 밝혔다.
그렉 크로아 하트만은 리눅스커널 프로젝트에서 리누스 토발즈 다음으로 중요한 인물이다. 리누스 토발즈가 최신 커널 개발을 총관리한다면, 그렉 크로아 하트만은 리눅스커널에서 보안, 백포팅, 드라이버, 자동화 테스트 인프라 관리 등에 대한 작업을 관리한다. 그는 리눅스 2.6 버전부터 현재까지 모든 리눅스 장기지원(LTS) 릴리스를 책임졌다. 리눅스의 커널 안정화 브랜치 관리의 표준 프로세스를 확립했다.
현재 그는 리눅스커널에 러스트 코드를 병합하는 작업에서 중요한 역할을 하고 있다. 새롭게 병합되는 러스트 코드가 기존 커널의 코드와 공존할 수 있게 만드는 병합 승인자이자 품질·정책 조정자(role of integration gatekeeper) 역할을 맡고 있기 때문이다.
리눅스커널의 러스트 병합(Rust for Linux)은 드라이버, 서브시스템, 메모리 관리 영역 등의 커널 코드를 기존 C 언어 대신 러스트로 작성하게 하는 프로젝트다. 그렉은 드라이버 및 러스트의 트리 병합을 최종 승인하고 있다.
그는 “러스트가 왜 좋은지 이야기 하기 전에 C에 대해 이야기해 보자”며 “현재 커널의 많은 C 언어는 사라지지 않을 것이고, 리눅스는 실제로 세상을 운영하고 있으며 가장 중요한 운영체제이자, 가장 중요한 소프트웨어 프로젝트이므로 프로젝트가 계속되도록 해야 한다”고 말했다.
그는 “리눅스는 큰 커뮤니티이며, 작년 거의 5000명의 개발자가 있었고, 매 릴리스마다 약 350개의 다른 회사가 참여했다”며 “우리는 7만6496개의 변경을 승인하는데, 시간당 8.7개 수준이며, 안정화 트리에서 하루당 40개의 변경이 일어나고, 하루에 13개의 CVE가 등장하며, 새로운 릴리스는 8~9주 단위로 나온다”고 말했다.
그는 “너무 많은 개발자라는 문제를 갖고 있는데, 세계서 가장 큰 소프트웨어 프로젝트이지만 10년 동안 속도가 느려지지 않았다”며 “세상이 멈추지 않았기 때문이라고 말하듯 믿을 수 없을 정도로 빠르게, 우리는 여전히 새로운 하드웨어와 새로운 사용 모델을 위해 오래된 것으로 되돌아가서 리팩토링하기도 한다”고 강조했다.
그는 “그러나 우린 너무 많은 개발자라는 문제를 갖고 있다”고 말해 적은 수의 유지관리자로 대규모 프로젝트를 관리하는 현재의 어려움을 설명했다.

그는 리눅스커널의 C 코드를 제시했다. 블루투스 저전력(BLE) 연결을 설정하는 내용이다. 블루투스 호스트 디바이스 연결 파라미터를 추가하고, 자동 연결 설정이 명시적으로 요청돼 있으면, 자동 연결을 비활성화하며, BLE 디바이스를 스캔해 연결을 시도하는 식이다.
그는 “C로 작성된 실제 커널의 이 코드는 블루투스 스택인데, 버그가 있다”며 “우리는 실제로 P가 무엇을 하고 있는지 보고 있지 않았는데, P가 null을 반환하고 나중에 역참조하는 것 때문에 커널이 충돌했다”고 설명했다.
이 코드는 변환값 P를 검사하지 않고 바로 사용하고 있는 버그를 포함한다. 파라미터 연결에 실패하면 변환값 P가 Null일 수 있고, 자동으로 연결하려 하면 역참조가 발생한다. 에러 처리 없이 이뤄지므로 안정성과 신뢰성이 깨지는 것이다.
그는 “이는 C 코드에서 매우 일반적으로 일어나는 수정으로, 이를 누군가 보고했고 인턴이 수정했다”며 “C 코드를 검토할 때 모든 일의 초기 상태를 기억해야 하고, 뷰 참조 전에 오류 값을 확인하는 사람이 실제로 제대로 잠금해제 했는지 확인해야 한다”고 설명했다.
그는 “검토자는 이런 일을 많이, 계속 진행해야 한다”고 지적했다.

그러면서 수정된 코드를 보였다. 장치 주소와 타입으로 연결 파라미터 구조체(P)를 추가/반환하고, 만약 P가 Null이면 에러코드 -EIO를 설정하고 ‘잠금(unlock)’ 레이어로 가서 정리 후 리턴하게 했다. P가 유효일 때 명시적 연결 모드면 자동연결을 비활성화하고, 아니면 스캔해 기기 연결을 시도하게 한다. 반환값 검사를 추가하지만, 에러를 수동으로 처리하게 한 것이다.
그는 “오류 검사는 제대로 수행됐지만, 오류를 반환하는 대신 잘못된 위치로 이동했다”며 “실제로 다른 것을 다시 정리하기 위해 다른 곳으로 이동해야 한다”고 설명했다.

그는 커널 드라이버의 probe 함수에서 에러 처리 경로를 수정한 패치를 제시했다. 에러가 발생하면 즉시 return err:로 함수가 빠져나가게 하던 걸, 에러 발생 시 공통 정리(cleanup) 경로로 이동하도록 변경한 내용이다.
probe 함수는 장치 초기화 도중 메모리, 등록된 콜백 및 워치, 할당된 구조체, 락 등의 여러 자원을 차례로 할당하게 됐다. 초기화 중 에러 발생 시 이미 할당된 자원을 정리해야 하는데, 그렇지 않으면 메모리 누수나 중복 등록 상태, 나아가 커널 패닉이나 보안 문제까지 이어질 수 있다. 공통 정리 레이블로 가서 이미 할당한 자원을 순차적으로 해제한 다음 함수를 반환시키게 해 안전성을 강화한 것이다.
그는 “C의 지정된 락과 할당은 코드의 크기를 줄이고 자동으로 작동하기에 좋다”며 “코딩을 더 간단하게 만들고, 검토도 더 쉬워진다”고 말했다.
그는 “C의 새로운 버전에 자동 변수 같은 자동 잠금 해제란 게 있는데, 상태를 유지하는 대신 ‘이 코드 아래를 보호하라’라고 지정하면 된다”며 “그럼 코드가 반환될 때 해당 코드가 제대로 정리되는 좋은 방법”이라고 덧붙였다.

이같은 예들은 C 언어를 이용하더라도 보안 위협을 해결하거나 잠금 해제, 자원 관리 등을 효과적으로 처리하게 할 수 있다는 걸 보여준다. 그러나 문제는 이같은 여러 작업이 수동으로 처리되고, 수시로 리팩토링돼야 하다보니 적은 수의 코드 리뷰어(혹은 유지관리자)의 업무가 과중된다는 점이다.
그는 “C의 새 기능도 코딩을 더 간단하게 만들고, 검토하기 더 쉽게 한다”며 “그러나 커널의 주요 병목 현상은 리뷰 담당자”라고 말했다.

그는 이어 맨 처음 제시했던 BLE 관련 C 코드를 러스트로 리팩토링한 것을 보였다. 기존 코드와 거의 동일하지만, 러스트의 에러 전파 연산자인 물음표가 추가됐다. 이에 따라 파라미터 호출 결과가 성공이면 값을 반환하고, 실패하면 현재 함수에서 즉시 반환하게 됐다.
그는 “러스트를 사용하면 쉽게 코드로 표현할 수 있으며, 코드가 잘못되면 컴파일되지 않는다”며 “러스트로 작성되고 제대로 컴파일된다면 당신은 논리를 올바르게 수행했다는 것이며, 그러면 검토 시간이 절약되고 작업이 더 쉬워진다”고 말했다.
그는 “컴파일러와 코드 자체에서 패턴을 적용하면 에러 값 체크, 적절한 락 관리, 리소스 등의 작업이 더 쉬워진다”고 덧붙였다.
그는 러스트의 장점이 보안성과 코드 작성의 용이성이라고 강조했다.
그는 “나는 모든 보안 문제의 약 60%가 커널에 있다고 하는데, 어떤 사람은 내가 틀렸다며 80%는 된다고 한다”며 “만약 우리가 이런 걸 단순화한다면 수많은 보안 버그가 즉시 사라질 것”이라고 말했다.
이어 “내가 러스트에 흥분하는 이유”라며 “러스트는 다른 사람이 버그를 받거나 검토자가 유지 관리하기 전에 보안 버그를 줄여준다”고 강조했다.
그는 “나나 리뷰어가 염두에 둬야 하는 상태가 줄어들고, 더 적은 양의 코드를 수행하게 하고, 버그가 적다”며 “리눅스커널은 유지 관리자가 매우 적어서 관리 작업이 어려운 상태”라고 덧붙였다.

그러면서 러스트로 작성된 구조체(struct) 정의와 뮤텍스(mutex)를 이용한 스레드 안전 값 접근을 보여주는 코드 예제를 제시했다. 정수값을 저장하는 구조체를 정하고, 구조체를 뮤텍스로 감싸 동시성을 보장한다. 다음은 뮤텍스로 보호된 값을 읽어 결과로 반환하게 한다. 성공시 값을 반환하거나 실패 시 에러를 반환하게 했다. 이는 러스트의 안전성을 보여주는 코드로 수동으로 락과 언락을 하지 않고 범위를 벗어나면 자동으로 언락되게 한다.
그는 “러스트는 신뢰할 수 없는 데이터의 유효성 검사를 적용하고, 커널로 들어오는 데이터를 신뢰할 수 없음으로 표시할 수 있다”며 “커널에서 논리적으로 해당 데이터에 액세스할 유일한 방법은 검증자를 이용하는 것이며, 유지관리자로서 나는 이 훌륭한 검증자가 어디 있는 지 알 수 있다”고 설명했다.
그는 러스트의 장점으로 코드 리뷰를 더 쉽게 한다고 강조했다. 보안 이슈가 코드 리뷰 시점에 나타나는 게 아니라, 빌드 시점에 관리돼 문제의 확대를 줄여준다고 했다. 구조화되지 않은 데이터의 검증, 메모리 수명 규칙, 잠금 규칙, 오류 처리, 타입 안전성 등에서 더 집중할 수 있게 해준다고도 밝혔다.
그러면서 “러스트에 대해 모두 메모리 안전성을 말하고 흥미롭긴 하지만, 메모리 안전은 잘못하면 코드가 충돌한다는 의미기도 하다”며 “메모리 안전이 메모리 오류가 전혀 없다는 것을 의미하진 않고, 충돌이 발생할 수 있다는 뜻이며 보안 취약점이 생길 수도 있다”고 지적했다.

그에 따르면, 현재 리눅스커널에 3500만라인의 C코드가 있다. 그리고 러스트 코드는 6만5000라인이다.
그는 “현재 커널에 바인딩이 있는데, 이는 C코드와 러스트 코드의 교차점이며, 플랫폼 드라이버, PCI 드라이버, 메시지 장치 드라이버, 네트워크 카드용 드라이버 등을 위한 것”이라며 “디버거 패스, 잠금, 메모리 관리와 같은 모든 API가 러스트에 있고, 커널과 러스트에서 실제 코드를 작성할 수 있다”고 말했다.
그는 “러스트가 만능은 아니지만 매우 훌륭하며, 레드햇의 엔비디아 GPU 드라이버, Arm의 GPU 드라이버, 퀄컴의 SoC 드라이버 등이 러스트로 제공되고 있다”며 “러스트가 프로그래밍을 재밌게 만든다는 건 사실이고, 러스트는 차분하며 코드가 컴파일되면서 실제로 작동하는 것을 만든다”고 했다.

이어 “사람들은 변화로 가는 길이 어렵다고 불평하지만, 우리는 변하지 않으면 성공할 수 없다”며 “우리는 지금 당장 기존 코드를 새롭게 작성하지 않을 것이고, 새로운 것을 만들 것”이라고 강조했다.
마지막으로 “러스트는 우리로 하여금 C 코드를 재평가하도록 했으며, 사용하기 정말 어려운 API가 잘못됐다는 걸 알게 해서 다시 살펴보가 재작성할 기회를 줬다”며 “러스트는 리눅스 커널에게 여러 API를 재평가하고 다시 작성하며, 수정하고, 보안을 강화하고, 사용하기 쉽게 만들었기에 좋은 것”이라고 덧붙였다.
글. 바이라인네트워크
<김우용 기자>yong2@byline.network


