2P by GN⁺ | ★ favorite | 댓글 1개
  • GhostLock(CVE-2026-43499) 은 Linux 2.6.39에 도입돼 7.1에서 수정된 커널 취약점으로, 비특권 로컬 공격자가 일반적인 스레딩 시스템 호출만으로 스택 UAF를 일으켜 루트 권한 획득과 컨테이너 탈출에 이용할 수 있음
  • Requeue-PI 프록시 경로의 remove_waiter()가 실제 대기 태스크 대신 currentpi_blocked_on을 지워, 사용자 공간으로 복귀한 태스크에 해제된 스택 프레임을 가리키는 포인터가 남음
  • 세 futex와 세 스레드로 PI 의존성 순환을 만들어 -EDEADLK 롤백을 유도하고, PR_SET_MM_MAP의 제어 가능한 스택 버퍼에 가짜 rt_mutex_waiter를 구성해 제약된 포인터 쓰기를 확보함
  • 익스플로잇은 prefetch로 KASLR·physmap 기준 주소를 찾고 CPU entry area(CEA)에 가짜 구조체와 ROP 스택을 배치한 뒤, inet6_protos[IPPROTO_UDP]를 덮어 IPv6 UDP 루프백 패킷으로 제어 흐름을 탈취
  • 연구진은 97% 안정적인 권한 상승·컨테이너 탈출 익스플로잇으로 Google kernelCTF에서 $92,337을 받았으며, 패치되지 않은 모든 Linux 배포판은 최신 LTS로 업그레이드해야 함

영향 범위와 취약점 개요

  • GhostLock은 VEGA가 발견한 Linux 커널 취약점으로, 별도 권한이나 사용자 네임스페이스 없이 로컬 비특권 사용자가 트리거할 수 있음
  • 8161239a8bcc의 rtmutex 재작업으로 도입됐으며, 영향 범위는 v2.6.39-rc1부터 v7.1-rc1까지
  • 2026년 4월 3bfdc63936dd에서 수정됐고, 필요한 커널 설정은 CONFIG_FUTEX_PI=y뿐임
  • 공격자는 다음 과정을 거쳐 권한을 상승시킬 수 있음
    • 일반적인 스레딩 시스템 호출만으로 커널 스택 메모리를 가리키는 댕글링 커널 포인터를 얻음
    • 거의 임의의 주소에 포인터 또는 8바이트 0을 쓸 수 있는 제약된 프리미티브를 만듦
    • 함수 테이블을 탈취해 제어 흐름을 장악하고 루트 권한을 획득함
  • 패치되지 않은 모든 Linux 배포판이 영향을 받으므로 최신 LTS 버전으로 업그레이드해야 함

remove_waiter()가 잘못된 태스크를 정리하는 원인

  • kernel/locking/rtmutex.cremove_waiter()는 원래 블록된 스레드가 자신의 대기 상태를 직접 정리하는 경로를 위해 작성됨
  • 정상적인 느린 경로에서는 실행 중인 current가 waiter의 소유 태스크이므로 current->pi_blocked_on을 지우는 동작이 올바름
  • Requeue-PI 프록시 경로에서는 rt_mutex_start_proxy_lock()이 다른 수면 중인 태스크를 대신해 rt_mutex_waiter를 큐에 넣고, 오류가 발생하면 이를 롤백함
    • 이때 currentFUTEX_CMP_REQUEUE_PI를 호출한 requeuer임
    • 실제 waiter는 FUTEX_WAIT_REQUEUE_PI에서 잠든 별도의 태스크임
  • __rt_mutex_start_proxy_lock()-EDEADLK를 반환하면 remove_waiter()는 waiter를 lock에서 제거하면서도 current->pi_blocked_onNULL로 만듦
  • 실제 waiter의 pi_blocked_on은 자신의 커널 스택에 있는 rt_mutex_waiter를 계속 가리키며, waiter가 사용자 공간으로 복귀하면 해당 스택 프레임은 해제된 것으로 간주됨
  • 이후 PI 체인 탐색이 해당 태스크를 통과하는 순간 해제된 스택 객체를 역참조
  • lockdep은 어떤 pi_lock이 잡혔는지만 확인하고 누구의 lock인지는 검사하지 않아 이 오류를 잡지 못함

