Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Linux Kernelの1文字のミスで 権限昇格ができた話
Search
rona
March 20, 2026
Programming
2.7k
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Linux Kernelの1文字のミスで 権限昇格ができた話
rona
March 20, 2026
Other Decks in Programming
See All in Programming
リアルな遅延を測る仕様
kota_yata
1
120
ソフトウェアエンジニアにとっての生成AI - 特性を知って使い倒す / generative ai for software enginner
kishida
7
2.1k
TSX の <Hoge<Fuga>> という構文に驚いた話 / tsx-type-argument-syntax
kanaru0928
0
240
レビュー履歴をAIに食わせて、 Compose移行を加速するs
shihochan
0
200
Dockerfile CMD for Node.js
grazie1999
0
120
30年振りにコンパイラの定数整数除算を改善した
herumi
9
4.1k
Pythonの実行はどこまで賢くなったのか? CPythonとPyPyから見る最適化のしくみ
curekoshimizu
3
1.8k
AWS Transform Customによる Spring Boot 2.xから4.xへのVerUp
satoshi256kbyte
2
100
Go を使い始めて 2 ヶ月の学び / My first two months with Go
contour_gara
0
370
夏だ!祭りだ!祭りとはドメインモデリングでは?
ryugen04
0
370
Gmail/Google DriveをトリガーにAIエージェントを動かそう! / Run AI agents with Gmail/Google Drive as triggers!
har1101
2
430
jsmini JavaScript Engine を作ってみた話
yosuke_furukawa
PRO
0
350
Featured
See All Featured
The Organizational Zoo: Understanding Human Behavior Agility Through Metaphoric Constructive Conversations (based on the works of Arthur Shelley, Ph.D)
kimpetersen
PRO
0
420
Stop Working from a Prison Cell
hatefulcrawdad
274
21k
Bioeconomy Workshop: Dr. Julius Ecuru, Opportunities for a Bioeconomy in West Africa
akademiya2063
PRO
1
280
Bridging the Design Gap: How Collaborative Modelling removes blockers to flow between stakeholders and teams @FastFlow conf
baasie
0
660
Beyond borders and beyond the search box: How to win the global "messy middle" with AI-driven SEO
davidcarrasco
3
220
The Director’s Chair: Orchestrating AI for Truly Effective Learning
tmiket
1
280
Breaking role norms: Why Content Design is so much more than writing copy - Taylor Woolridge
uxyall
1
380
Information Architects: The Missing Link in Design Systems
soysaucechin
1
1.1k
技術選定の審美眼(2025年版) / Understanding the Spiral of Technologies 2025 edition
twada
PRO
120
120k
Deep Space Network (abreviated)
tonyrice
0
270
Are puppies a ranking factor?
jonoalderson
2
3.8k
Paper Plane
katiecoart
PRO
2
53k
Transcript
Linux Kernelの1文字のミスで 権限昇格ができた話 rona (@rqda_A) Kernel/VM探検隊@つくば No3 1/53
WHOAMI Rona - 筑波大学 WORD編集部 - 趣味: CTF (pwn) -
好き: kernel空間、猫 2/53
1. Intro - タイトルの「1文字」は 嘘 - ごめんなさい - 1<<5(32)文字に変更させてください 3/53
1. Intro - CVE-2025-37997の話 - パッチは1<<5文字の変更 https://lore.kernel.org/linux-cve-announce/2025052902-CVE-2025-37997-2c6c@gregkh/T/#u 4/53
1. Intro - 以下の環境で一般ユーザーがsudoなしでrootになれる - RedHad Enterprise Linuxのデフォルトインストール - rootless
Docker/podmanが入ったLinux 5/53
Linux Kernelの1<<5文字のミスで 権限昇格ができた話 rona (@rqda_A) Kernel/VM探検隊@つくば No3 6/53
2. Prerequisite - パッチは32文字 - % が / になっていることが大事 https://lore.kernel.org/linux-cve-announce/2025052902-CVE-2025-37997-2c6c@gregkh/T/#u
7/53
2. Prerequisite - IPSetとは? → netfilterサブシステムでIPをまとめて管理する方法 - 利点: 対象ipをiptablesなどのルールをいちいち変えずに編集できる ipset
create blocklist hash:ip ipset add blocklist 192.0.2.68 ipset add blocklist 192.0.2.70 iptables -A INPUT -m set --match-set blocklist src -j DROP ipsetの例 8/53
2. Prerequisite ipset create blocklist hash:ip ipset add blocklist 192.0.2.68
ipset add blocklist 192.0.2.70 iptables -A INPUT -m set --match-set blocklist src -j DROP - IPSetとは? → netfilterサブシステムでIPをまとめて管理する方法 - 利点: 対象ipをiptablesなどのルールをいちいち変えずに編集できる このサブシステムに脆弱性があった ipsetの例 9/53
htable 0 1 2 3 401 402 403 404 region
0 region 1 hbucket used size pos value [] - htableはhash table (入力データのhash を使って bucket を選ぶ table) - hbucketへのポインタを持つ - hbucketは実データを保管するbucket 2. Prerequisite | IPSetの構造 10/53
2. Prerequisite | hbucketの構造 rcu_head rcu u8 size, pos long
used (bitmap) u32 ip ulong timeout u32 skbmark, skbmarkmask hbucket u16 skbprio, skbqueue ... ヘッダー部 データ部 (何個も続く) 11/53
- hbucketに大きくなってほしくないのでhtableをregionに分割 - hashの衝突が多くなってきたらregionを増やして多くのhbucketに分散 - 1regionは0x400個 2. Prerequisite | IPSetの構造
htable 0 1 2 3 401 402 403 404 region 0 region 1 801 802 803 804 region 2 12/53
1. 入力値のjhashを取って、tableのサイズ分だけにtruncate 入力 value jhash & (tablesize -1) 例: 192.168.1.1
例: 0x12318e42 例: 0x242 (region数 == 1) 例: 0xe42 (region数== 4) 2. Prerequisite | IPSet addの実装 13/53
2. htableのうち、先程計算したindex番目のhbucketを編集 hbucket used pos/size 192.168.1.68 192.168.1.1 0 1 2
... 0xe41 0xe42 htable 2. Prerequisite | IPSet addの実装 14/53
3. add時にtimeout (==有効期限)を設定できる hbucket used pos/size 192.168.100.98 192.168.1.1 / 1m
0 1 2 ... 0xe41 0xe42 htable 2. Prerequisite | IPSet addの実装 15/53
1. region毎にtimeoutしたエントリの存在を確認/存在したら削除 2. Prerequisite | IPSet GCの実装 hbucket used pos/size
192.168.100.98 192.168.1.1 / 1m 0 1 2 ... 0xe41 0xe42 htable 16/53
2. Prerequisite | IPSet GCの実装 hbucket used pos/size 192.168.100.98 削除
0 1 2 ... 0xe41 0xe42 htable 1. region毎にtimeoutしたエントリが存在確認/存在したら削除 17/53
3. Vulnerability | lockの取り方 - Kernelはマルチスレッドなので、適切なlockが必要 - region毎にhregion[n]をlockする方針 1region毎にlockを取ってGC bucket
index % region数でlockを取る 0 GC側 Add 側 htable htable 0x401 1 2 0x403 0x402 例: hregion[0]のlockを取ってGCするもの 例: hregion[0]のlockを取ってaddするもの (region数 == 2とする) 1 0x402 0x401 0x403 0 2 18/53
3. Vulnerability | lockの取り方 - Kernelはマルチスレッドなので、適切なlockが必要 - region毎にhregion[n]をlockする方針 → add側がlockの取り方をミスってる!!
1region毎にlockを取ってGC bucket index % region数でlockを取る 0 GC側 Add 側 htable htable 0x401 1 2 0x403 0x402 例: hregion[0]のlockを取ってGCするもの 例: hregion[0]のlockを取ってaddするもの (region数 == 2とする) 0x402 0x401 0x403 1 0 2 19/53
3. Vulnerability | パッチの意味 - % が / になっている →
add側のlockの計算マクロがこれ https://lore.kernel.org/linux-cve-announce/2025052902-CVE-2025-37997-2c6c@gregkh/T/#u 20/53
3. Vulnerability | lockの不整合・具体例 0 1 2 ... 0x401 0x402
htable 例: region数==2のとき GC Thread - region0のGCをしている - hregion[0]をlockする add Thread - index 1にエントリを追加し ようとしている - hregion[1]をlockする 21/53
0 1 2 ... 0x401 0x402 htable 例: region数==2のとき GC
Thread - region0のGCをしている - hregion[0]をlockする add Thread - index 1にエントリを追加し ようとしている - hregion[1]をlockする - (index % region数)をlock 3. Vulnerability | lockの不整合・具体例 22/53
0 1 2 ... 0x401 0x402 htable 例: region数==2のとき GC
Thread - region0のGCをしている - hregion[0]をlockする add Thread - index 1にエントリを追加し ようとしている - hregion[1]をlockする - (index % region数)をlock index==1に対して2スレ ッドが同時に操作 3. Vulnerability | lockの不整合・具体例 23/53
4. Exploit | bucketの構造 rcu_head rcu u8 size, pos long
used u32 ip ulong timeout u32 skbmark, skbmarkmask hbucket u16 skbprio, skbqueue ... ヘッダー部 データ部 (何個も続く) 24/53
1. regionのはじめから最後までを loop mtype_gc_doの実装 4. Exploit | GCの実装 25/53
1. regionのはじめから最後までを loop 2. 各regionにおいて、bucketのすべ てのエントリをloop mtype_gc_doの実装 4. Exploit |
GCの実装 26/53
1. regionのはじめから最後までを loop 2. 各regionにおいて、bucketのすべ てのエントリをloop 3. usedが立ってないエントリと mtype_gc_doの実装 4.
Exploit | GCの実装 27/53
1. regionのはじめから最後までを loop 2. 各regionにおいて、bucketのすべ てのエントリをloop 3. usedが立ってないエントリと expireしたエントリをd++で数える (expireしたものはusedのbitを落と
す) mtype_gc_doの実装 4. Exploit | GCの実装 28/53
1. regionのはじめから最後までをloop 2. 各regionにおいて、bucketのすべてのエントリ をloop 3. usedが立ってないエントリとexpireしたエント リをd++で数える (expireしたものはusedのbitを 落とす)
4. dがAHASH_INIT_SIZEが2を超えていたら mtype_gc_doの実装 4. Exploit | GCの実装 29/53
4. Exploit | GCの実装 1. regionのはじめから最後までをloop 2. 各regionにおいて、bucketのすべてのエントリ をloop 3.
usedが立ってないエントリとexpireしたエント リをd++で数える (expireしたものはusedのbitを 落とす) 4. dがAHASH_INIT_SIZE(2)を超えていたら 5. (最大エントリ数 - 2) * エントリサイズの領域を alloc mtype_gc_doの実装 30/53
4. Exploit | GCの実装 1. regionのはじめから最後までをloop 2. 各regionにおいて、bucketのすべてのエントリ をloop 3.
usedが立ってないエントリとexpireしたエント リをd++で数える (expireしたものはusedのbitを 落とす) 4. dがAHASH_INIT_SIZE(2)を超えていたら 5. (最大エントリ数 - 2) * エントリサイズの領域を alloc 6. 元の領域からusedのbitが立っているエントリ だけコピー mtype_gc_doの実装 31/53
4. Exploit | GCとaddのrace condition rcu_head rcu u8 size, pos
192.0.2.1 / 1h 192.0.2.68 / 1h id==1のhbucket 1 2 3 4 0 long used 192.0.2.194 / 0s 192.0.2.253 / 0s 1. GCがhregion[0]のlockを取ってregion0のGC を開始 具体例 32/53
4. Exploit | GCとaddのrace condition rcu_head rcu u8 size, pos
192.0.2.1 / 1h 192.0.2.68 / 1h id==1のhbucket 1 2 3 4 0 long used 192.0.2.194 / 0s 192.0.2.253 / 0s 1. GCがhregion[0]のlockを取ってregion0のGC を開始 2. GCがタイムアウトしたエントリのused bitを 落とす 具体例 33/53
4. Exploit | GCとaddのrace condition rcu_head rcu u8 size, pos
192.0.2.1 / 1h 192.0.2.68 / 1h id==1のhbucket 1 2 3 4 0 long used 203.0.113.1 / 1h 192.0.2.253 / 0s 1. GCがhregion[0]のlockを取ってregion0のGC を開始 2. GCがタイムアウトしたエントリのused bitを 落とす 3. 別スレッドでこのhbucketに対するaddが実行 され、エントリが挿入される (used bitが再度立 つ) 具体例 34/53
4. Exploit | GCとaddのrace condition rcu_head rcu u8 size, pos
192.0.2.1 / 1h 192.0.2.68 / 1h id==1のhbucket 1 2 3 4 0 long used 203.0.113.1 / 1h 192.0.2.253 / 0s rcu_head rcu u8 size, pos new hbucket 1 2 3 4 0 long used 4. GCは2要素分少なく した領域を新たにalloc 35/53
4. Exploit | GCとaddのrace condition rcu_head rcu u8 size, pos
192.0.2.1 / 1h 192.0.2.68 / 1h id==1のhbucket 1 2 3 4 0 long used 203.0.113.1 / 1h 192.0.2.253 / 0s rcu_head rcu u8 size, pos new hbucket 1 2 3 4 0 long used 4. GCは2要素分少なく した領域を新たにalloc 5. used bitが立ってい るエントリを1つずつ コピー 192.0.2.1 / 1h 0 36/53
4. Exploit | GCとaddのrace condition rcu_head rcu u8 size, pos
192.0.2.1 / 1h 192.0.2.68 / 1h id==1のhbucket 1 2 3 4 0 long used 203.0.113.1 / 1h 192.0.2.253 / 0s rcu_head rcu u8 size, pos new hbucket 1 2 3 4 0 long used 4. GCは2要素分少なく した領域を新たにalloc 5. used bitが立ってい るエントリを1つずつ コピー 192.0.2.1 / 1h 1 0 192.0.2.68 / 1h 37/53
4. Exploit | GCとaddのrace condition rcu_head rcu u8 size, pos
192.0.2.1 / 1h 192.0.2.68 / 1h id==1のhbucket 1 2 3 4 0 long used 203.0.113.1 / 1h 192.0.2.253 / 0s rcu_head rcu u8 size, pos new hbucket 1 2 3 4 0 long used 4. GCは2要素分少なく した領域を新たにalloc 5. used bitが立ってい るエントリを1つずつ コピー 192.0.2.1 / 1h 1 0 192.0.2.68 / 1h 2 203.0.113.1 / 1h 範囲外書き込み!! BoF (OOB write)!! 38/53
4. Exploit | bucketの構造 rcu_head rcu u8 size, pos u32
ip ulong timeout u32 skbmark, skbmarkmask long used u16 skbprio, skbqueue もし範囲外書き込みの先に別のhbucketがいた ら? 赤文字のところには任意のデータを入れられる → 別のhbucketを(自認)デカsizeに書き換えられ る 39/53
4. Exploit | bucketの構造 rcu_head rcu u8 size, pos u32
ip ulong timeout u32 skbmark, skbmarkmask long used u16 skbprio, skbqueue もし範囲外書き込みの先に別のhbucketがいたら? 赤文字のところには任意のデータを入れられる → 別のhbucketを(自認)デカsizeに書き換えられる → 巨大な範囲外書き込みができる 40/53
4. Exploit | dirty pagetable 範囲外書き込みを権限昇格につなげる手法 → dirty pagetable 41/53
4. Exploit | dirty pagetable 範囲外書き込みを権限昇格につなげる手法 → dirty pagetable pagetableとは?
→ 仮想アドレスと物理アドレスを対応付ける仕組み https://www.coins.tsukuba.ac.jp/~yas/coins/os2-2025/2026-01-15/index.html 42/53
4. Exploit | dirty pagetable 範囲外書き込みを権限昇格につなげる手法 → dirty pagetable pagetableとは?
→ 仮想アドレスと物理アドレスを対応付ける仕組み → pagetableを書き換えてある仮想アドレスを任意の物理アドレスに向けるのがdirty pagetable https://www.coins.tsukuba.ac.jp/~yas/coins/os2-2025/2026-01-15/index.html 43/53
4. Exploit | dirty pagetable 範囲外書き込みを権限昇格につなげる手法 → dirty pagetable pagetableとは?
→ 仮想アドレスと物理アドレスを対応付ける仕組み → pagetableを書き換えてある仮想アドレスを任意の物理アドレスに向けるのがdirty pagetable 任意の物理メモリをユーザーランドからいじれるようになる → カーネルも物理メモリに乗っていて物理メモリの世界にRWXなどという概念はない 44/53
4. Exploit | dirty pagetable 範囲外書き込みを権限昇格につなげる手法 → dirty pagetable pagetableとは?
→ 仮想アドレスと物理アドレスを対応付ける仕組み → pagetableを書き換えてある仮想アドレスを任意の物理アドレスに向けるのがdirty pagetable 任意の物理メモリをユーザーランドからいじれるようになる → カーネルも物理メモリに乗っていて物理メモリの世界にRWXなどという概念はない → 何でもできる (R-Xな領域の上書きも!) 45/53
4. Exploit | dirty pagetable 書き込み先: core_pattern - crashしたときにcoredumpを生成するためにroot権限でどんなことをすればいいか書かれ ている
- |から始まると、そのファイルを実行する 46/53
4. Exploit | dirty pagetable 書き込み先: core_pattern - crashしたときにコアダンプを生成するためにroot権限で何をすべきか書かれている -
|から始まると、そのファイルを実行する - 例えば |/home/rona/lpe に書き換えるとroot権限で何でも実行させられる (== 権限昇格) 47/53
4. Exploit | dirty pagetable 権限昇格手法 1. 範囲外書き込みで到達可能な範囲にpagetableが置かれるように調整 2. 範囲外書き込みでpagetable
entryをcore_patternが置かれている物理ページに向ける 48/53
4. Exploit | dirty pagetable 権限昇格手法 1. 範囲外書き込みで到達可能な範囲にpagetableが置かれるように調整 2. 範囲外書き込みでpagetable
entryをcore_patternが置かれている物理ページに向ける 3. core_patternを書き換える 49/53
4. Exploit | dirty pagetable 権限昇格手法 1. 範囲外書き込みで到達可能な範囲にpagetableが置かれるように調整 2. 範囲外書き込みでpagetable
entryをcore_patternが置かれている物理ページに向ける 3. core_patternを書き換える 4. win! 権限昇格! 50/53
4. Exploit | 影響を受けるプロダクト - 一般ユーザーがipsetをいじれる環境 → unprivileged_userns_cloneが有効なLinux - RedHad
Enterprise Linuxのデフォルトインストール - rootless Docker/podmanが入ったLinux 51/53
5. おわり - マルチスレッドアプリケーションを安全に書くのは難しい - Linux kernelのように良くauditされたOSSにもミスは存在する 52/53
6. 宣伝 dirty pagetableと同様の攻撃をやってみたい!という方はHungry Goatsを解いて みてください! 脆弱なLinuxカーネルモジュールを利用して権限昇格をする問題 https://alpacahack.com/challenges/hungry-goats 53/53