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
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
rona
March 20, 2026
Programming
2.5k
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
「なぜそう決めたのか」を残し続ける仕組み ― Notion AI カスタムエージェント × Slack連携による設計判断の自動記録 - NIKKEI Tech Talk #47
niftycorp
PRO
0
170
ECSアプリログをFireLensでコスト削減しようとしたけど諦めた話 in Fargate×Node.js
akihisaikeda
2
4.2k
TAKTでAI駆動開発の品質を設計する
j5ik2o
7
1.3k
技術記事、AIに書かせるか、自分で書くか? 〜それでも私が自分の手で書く理由〜 / #QiitaConference
jnchito
2
1.4k
不変条件と整合性境界—ビジネスが決める設計判断と実現パターン / Invariants and Consistency Boundaries
nrslib
13
4.6k
ふつうのFeature Flag実践入門
irof
7
3.9k
Vue × Nuxt × Oxc どこまで使える?実運用の現在地
andpad
0
250
タクシーアプリ『GO』の バックエンド開発のおける AI利活用と若者のすべて
pyama86
3
2k
「エンジニアインターン、どうやって取った?」準備のリアルを語るLT会 Progate BAR
akiomatic
0
130
スマートグラスで並列バイブコーディング
hyshu
0
140
Technical Debt: Understanding it Rightly, Engaging it Rightly #LaravelLiveJP
shogogg
0
230
軽量Java基盤の設計 DIコンテナに頼らない、長期保守と1秒起動の実現 JJUG CCC 2026 Spring
macha64
0
520
Featured
See All Featured
Unlocking the hidden potential of vector embeddings in international SEO
frankvandijk
0
840
Navigating Algorithm Shifts & AI Overviews - #SMXNext
aleyda
1
1.3k
Discover your Explorer Soul
emna__ayadi
2
1.1k
The Curious Case for Waylosing
cassininazir
1
390
Design of three-dimensional binary manipulators for pick-and-place task avoiding obstacles (IECON2024)
konakalab
0
460
For a Future-Friendly Web
brad_frost
183
10k
Information Architects: The Missing Link in Design Systems
soysaucechin
0
970
Building a Scalable Design System with Sketch
lauravandoore
463
34k
My Coaching Mixtape
mlcsv
0
150
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
52
6k
Lightning Talk: Beautiful Slides for Beginners
inesmontani
PRO
2
580
Product Roadmaps are Hard
iamctodd
PRO
55
12k
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