-EDEADLK 롤백을 만드는 세 futex 순환

  • 오류 경로에 도달하려면 세 futex와 세 스레드로 PI 의존성 순환을 구성함
    • f_pi_chain: waiter가 먼저 잠그는 PI futex
    • f_pi_target: owner가 먼저 잠그고 requeue 대상이 되는 PI futex
    • f_wait: waiter가 FUTEX_WAIT_REQUEUE_PI로 대기하는 일반 futex
  • 트리거 순서는 다음과 같음
    1. waiter가 f_pi_chain을 잠근 뒤 FUTEX_WAIT_REQUEUE_PI(f_wait -> f_pi_target)에서 블록되고, rt_mutex_waiter가 자신의 커널 스택에 놓임
    2. owner가 f_pi_target을 잠근 뒤 waiter가 보유한 f_pi_chain에서 블록됨
    3. main 스레드가 FUTEX_CMP_REQUEUE_PI(f_wait -> f_pi_target)를 호출함
  • 프록시 requeue가 waiter를 f_pi_target에 연결하려 하면 waiter → f_pi_target → owner → f_pi_chain → waiter 순환이 닫힘
  • PI 체인 탐색이 -EDEADLK 를 반환하고 잘못된 롤백을 실행하면서, waiter는 댕글링 pi_blocked_on을 가진 채 깨어남
  • 중요한 조건은 waiter가 아직 스택 객체를 보유할 때 requeuer가 롤백하는 것이며, 순환이 완성된 뒤에는 과정이 자체적으로 진행됨
  • waiter가 사용자 공간으로 돌아오면 더는 시간 압박이 없고, 나중에 언제든 sched_setattr()로 체인 탐색을 일으킬 수 있음
  • 구성에는 세 스레드를 사용하지만 UAF 경쟁 자체는 CPU 코어 하나에서도 트리거 가능

스택 UAF가 제공하는 초기 프리미티브

  • 댕글링 포인터는 이전 FUTEX_WAIT_REQUEUE_PI 프레임에 있던 rt_mutex_waiter를 가리킴
  • 같은 태스크의 동일한 스택 깊이에 제어 가능한 바이트를 다시 배치하면, 커널이 이를 가짜 rt_mutex_waiter로 역참조하게 만들 수 있음
  • 가짜 구조체를 어떻게 배치하느냐에 따라 한 번의 접근으로 두 가지 주요 프리미티브를 얻음
    • 제약 조건이 있는 거의 임의의 주소에 포인터를 쓸 수 있음
    • 제약 조건이 있는 거의 임의의 주소에 8바이트 0을 쓸 수 있음
  • 쓰기 전에 여러 포인터 역참조와 무결성 검사가 수행되지만, 조건을 충족하면 쓰기 이후에도 커널이 충돌하지 않고 정상 복귀함
  • 익스플로잇을 완성하려면 스택 프레임 재사용, 가짜 waiter의 구조 검사 통과, 쓰기 제약을 만족하는 대상 선정이 모두 필요함

PR_SET_MM_MAP으로 해제된 스택 프레임 재사용

  • waiter는 futex 시스템 호출에서 돌아오자마자 prctl(PR_SET_MM, PR_SET_MM_MAP, ...)을 호출함
  • prctl_set_mm_map()은 사용자가 제공한 auxv를 고정 크기 스택 버퍼 unsigned long user_auxv[AT_VECTOR_SIZE]에 복사함
  • 이 버퍼는 해제된 waiter와 비슷한 스택 깊이에 놓이므로, 크고 정렬된 제어 가능 qword 블록이 이전 rt_mutex_waiter 위에 겹침
  • auxv의 중첩 영역은 다음과 같이 구성함
    • tree: 삭제할 때 선택한 자식 포인터 W0_BASE를 트리 루트로 올리는 rb 노드로 만듦
    • task: 체인 탐색의 역참조를 안전하게 통과하도록 &init_task로 설정함
    • lock: 쓰기 대상을 맞추기 위해 &inet6_protos[IPPROTO_UDP] - 8로 지정함
    • wake_state: 0으로 설정함
  • auxv를 memfd에 두고 복사가 페이지 경계를 넘도록 배치한 다음, 형제 스레드가 prctl 실행 중 뒤쪽 페이지에 fallocate(PUNCH_HOLE) 경쟁을 걸어 copy_from_user 시간을 늘림
  • 다른 CPU의 consumer 스레드는 가짜 waiter가 스택에 남아 있는 동안 waiter에 sched_setattr()를 호출해 PI 체인을 탐색함
  • clone, setsockopt, pselect, keyctl처럼 제어 가능한 큰 스택 지역 변수를 사용하는 다른 시스템 호출도 같은 역할을 할 수 있음
  • prctl은 버퍼가 크고 정렬돼 있으며 네임스페이스가 필요하지 않아 선택됐고, 추가 후보는 공개 PoC 코드에 포함돼 있음

