1P by GN⁺ 1달전 | ★ favorite | 댓글 1개
  • 메모리 안전성샌드박싱은 서로 독립적인 보안 개념으로, 두 가지를 모두 갖춰야 강력한 방어 체계를 형성함
  • Fil-C는 C/C++의 메모리 안전 구현체로, Linux 시스템 호출 수준까지 안전성을 보장하며 OpenSSH 같은 시스템 구성요소에서도 사용 가능함
  • OpenSSH의 seccomp-BPF 기반 샌드박스를 Fil-C로 이식하는 과정에서, 스레드 생성 제한과 seccomp 필터 조정이 핵심 과제였음
  • Fil-C 런타임의 백그라운드 스레드 관리를 위해 zlock_runtime_threads() API가 추가되어, 샌드박스 내에서 스레드 동작을 제어함
  • Fil-C는 prctl 호출을 모든 런타임 스레드에 동기화 적용해, no_new_privsseccomp 필터가 전체 프로세스에 일관되게 적용되도록 구현함

메모리 안전성과 샌드박싱의 관계

  • 메모리 안전성과 샌드박싱은 서로 다른 보안 계층으로, 한쪽만으로는 완전한 보호를 제공하지 않음
    • 메모리 안전하지만 샌드박스되지 않은 예: Java 프로그램이 사용자 입력을 통해 파일을 덮어쓸 수 있는 경우
    • 샌드박스되었지만 메모리 안전하지 않은 예: 어셈블리로 작성되어 권한이 제한된 프로그램
  • 실제 샌드박스는 브로커 프로세스와의 통신 허용 등 구조적 허점이 존재
  • 따라서 메모리 안전성과 샌드박싱을 병행하는 것이 최선의 방어 방식임

Fil-C와 OpenSSH 샌드박스의 결합

  • Fil-C는 C/C++의 메모리 안전 구현체로, Linux 시스템 호출 수준에서 안전성을 유지
    • Fil-C 런타임은 init, udevd 같은 저수준 시스템 구성요소에서도 동작 가능
    • OpenSSH는 Fil-C에서 정상적으로 작동하며, seccomp-BPF 샌드박스를 활용함
  • OpenSSH는 Linux에서 다음 도구로 샌드박스를 구성함
    • chroot로 파일시스템 접근 제한
    • sshd 사용자/그룹으로 실행
    • setrlimit으로 파일 열기·프로세스 생성 제한
    • seccomp-BPF 필터로 허용된 시스템 호출만 허용
  • Fil-C는 chroot와 사용자 전환은 기본적으로 지원하지만, setrlimit과 seccomp-BPF는 런타임 동작과 충돌 가능성이 있어 추가 조정 필요

Fil-C 런타임의 스레드 제어

  • Fil-C 런타임은 가비지 컬렉션용 백그라운드 스레드를 사용하며, 필요 시 자동으로 중단·재시작함
  • OpenSSH의 setrlimit 샌드박스는 새 프로세스 생성 금지를 목표로 하므로, 런타임의 스레드 생성이 이를 위반할 수 있음
  • 이를 해결하기 위해 <stdfil.h>zlock_runtime_threads() API를 추가
    • 런타임이 필요한 스레드를 즉시 생성하고, 이후 자동 종료를 비활성화
    • OpenSSH의 ssh_sandbox_child 함수에서 setrlimit 또는 seccomp-BPF 호출 전에 실행

OpenSSH seccomp 필터 조정

  • zlock_runtime_threads() 적용 후 대부분의 샌드박스 기능은 그대로 작동
  • seccomp 필터에서 다음 변경이 이루어짐
    • 위반 시 SECCOMP_RET_KILL_PROCESS로 설정해 Fil-C 백그라운드 스레드도 함께 종료
    • MAP_NORESERVE를 허용 목록에 추가, Fil-C 메모리 할당기 사용 지원
    • sched_yield 호출 허용, Fil-C의 락 구현에서 사용됨
  • Fil-C의 동기화용 futex 호출은 이미 허용되어 추가 변경 불필요

