
PinTheft(CVE-2026-43494)のGo実装
pintheft の Go 移植版 - RDS zcopy double-free LPE。Dirty Frag 脆弱性クラスに属します。
[!IMPORTANT] Arch Linux は、この脆弱性に対して最も露出しているディストリビューションの一つです。RDS モジュールをデフォルトでロードできる数少ないディストリビューションの一つだからです。
バグは rds_message_zcopy_from_user() にあります。この関数は FOLL_GET を使用してユーザーページを1つずつ GUP ピン留めします。後続のページでページフォールトが発生した場合(例:PROT_NONE ガードページ)、エラーパスは既にピン留めされたページに対して put_page() を呼び出します。その後、rds_message_purge() がそれらに対して再び __free_page() を呼び出します。op_mmp_znotifier は NULL にされたものの、op_nents/sg エントリはそのまま残されているためです。ページがまだ他の参照を持っている場合、__free_page は参照カウントを静かにデクリメントします。失敗する sendmsg ごとに、最初のページからちょうど1つの参照が奪われます。
CONFIG_INIT_ON_ALLOC_DEFAULT_ON の回避io_uring REGISTER_BUFFERS を使用してターゲットページをピン留めします。これにより、FOLL_PIN を通じて GUP_PIN_COUNTING_BIAS(1024)が参照カウントに加算されます。失敗する zcopy 送信で 1024 個のピン参照をすべて奪います。ページの参照カウントは現在 ~1(PTE マッピングのみ)になります。munmap は通常の __folio_put パスをたどり、解放前に mem_cgroup_uncharge(memcg_data をクリア)を呼び出します。bad_page チェックは発動しません。
io_uring は生存性チェックなしで bvec 配列内に生の struct page* を保持します。ページが suid バイナリのページキャッシュとして再利用された後、IORING_OP_READ_FIXED はそのダングリングポインタを通じてペイロードをページに書き込みます。
IORING_REGISTER_CLONE_BUFFERS は imu->refs をインクリメントします。フォークされたデーモンの子プロセスがクローンリングの fd を開いたまま保持します。io_buffer_unmap は refs > 1 を確認して unpin_user_folio をスキップし、解放されたページでの参照カウントの破損を防ぎます。
CPU 0 にピン留めし、解放前に古い PCP エントリを排出します。これにより、ページキャッシュアロケータがページを取得する際、対象ページが先頭に配置されます。
REGISTER_BUFFERS(+1024) -> CLONE_BUFFERS(imu->refs=2) ->
daemon holds clone -> steal 1024 refs -> evict page cache ->
drain PCP -> munmap(free) -> pread(reclaim) ->
READ_FIXED(overwrite) -> verify -> exec -> root
go build -o pintheft-go .
./pintheft-go
成功すると、PTY 経由で root シェルが起動します。ディスク上のバイナリは変更されません。
sudo cp /tmp/.backup_pintheft_<pid> /usr/bin/su && sudo chmod u+s /usr/bin/su
CONFIG_RDS=m、CONFIG_RDS_TCP=m(SO_RDS_TRANSPORT=2 経由で自動ロードされます)CONFIG_IO_URING=y かつ io_uring_disabled=0ちなみに Arch Linux 大好きです :)