rb-tree 삭제로 제약된 포인터 쓰기 만들기

  • 가짜 waiter를 제어해도 즉시 완전한 임의 쓰기가 생기지는 않으며, 체인 탐색은 다음 경로를 실행함
    • task->pi_blocked_on에서 가짜 waiter를 찾음
    • fake waiter->lock에서 가짜 rt_mutex_base를 찾음
    • rt_mutex_dequeue(lock, waiter)lock->waiters에서 rb-tree 삭제를 수행함
  • 자식이 하나뿐인 루트 노드를 삭제하면 해당 자식이 루트 슬롯에 기록되는 성질을 이용함
  • locktarget - 8로 지정하면 주변 데이터가 다음 rt_mutex_base 필드로 해석됨
    • target - 8: 잠기지 않은 상태로 읽혀야 하는 wait_lock
    • target: 덮어쓸 waiters.rb_root.rb_node
    • target + 8: waiters.rb_leftmost
    • target + 16: owner
  • 결과적으로 실행되는 단일 쓰기는 *(uint64_t *)target = W0_BASE
  • 대상 주소는 대략 다음 조건을 만족해야 함
    • target - 0x08의 하위 32비트가 0이어야 함
    • target + 0x08의 64비트 값이 0이어야 함
    • target + 0x10의 owner 포인터에서 하위 플래그를 제외한 값이 0이어야 함
  • 앞쪽 qword가 잠긴 spinlock처럼 보이면 trylock이 실패해 아무것도 쓰지 않고 종료됨
  • 뒤쪽 값이 제어되지 않은 top waiter나 owner를 가리키거나 매핑되지 않은 값이면 커널 패닉이 발생할 수 있음
  • W0_BASE는 비교, 재큐잉, 우선순위 갱신, owner 없는 wakeup이 끝날 때까지 유효해야 하므로 CEA의 direct-map 별칭을 사용함

prefetch 누출과 CPU entry area

  • KASLR·physmap 기준 주소 찾기

    • 특정 주소에 대한 prefetch 실행 시간은 현재 페이지 테이블에 그 주소가 매핑됐는지에 따라 달라짐
    • 비특권 프로세스가 커널 주소 범위의 실행 시간을 측정하면 매핑 위치를 추정할 수 있으며, 세부 원리는 prefetch 논문에 정리돼 있음
    • 기본 Linux 커널 이미지 기준 주소의 엔트로피가 약 9비트여서 반복 측정으로 KASLR 기준 주소를 거의 100% 신뢰도로 복구함
    • 이론상 prefetch가 있고 적절한 KPTI가 없는 CPU가 영향을 받지만, 실질적으로는 KPTI가 꺼진 x86에서 주로 쓰는 기법임
    • kernelCTF 이미지는 KPTI가 꺼져 있으며, KPTI가 켜져 있어도 prefetchEntryBleed를 결합하면 trampoline을 통해 커널 이미지 기준 주소를 복구할 수 있음
  • CEA 주소 무작위화 우회

    • CPU entry area(CEA) 는 진입·예외 처리용 스택과 레지스터 문맥을 보관하는 x86 CPU별 구조체임
    • 비특권 프로그램이 소프트웨어 예외를 일으키면 자체 레지스터 문맥을 CEA 예외 스택의 pt_regs에 기록해 약 120바이트의 연속된 제어 가능 메모리를 만들 수 있음
    • Linux 6.2 이전에는 CEA 가상 주소가 완전히 고정돼 가짜 구조체, 포인터 역참조의 부작용 흡수, ROP 스택 구성에 바로 사용할 수 있었음
    • Project Zero의 Bringing back the stack attack 공개 이후 Linux 6.2부터 CEA 가상 주소가 강하게 무작위화됨
    • 각 CPU의 CEA 가상 주소는 서로 다르게 무작위화되지만 물리 주소는 고정돼 있으므로, physmap 기준 주소를 알면 direct-map 별칭을 계산할 수 있음
    • prefetch, 후보 경계 정규화, 예상 CEA 페이지 검사를 결합해 주변 별칭을 배제하고 cea_direct = physmap_base + CPU1_CEA_BASE를 구함
    • kernelCTF LTS 6.12.80의 3.5GB 부팅 환경에서 관련 오프셋은 0x11c517000(+0x1f58)