Fil-C의 prctl 구현 방식

  • OpenSSH는 seccomp 필터 설치 시 두 가지 prctl 호출을 사용
    • PR_SET_NO_NEW_PRIVS추가 권한 획득 차단
    • PR_SET_SECCOMP, SECCOMP_MODE_FILTER필터 활성화
  • 문제는 prctl호출 스레드에만 적용된다는 점으로, Fil-C의 다른 런타임 스레드가 필터 없이 남을 위험 존재
  • Fil-C는 이를 방지하기 위해 filc_runtime_threads_handshake() API로 모든 런타임 스레드에 동기화 적용
    • 각 스레드가 동일한 prctl 호출을 수행하도록 보장
    • 여러 사용자 스레드가 존재할 경우 Fil-C 안전성 오류를 발생시켜 보호 강화

결론

  • 메모리 안전성과 샌드박싱의 결합이 가장 강력한 보안 조합
  • Fil-C는 OpenSSH의 seccomp 기반 샌드박스를 완전하게 통합하면서도 보호 수준 저하 없이 메모리 안전성 유지
  • Linux 환경에서 Fil-C를 활용하면, 시스템 수준 보안과 언어 수준 안전성을 동시에 확보 가능
Hacker News 의견들
  • landlock에 대한 언급이 없는지 궁금함

  • C → WASM → C로 이어지는 하이브리드 컴파일 접근법이 있음
    이렇게 하면 OS 상호작용을 완전히 제어하고, WASM처럼 메모리 접근을 샌드박싱하면서도 기술적으로는 여전히 C 코드로 유지됨
    관련 자료는 RLBox에서 볼 수 있음

    • WASM 샌드박스는 프로그램의 정합성(soundness) 을 보장하지 않음
      메모리를 망가뜨릴 수는 있지만, 그 범위가 샌드박스 안으로 제한될 뿐임
      SECCOMP 같은 시스템은 모든 상호작용 정책을 세세히 정의해야 해서 관료적
      반면 Fil-C는 언어와 런타임 자체가 프로그램의 올바른 동작을 보장하려는 접근을 취함
      Fil-C 바이너리는 일반 실행 파일이므로 SECCOMP 같은 샌드박스와 함께 사용할 수도 있음
      Linux가 prctl 인터페이스를 만드는 데 20년이 걸렸으니, WASI에서 비슷한 걸 보려면 10년은 기다려야 할 것 같음
    • RLBox는 샌드박싱 기술이지 메모리 안전성 기술은 아님
      샌드박스 내부에서도 이상한 실행 흐름을 만들 수 있음
  • Fil-C의 저자는 기술적으로 흥미로운 발명을 잘 하지만, 구현 검증이 충분히 이루어졌는지는 걱정됨
    setuid 프로그램을 Fil-C로 컴파일할 수 있다고 했는데, ld.so를 수정한 부분이 위험할 수 있음
    setuid 앱은 환경 변수, 파일 디스크립터, rlimit, 시그널 등에서 매우 방어적으로 작성되어야 함
    이런 부분은 아직 미완성이라 실제 인프라에 쓰기엔 리스크가 있음
    그래도 코드베이스를 Fil-C로 테스트해보면 흥미로운 버그를 발견할 수도 있음

    • 실제로 Fil-C를 깨뜨릴 방법이 있는지 테스트 중
    • 진짜 걱정된다면 직접 실험하고 결과를 공유해야 함
    • 런타임을 투명하게 만들어 감사(auditing) 가 가능하도록 하는 게 목표임
      ld.so 수정은 libc 레이아웃을 가르치는 정도의 작은 변경임
      setuid 관련 getenv 버그도 이미 secure_getenv로 수정했음
      지적한 내용엔 일부 진실과 일부 FUD가 섞여 있음
    • Fil-C 저자가 비판에 비협조적으로 대응하는 태도가 아쉬움
      Fil-C는 데이터 레이스 상황에서 포인터와 capability가 불일치할 수 있음
      이로 인해 메모리 안전성 위반이 발생할 수 있음
      저자는 이를 부정하지만, Java와 비교하는 건 부적절함
      기술은 훌륭하지만, 저자의 태도가 신뢰를 떨어뜨림
  • WASM은 샌드박스이자 실행 환경으로, 사용 방식에 따라 메모리 안전성을 어느 정도 확보할 수 있음
    C를 WASM으로 컴파일하면 버그는 여전히 존재하지만, 그 영향 범위가 제한됨
    따라서 WASM을 샌드박싱 기술로 분류하는 건 맞지만, 실행 환경으로서 더 많은 가능성이 있음

    • WASM은 결국 샌드박싱 기술
      모듈 B의 버그로 모듈 A의 데이터를 읽을 수 있음
      즉, WASM은 가벼운 프로세스 샌드박스 대체재에 불과함
    • “사용 방식에 따라 다르다”는 말 자체가 WASM이 완전히 안전하지 않다는 증거임
      C도 “사용 방식에 따라 안전하다”고 말할 수 있으니까
    • WASM은 C의 메모리 모델을 이해하지 못하므로, Fil-C처럼 보호 기능을 구현할 수 없음
      WASM은 런타임 탈출은 막지만, 내부 프로그램의 메모리 탈출은 막지 못함
  • Fil-C와 Rust 비교를 요청함

    • 두 기술 모두 훌륭하지만 접근 방식이 다름
      Fil-C는 기존 C 프로그램을 호환성과 보안 중심으로 강화하는 데 적합함
      Rust는 새 코드베이스를 만들 때 정적 안전성성능을 확보하기 좋음
      Fil-C는 약간의 성능 손실이 있지만 기존 C 코드(ffmpeg, nginx, sudo 등)에 유용함
      Rust는 멀티스레딩과 타입 시스템이 강점임
    • Fil-C는 GC를 도입해 성능 저하가 있을 수 있음
      언어 설계 개선보다는 메모리 안전성 확보가 목적임
      경쟁군은 Rust보다는 D, Nim, Go에 가까움
    • Fil-C는 런타임 검사로 안전하지 않은 메모리 접근을 감지하면 프로그램을 중단시킴
      Rust는 컴파일 타임에 예방
      두 접근은 직교적이며, Rust에도 Fil-C 스타일의 런타임 검사를 추가할 수 있음
  • MicroVM이 점점 인기를 얻고 있음
    Fil-C가 이를 어떻게 활용할 수 있을지 궁금함

    • 약간의 포팅이 필요하겠지만, microVM의 일부 기능을 Fil-C의 메모리 안전한 유저랜드로 끌어올릴 수도 있음
  • 이 프로젝트가 더 주목받길 바람
    sudo나 polkit 같은 핵심 도구가 메모리 안전하게 배포되면 좋겠음

  • 메모리 안전 언어에서도 샌드박싱 활용이 더 많아졌으면 함
    Rust나 Go에서도 OS 수준의 샌드박스를 잘 안 쓰는 게 아쉬움

    • Seccomp는 이식성과 조합성이 떨어짐
      라이브러리 단위로 설정하기 어렵고, 커널 버전이나 libc 구현에 민감함
      파일 경로 같은 포인터 뒤의 입력은 필터링할 수 없어 한계가 있음
      그래서 보통 애플리케이션 단위로 직접 설정해야 함
    • Rust는 런타임이 거의 없어서 샌드박싱에 적합함
      반면 Go는 런타임이 커서 Fil-C처럼 안전하게 만들기 어려움
  • Fil-C가 clang의 Address Sanitizer(ASan) 와 뭐가 다른지 궁금함
    단순히 런타임 패닉을 내는 수준이라면 “메모리 안전”이라 부르기 어렵지 않나 함

    • ASan은 버그를 잘 잡지만 완전한 메모리 안전성을 보장하지 않음
      일부 버그는 탐지하지 못함
      메모리 주변에 “red zone”을 두는 방식이라 운이 좋으면 탐지됨
    • 메모리 오류가 영향을 주기 전에 패닉으로 막힌다면, 그것도 메모리 안전으로 볼 수 있음
      메모리 안전은 “크래시하지 않는다”가 아니라 “잘못된 접근이 효과를 내지 못한다”는 의미임
  • 완전한 VM을 샌드박스로 쓰면 안 되는 이유를 질문함

    • VM은 훌륭한 샌드박스지만, Chrome이나 OpenSSH 같은 앱은 권한 분리가 필요함
      하나의 프로세스는 권한 없이 입력을 파싱하고, 다른 프로세스는 높은 권한으로 동작함
      두 프로세스는 IPC로 통신함
      VM을 쓰면 보안은 높지만 오버헤드가 크고, GPU나 파일 접근 같은 기능이 복잡해짐
      그래서 일반적으로는 OS 수준의 샌드박싱이 더 깔끔함
    • VM은 대부분의 문제를 해결하지만, 데스크톱 그래픽 가속은 여전히 어려움
      GPU를 전용으로 할당해야 하고, Qubes도 X11 포워딩으로만 연결되어 가속이 없음