CEA를 가짜 waiter와 후속 객체로 재사용

  • 첫 번째 쓰기 전에 CEA의 W0에 자기 일관성을 갖춘 가짜 waiter와 lock을 배치함
    • task&init_task로 설정함
    • prio에는 유효한 값을 넣음
    • lock의 wait_lock은 잠기지 않은 상태로 보이게 만듦
    • owner는 dequeue, 재큐잉, 우선순위 갱신, wakeup을 안전하게 통과하도록 구성함
  • rb-tree 쓰기가 끝나면 W0는 더 이상 waiter일 필요가 없으므로, 덮어쓴 대상이 요구하는 구조체로 CEA를 다시 채울 수 있음
  • CEA는 약 120바이트로 작지만, 계산 가능한 고정 커널 주소에 데이터를 배치할 수 있어 효율적임
  • NPerm과 kernelsnitch 등은 더 넓은 공간에서 같은 역할을 수행할 수 있음
  • 익스플로잇은 하나의 CEA 영역을 가짜 rt_mutex_waiter, 가짜 lock, inet6_protocol, JOP·스택 피벗 슬롯, 최종 ROP 스택으로 순차 또는 동시에 활용함

inet6_protos[IPPROTO_UDP]로 제어 흐름 탈취

  • 일반적인 x86_64 Linux에서는 KASLR 기준 주소를 확보한 뒤, 조건에 맞는 함수 테이블이나 이를 포함한 객체를 덮는 짧은 경로를 선택할 수 있음
  • 쓰기 가능한 데이터 영역의 inet6_protos[IPPROTO_UDP] 주변은 필요한 제약을 자연스럽게 만족함
    • inet6_protos[16] == NULL은 가짜 wait_lock의 잠기지 않은 상태가 됨
    • inet6_protos[17] == &udpv6_protocol은 실제 덮어쓸 대상임
    • inet6_protos[18] == NULL은 가짜 rb_leftmost가 됨
    • inet6_protos[19] == NULL은 가짜 owner가 됨
  • 쓰기가 끝나면 inet6_protos[IPPROTO_UDP]는 CEA 페이지 안의 가짜 inet6_protocol을 가리킴
  • CEA를 다시 분사해 구조체를 다음과 같이 구성함
    • handler: 첫 번째 피벗 가젯으로 지정함
    • err_handler: 사용하지 않음
    • flags: INET6_PROTO_NOPOLICY | INET6_PROTO_FINAL로 설정함
  • ::1connect한 뒤 데이터를 쓰는 IPv6 UDP 루프백 패킷을 보내면 커널이 가짜 handler를 호출해 프로그램 카운터를 제어할 수 있음

짧은 피벗과 DirtyMode 권한 상승

  • Google kernelCTF의 lts-6.12.80 대상에서는 적합한 단일 스택 피벗 가젯을 찾지 못해, 추가 load/call로 CEA 주소를 rbp에 넣은 뒤 mov rsp, rbp; pop rbp; ret로 피벗함
  • ret2usr/proc/%P/fd/x 전체 덮어쓰기는 약 10개 가젯 qword가 필요해 제한된 CEA 공간에 비해 너무 큼
  • 최종 단계에는 한 번의 쓰기로 권한 비트를 바꾸고 나머지 과정을 사용자 공간에서 수행하는 DirtyMode를 사용함
  • 쓰기 대상은 커널 데이터의 coredump_sysctls[1].mode, 즉 core_pattern sysctl의 접근 모드임
  • 커널 이미지와 같은 KASLR 슬라이드를 공유하므로 주소를 계산할 수 있으며, 쓰기 비트인 두 번째 최하위 비트가 설정된 값이면 충분함
  • 짧은 pop reg; mov [reg], reg; ret 체인으로 모드 값을 바꾸고 msleep으로 탈취한 스레드를 안전하게 정지시킴
  • /proc/sys/kernel/core_pattern을 모든 사용자가 쓸 수 있게 되면 비특권 프로세스가 |/proc/%P/fd/666 %P를 기록하고 helper를 충돌시켜, 커널이 공격자의 바이너리를 루트 권한으로 실행하게 함
  • 초기 rb-tree 쓰기는 배치 제약 때문에 coredump_sysctls[1].mode에 직접 도달할 수 없어, 모드 변경은 짧은 ROP 단계에서 수행함

전체 익스플로잇 흐름과 결과

  • 공격은 다음 순서로 진행됨
    1. prefetch로 커널 이미지 슬라이드와 physmap 기준 주소를 누출함
    2. GhostLock으로 waiter의 pi_blocked_on에 댕글링 rt_mutex_waiter를 남김
    3. PR_SET_MM_MAP으로 같은 커널 스택 프레임을 재사용해 가짜 waiter를 만듦
    4. rtmutex rb-tree 삭제를 이용해 inet6_protos[IPPROTO_UDP]에 CEA 포인터를 기록함
    5. CEA에 가짜 inet6_protocol, 피벗 슬롯, ROP 스택을 배치함
    6. IPv6 UDP 루프백 패킷으로 덮어쓴 handler를 호출함
    7. DirtyMode로 core_pattern의 모드 비트를 바꾸고 사용자 공간에서 권한 상승을 마침
  • kernelCTF 원격 환경에서 CEA와 DirtyMode를 조합한 경로는 약 5초 만에 플래그를 획득함
  • 전체 익스플로잇은 CyberMeowfia 프로젝트에 공개돼 있음
  • Android에서는 스택 프레임 재사용과 ASLR·CFI 우회 방식이 달라지며, 별도의 후속 글에서 다룰 예정임

대안 경로와 완화책

  • 더 큰 ROP 공간

    • NPerm 기반 메모리는 제어 흐름을 탈취한 뒤 큰 가짜 스택으로 사용할 수 있음
    • Lukas Maar의 heap-KASLR 누출처럼 더 무거운 경로도 가능하지만, 단계가 추가돼 실행 시간이 늘어남
    • kernelCTF에서는 가장 짧고 신뢰성 높은 체인이 유리하므로 CEA와 DirtyMode 조합을 사용함
  • 커널 패치

    • 최종 패치는 current 대신 waiter->task 를 기준으로 pi_lock을 잡고 pi_blocked_on을 지움
    • remove_waiter()waiter_task = waiter->task를 저장한 뒤 다음 순서로 처리함
      1. waiter_task->pi_lock을 잠금
      2. waiter를 rtmutex 큐에서 제거함
      3. waiter_task->pi_blocked_on = NULL로 설정함
      4. 후속 rt_mutex_adjust_prio_chain()에도 current 대신 waiter_task를 전달함
    • 연구진이 v1 이전에 보낸 별도 수정안은 호출자가 소유 태스크를 명시적으로 전달하도록 구성함
      • 자기 자신이 블록되는 경로에서는 current를 전달함
      • 프록시 롤백에서는 프록시 대상 task를 넘김
      • pi_blocked_on이 여전히 해당 waiter를 가리킬 때만 지우고 태스크의 pi_lock으로 보호함
  • RANDOMIZE_KSTACK_OFFSET

    • 익스플로잇은 해제된 waiter 프레임과 후속 user_auxv 프레임이 결정적으로 겹치는 데 의존함
    • RANDOMIZE_KSTACK_OFFSET를 켜면 스택 오프셋이 달라져 이 단계가 약 1/32 확률의 5비트 추측으로 바뀜
    • 제출된 두 일반 대상에서는 이 설정이 기본적으로 꺼져 있었고, 완화 대상에서는 켜져 있어 해당 익스플로잇 경로를 사용하지 않음
  • STATIC_USERMODE_HELPER

    • STATIC_USERMODE_HELPER는 이 특정 DirtyMode 경로를 차단함
    • 다만 접근 권한을 ctl_table::mode로 제어하고 테이블이 예측 가능한 쓰기 가능 커널 데이터에 있는 다른 /proc/sys 설정으로 같은 방식을 일반화할 수 있음

공개 일정

  • 2026년 4월 18일: 취약점과 초안 패치를 security@kernel.org에 전달함
  • 2026년 4월 20일: 다른 패치로 취약점이 수정됨
  • 2026년 5월 4일: 수정안 v1이 백포트됨
  • 2026년 6월 30일: Google이 kernelCTF 제출을 확인함
  • 2026년 7월 7일: 기술 분석을 공개함
  • VEGA가 발견한 취약점에는 표준 90+30일 공개 정책을 적용함

댓글과 토론

Hacker News 의견들
  • Android 9·13·16과 서로 다른 Firefox 150 미만 버전을 쓰는 기기 3대에서 테스트했는데, 2대는 부팅 반복에 빠져 복구 모드로 들어가야 했고 나머지 1대는 전원이 꺼짐. 데모는 지원되는 Pixel 기기의 배경화면을 바꾸며, 테스트 페이지는 IonStack에서 확인 가능함
    개인 기기에서 블로그나 임의 사이트를 볼 때는 주 브라우저와 별도로 Chromite 같은 Chromium 계열 브라우저를 설치하고, 플래그에서 JavaScript와 자주 공격받는 하드웨어 가속 비디오 디코더를 끈 뒤 깨진 사이트에는 읽기 모드를 쓰는 편이 안전함. 아니면 전용 태블릿을 두는 방법도 있음

    • 현재는 Pixel 10에서만 테스트했지만 다른 기기를 지원하려는 PR이 몇 개 올라오고 있으며, https://github.com/NebuSec/CyberMeowfia에서 확인할 수 있음
    • 커널 익스플로잇을 다른 기기로 이식해 보니, 컴파일러가 커널 빌드마다 스택 프레임을 배치하는 방식에 매우 민감했음. 특정 빌드에 맞는 스탬프 방식과 오프셋을 찾고 나면 상당히 안정적으로 동작함
    • 위험을 감수하고 Samsung S26 Ultra에서 실행했으며, adb를 설치해 확인한 뒤 전체 결과를 밝힐 예정임
      테스트 페이지에 접속하자 Firefox 탭에 출력이 나타나 개념 증명 코드가 실행된 듯했지만, 이후 휴대전화가 멈추고 모든 입력을 거부함. 재시작만 작동했는데 커널이 멈춘 것으로 보이는 상황에서도 어떻게 재시작 이벤트에는 응답할 수 있는지 궁금함. 화면은 실행 결과 일부를 표시한 채 켜져 있다가 화면 보호기가 작동함
    • 아직 루팅할 수 없는 Android 기기들을 루팅하는 데 활용할 수 있다면 대단할 텐데, 가능한 방법이 궁금함
    • Firefox 취약점은 IonMonkey JIT 컴파일러의 타입 혼동인 CVE-2026-10702로 보임: https://www.sentinelone.com/vulnerability-database/cve-2026-10702/
  • 익스플로잇을 발견했을 뿐 아니라 copyfail과 달리 누구나 바로 쓸 수 있는 제로데이 로컬 권한 상승 스크립트를 공개하지 않은 보안 연구자들에게 큰 찬사를 보냄
    Rocky Linux 9에서 몇 시간 동안 로컬 권한 상승(LPE)을 시도했지만 다행히 성공하지 못했음. 시간 여유가 많거나 실력이 매우 뛰어나지 않다면 기업용 배포판에서 실제 공격에 활용하기는 어려워 보임

  • 일반적으로 부트로더를 해제할 수 없는 휴대전화에서도 이 취약점으로 부트로더 잠금 해제가 가능할지 궁금함. 가능하다면 Android 생태계에 일어난 최고의 사건 중 하나가 될 수 있음

  • 제목에 로컬 권한 상승을 뜻하는 LPE를 넣었어야 대부분이 안심하고 주말로 돌아갈 수 있었을 것 같음

    • 그렇게 안심할 일은 아님. 보통 로컬 권한 익스플로잇은 일반 사용자 권한에서 루트 권한으로 올라가는 공격을 뜻하고, 일반 권한 앱도 이미 큰 피해를 줄 수 있어 대개 크게 걱정하지 않음
      하지만 이번 공격은 Firefox의 격리된 브라우저 프로세스처럼 강하게 샌드박스된 프로세스 안에서도 발동 가능함. 공격자는 JavaScript 취약점으로 격리 샌드박스에서 로컬 코드를 실행한 뒤 이번 취약점으로 커널 모드까지 올라가는 두 단계 공격만 연결하면 되므로, Firefox와 Linux 커널을 모두 업데이트해야 함
    • 상위 댓글의 공격은 JavaScript에서 곧바로 루트 권한을 얻는 것처럼 보이지만, 실제로는 서로 다른 익스플로잇 두 개를 연결함
    • 컨테이너 탈출이 가능하다면 여전히 많은 사람에게 영향을 줄 수 있지 않을까 싶음
    • Firefox/IonMonkey의 타입 혼동 취약점도 함께 발견했으므로, 임의 웹사이트에 접속하는 것만으로도 매우 빠르게 기기가 장악될 수 있음
    • 요즘은 이런 상황에 소모하려고 쌓아 둔 제로데이가 수백 개는 있을 것 같음. SSH부터 Node.js까지 몇 주마다 새로운 문제가 나오니, 모든 통신을 WireGuard 뒤에 두는 정도가 아니라면 사실상 전부 원격 취약점처럼 취급해야 할 판임
  • “Google이 kernelCTF 보상으로 92,337달러를 지급했다”는 대목부터 귀가 솔깃해짐

    • 영향 범위를 고려하면 적은 금액처럼 보임. 기업들은 원격 익스플로잇에만 큰돈을 지급하는 것인지 궁금함
  • Android 앱이 NDK로 네이티브 코드를 실행해 루트 권한을 얻을 수 있다는 뜻인지, SELinux가 방어에 도움이 되는지 궁금함

    • 비플래그십 휴대전화는 커널을 비롯한 업데이트를 받기 드물어 실제로 가능할 확률이 높아 보임
      오래된 커널에도 패치를 백포트할 수는 있지만, 스마트폰 업데이트 변경 내역에서 CVE를 명시하는 경우가 드물어 취약점 검사 도구가 사실상 유일한 확인 수단임. Play Store나 외부에서 받은 앱이 침해됐다면 즉시 루트 권한을 얻을 수 있으므로, 설치 시 신뢰와 감사를 확인하는 원칙은 여전히 중요함
      향후 모든 Google Play Integrity 수준에 이 검사가 추가돼 패치되지 않은 휴대전화에는 여러 앱을 설치하지 못하게 될 가능성이 있음. 임의 사이트와 광고를 피하기 어려운 브라우저에서는 샌드박스 탈출이 앱 격리까지 우회하므로 더 심각하며, iOS의 JailbreakMe와 비슷함
    • 커널 자체가 침해되면 SELinux는 방어하지 못함. Android 샌드박스나 Docker 같은 컨테이너 기술도 이 익스플로잇을 막지 못하고, 현실적인 격리 수단은 완전 가상화뿐임. KVM을 쓴다면 지난주 공개된 CVE-2026-53359 패치가 모든 곳에 배포됐다는 전제가 필요함
      지난 15년간 나온 Linux에서 네이티브 코드를 실행할 수 있는 앱이라면 기기에 커널 업데이트가 도착하기 전까지 루트 권한을 얻을 수 있음
  • GhostLock은 Linux 2.6.39에 들어갔고 Linux 7.1에서야 수정됐다는 사실이 충격적임

  • 댓글을 전날 이미 읽은 것 같은데 작성 시각은 모두 10시간 이내로 표시돼 있어 HN의 시간 표시가 잘못된 것인지 궁금함

    • HN의 재노출(re-up) 시스템 때문에 생긴 현상일 가능성이 큼. 이 글을 다시 올리면서 기존 댓글의 타임스탬프가 상대 시간으로 재계산됐으며, 관련 내용은 https://hn.algolia.com/?dateRange=all&page=0&prefix=true&query=by%3Adang%20timestamps%20re-up&sort=byDate&type=comment에서 볼 수 있음
      매일 살펴보는 “underwater” 목록, 즉 추천은 많이 받았지만 어떤 이유로든 첫 화면에 오르지 못한 글의 목록에서 이 글이 최상단이어서 다시 노출했음. 이상하게 보이지만 아직 이보다 덜 혼란스러운 대안이 나오지 않음
    • 비슷한 기사들을 하나로 합치면서 댓글까지 병합하는 경우가 있음