<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>BeaCox&#39;s Blog</title>
    <link>https://blog.beacox.space/tags/vma/</link>
    <description>Stay humble, remain critical.</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en</language>
    <managingEditor>root@beacox.space (BeaCox)</managingEditor>
    <webMaster>root@beacox.space (BeaCox)</webMaster>
    <copyright>© Since 2022 BeaCox</copyright>
    <lastBuildDate>Wed, 21 Oct 2026 02:20:32 +0000</lastBuildDate><atom:link href="https://blog.beacox.space/tags/vma/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>pwn.college KylebotFS Level 4 Writeup</title>
      <link>https://blog.beacox.space/posts/kbfs-lv4-wp/</link>
      <pubDate>Wed, 21 Oct 2026 10:00:00 +0800</pubDate>
      <author>root@beacox.space (BeaCox)</author>
      <guid>https://blog.beacox.space/posts/kbfs-lv4-wp/</guid>
      <description><br/>
  
  
  
  



&lt;div
  
    class=&#34;flex px-4 py-3 rounded-md bg-primary-100 dark:bg-primary-900&#34;
  
  &gt;
  &lt;span
    
      class=&#34;text-primary-400 ltr:pr-3 rtl:pl-3 flex items-center&#34;
    
    &gt;
    

  &lt;span class=&#34;relative block icon&#34;&gt;
    &lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 576 512&#34;&gt;
&lt;path fill=&#34;currentColor&#34; d=&#34;M234.7 42.7L197 56.8c-3 1.1-5 4-5 7.2s2 6.1 5 7.2l37.7 14.1L248.8 123c1.1 3 4 5 7.2 5s6.1-2 7.2-5l14.1-37.7L315 71.2c3-1.1 5-4 5-7.2s-2-6.1-5-7.2L277.3 42.7 263.2 5c-1.1-3-4-5-7.2-5s-6.1 2-7.2 5L234.7 42.7zM46.1 395.4c-18.7 18.7-18.7 49.1 0 67.9l34.6 34.6c18.7 18.7 49.1 18.7 67.9 0L529.9 116.5c18.7-18.7 18.7-49.1 0-67.9L495.3 14.1c-18.7-18.7-49.1-18.7-67.9 0L46.1 395.4zM484.6 82.6l-105 105-23.3-23.3 105-105 23.3 23.3zM7.5 117.2C3 118.9 0 123.2 0 128s3 9.1 7.5 10.8L64 160l21.2 56.5c1.7 4.5 6 7.5 10.8 7.5s9.1-3 10.8-7.5L128 160l56.5-21.2c4.5-1.7 7.5-6 7.5-10.8s-3-9.1-7.5-10.8L128 96 106.8 39.5C105.1 35 100.8 32 96 32s-9.1 3-10.8 7.5L64 96 7.5 117.2zm352 256c-4.5 1.7-7.5 6-7.5 10.8s3 9.1 7.5 10.8L416 416l21.2 56.5c1.7 4.5 6 7.5 10.8 7.5s9.1-3 10.8-7.5L480 416l56.5-21.2c4.5-1.7 7.5-6 7.5-10.8s-3-9.1-7.5-10.8L480 352l-21.2-56.5c-1.7-4.5-6-7.5-10.8-7.5s-9.1 3-10.8 7.5L416 352l-56.5 21.2z&#34;/&gt;&lt;/svg&gt;
  &lt;/span&gt;


  &lt;/span&gt;

  &lt;span
    
      class=&#34;dark:text-neutral-300&#34;
    
    &gt;本文由 AI 辅助编写，内容经人工校对。&lt;/span&gt;
&lt;/div&gt;

&lt;p&gt;&lt;img src=&#34;https://blog.beacox.space/posts/kbfs-lv4-wp/img001.png&#34; alt=&#34;允许wp&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;免责声明：这个系列鼓励wp :)&lt;/p&gt;

&lt;h2 class=&#34;relative group&#34;&gt;题目背景与 Diff 分析 
    &lt;div id=&#34;题目背景与-diff-分析&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;
    
    &lt;span
        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100&#34;&gt;
        &lt;a class=&#34;group-hover:text-primary-300 dark:group-hover:text-neutral-700 !no-underline&#34; href=&#34;#%e9%a2%98%e7%9b%ae%e8%83%8c%e6%99%af%e4%b8%8e-diff-%e5%88%86%e6%9e%90&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;
    &lt;/span&gt;        
    
&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;KylebotFS&lt;/code&gt; 是 pwn.college &lt;em&gt;The Quarterly Quiz&lt;/em&gt; 系列中的自定义内核文件系统模块（&lt;code&gt;challenge.ko&lt;/code&gt;）。用户可以通过挂载构造好的磁盘镜像，经由常规 VFS 接口（&lt;code&gt;open&lt;/code&gt; / &lt;code&gt;mmap&lt;/code&gt; / &lt;code&gt;munmap&lt;/code&gt;）与内核模块交互。&lt;/p&gt;

&lt;h3 class=&#34;relative group&#34;&gt;环境信息 
    &lt;div id=&#34;环境信息&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;
    
    &lt;span
        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100&#34;&gt;
        &lt;a class=&#34;group-hover:text-primary-300 dark:group-hover:text-neutral-700 !no-underline&#34; href=&#34;#%e7%8e%af%e5%a2%83%e4%bf%a1%e6%81%af&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;
    &lt;/span&gt;        
    
&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;内核版本&lt;/strong&gt;：&lt;code&gt;Linux 6.7.9 #7 SMP PREEMPT_DYNAMIC&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;启动参数&lt;/strong&gt;：开启 KASLR，&lt;code&gt;oops=panic panic_on_warn=1&lt;/code&gt;（触发任何内核 &lt;code&gt;WARN&lt;/code&gt; 直接 Panic，容错率为零）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;权限限制&lt;/strong&gt;：&lt;code&gt;/challenge/mount_kbfs&lt;/code&gt; 权限被设为 &lt;code&gt;0755&lt;/code&gt;（移除了 Level 2 的 SUID 位），但 &lt;code&gt;/dev/loop*&lt;/code&gt; 权限为 &lt;code&gt;0666&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class=&#34;relative group&#34;&gt;模块 Diff（Level 2 vs Level 4） 
    &lt;div id=&#34;模块-difflevel-2-vs-level-4&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;
    
    &lt;span
        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100&#34;&gt;
        &lt;a class=&#34;group-hover:text-primary-300 dark:group-hover:text-neutral-700 !no-underline&#34; href=&#34;#%e6%a8%a1%e5%9d%97-difflevel-2-vs-level-4&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;
    &lt;/span&gt;        
    
&lt;/h3&gt;
&lt;p&gt;对比 Level 2 与 Level 4 的 &lt;code&gt;challenge.ko&lt;/code&gt;，实质性改动仅有三处：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;位置&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;Level 2&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;Level 4&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;影响&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;kbfs_fs_type.fs_flags&lt;/code&gt;&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;FS_REQUIRES_DEV&lt;/code&gt; (&lt;code&gt;1&lt;/code&gt;)&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;FS_REQUIRES_DEV | FS_USERNS_MOUNT&lt;/code&gt; (&lt;code&gt;9&lt;/code&gt;)&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;允许在 User Namespace 中无特权挂载&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;kbfs_iget()&lt;/code&gt;&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;读取磁盘 &lt;code&gt;dnode&lt;/code&gt; 的 &lt;code&gt;uid/gid&lt;/code&gt;&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;使用挂载进程的 &lt;code&gt;kbfs_info-&amp;gt;uid/gid&lt;/code&gt;&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;封死了直接伪造磁盘 inode 属主提权的路子&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;kbfs_file_mmap()&lt;/code&gt;&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;校验映射范围与整数溢出&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;&lt;strong&gt;删去了边界检查与溢出检查&lt;/strong&gt;&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;&lt;strong&gt;核心漏洞：物理内存越界映射与越界释放&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;

&lt;h2 class=&#34;relative group&#34;&gt;漏洞成因 
    &lt;div id=&#34;漏洞成因&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;
    
    &lt;span
        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100&#34;&gt;
        &lt;a class=&#34;group-hover:text-primary-300 dark:group-hover:text-neutral-700 !no-underline&#34; href=&#34;#%e6%bc%8f%e6%b4%9e%e6%88%90%e5%9b%a0&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;
    &lt;/span&gt;        
    
&lt;/h2&gt;
&lt;p&gt;问题集中在 &lt;code&gt;kbfs_file_mmap()&lt;/code&gt; 与 &lt;code&gt;kbfs_vma_cleanup()&lt;/code&gt; 对内存分配粒度与映射粒度的处理不一致。&lt;/p&gt;

&lt;h3 class=&#34;relative group&#34;&gt;&lt;code&gt;mmap&lt;/code&gt; 越界物理映射（OOB Read） 
    &lt;div id=&#34;mmap-越界物理映射oob-read&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;
    
    &lt;span
        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100&#34;&gt;
        &lt;a class=&#34;group-hover:text-primary-300 dark:group-hover:text-neutral-700 !no-underline&#34; href=&#34;#mmap-%e8%b6%8a%e7%95%8c%e7%89%a9%e7%90%86%e6%98%a0%e5%b0%84oob-read&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;
    &lt;/span&gt;        
    
&lt;/h3&gt;
&lt;p&gt;对照源码看 &lt;code&gt;kbfs_file_mmap()&lt;/code&gt; 的逻辑：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;kbfs_file_mmap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;filp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;vm_area_struct&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vma&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;vma&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vm_end&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;vma&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vm_start&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;              &lt;span class=&#34;c1&#34;&gt;// 用户请求映射的 VMA 长度
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;max_size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;round_up&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;inode&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;PAGE_SIZE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;   &lt;span class=&#34;c1&#34;&gt;// 文件实际占用的页对齐长度
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// [!] Level 4 删去了以下两个检查：
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// if (vma-&amp;gt;vm_pgoff * PAGE_SIZE + size &amp;gt; max_size) return -EINVAL;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// if (vma-&amp;gt;vm_pgoff * PAGE_SIZE + size &amp;lt; size)     return -EINVAL;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;kb_vma&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vaddr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;__get_free_pages&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;GFP_KERNEL&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__GFP_ZERO&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;get_order&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;max_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;kb_vma&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* 将文件内容拷贝进新分配的物理页 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;off&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;off&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;max_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;off&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;PAGE_SIZE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;memcpy&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kb_vma&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vaddr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;off&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;...);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;pfn&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;__pa&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kb_vma&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vaddr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;PAGE_SHIFT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;remap_pfn_range&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vma&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;vma&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vm_start&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pfn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;vma&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vm_page_prot&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里的分裂非常直观：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;分配阶段&lt;/strong&gt;按文件的 &lt;code&gt;max_size&lt;/code&gt; 向 Buddy Allocator 申请物理页。如果镜像中文件 &lt;code&gt;i_size = 16&lt;/code&gt;，则 &lt;code&gt;max_size = 0x1000&lt;/code&gt;，&lt;code&gt;get_order(max_size) = 0&lt;/code&gt;，内核仅分配 &lt;strong&gt;1 个物理页（4KB）&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;映射阶段&lt;/strong&gt; &lt;code&gt;remap_pfn_range()&lt;/code&gt; 却按用户请求的 &lt;code&gt;size&lt;/code&gt; 建立页表映射。若用户 &lt;code&gt;mmap&lt;/code&gt; 长度为 64MB，内核会将该页起始的 &lt;strong&gt;连续 64MB 物理内存&lt;/strong&gt; 直接映射进用户空间。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;为什么是&lt;strong&gt;只读&lt;/strong&gt;窗口？因为 &lt;code&gt;kbfs_file_mmap()&lt;/code&gt; 强制要求 &lt;code&gt;MAP_PRIVATE&lt;/code&gt;（传入 &lt;code&gt;MAP_SHARED&lt;/code&gt; 直接返回 &lt;code&gt;-EINVAL&lt;/code&gt;）。在私有映射下，即便传入 &lt;code&gt;PROT_WRITE&lt;/code&gt;，&lt;code&gt;vma-&amp;gt;vm_page_prot&lt;/code&gt; 依然是只读的 &lt;code&gt;PAGE_COPY&lt;/code&gt;。任何写操作都会触发 Page Fault 进入 &lt;code&gt;wp_page_copy()&lt;/code&gt; 走写时复制（COW），修改的只是新分配的匿名页副本，原物理页纹丝不动。&lt;/p&gt;

&lt;h3 class=&#34;relative group&#34;&gt;&lt;code&gt;munmap&lt;/code&gt; 越界释放（OOB Page Free） 
    &lt;div id=&#34;munmap-越界释放oob-page-free&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;
    
    &lt;span
        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100&#34;&gt;
        &lt;a class=&#34;group-hover:text-primary-300 dark:group-hover:text-neutral-700 !no-underline&#34; href=&#34;#munmap-%e8%b6%8a%e7%95%8c%e9%87%8a%e6%94%beoob-page-free&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;
    &lt;/span&gt;        
    
&lt;/h3&gt;
&lt;p&gt;当 VMA 解除映射且底层 &lt;code&gt;struct file&lt;/code&gt; 引用计数归零时，调用链来到 &lt;code&gt;kbfs_file_release() -&amp;gt; kbfs_vma_cleanup()&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;free_pages&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kb_vma&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vaddr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;get_order&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kb_vma&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 按用户映射长度 size 释放！
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;kfree&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kb_vma&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;kb_vma-&amp;gt;vaddr&lt;/code&gt; 实际只分配了 Order 0（1 页），但释放时传入了 &lt;code&gt;get_order(kb_vma-&amp;gt;size)&lt;/code&gt;。若 &lt;code&gt;size = 2MB&lt;/code&gt;（Order 9，512 页），&lt;code&gt;free_pages(vaddr, 9)&lt;/code&gt; 会将该页连同其物理地址后方紧邻的 &lt;strong&gt;511 个物理页&lt;/strong&gt; 一并作为 Order 9 空闲块归还给 Buddy Allocator。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                  kbfs_file_mmap() &amp;amp; kbfs_vma_cleanup()
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Physical Pages: +--------+--------+--------+--------+ - - - +--------+
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                  | Page 0 | Page 1 | Page 2 | Page 3 |       |Page 511|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                  +--------+--------+--------+--------+ - - - +--------+
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                  ^        ^                                           ^
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                  |        |                                           |
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Allocated:      +--------+                                           |
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (max_size=4KB)   Order 0 (1 Page from __get_free_pages)              |
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                  |                                                    |
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Mapped &amp;amp; Freed: +----------------------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  (size=2MB)       Order 9 (512 Pages mapped via remap_pfn_range
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                            and freed via free_pages(vaddr, 9))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这就给出了本题的两个核心原语：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;64MB 物理内存只读窗口（映射 A）&lt;/strong&gt;：直接透视物理内存中的 &lt;code&gt;task_struct&lt;/code&gt;、&lt;code&gt;cred&lt;/code&gt;、&lt;code&gt;kbfs_vma_struct&lt;/code&gt; 等内核对象。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;2MB 连续物理页越界释放（映射 B）&lt;/strong&gt;：把后方 511 页强行送进 Buddy 空闲链表，构造 &lt;strong&gt;Page UAF&lt;/strong&gt;。&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 class=&#34;relative group&#34;&gt;核心机制与原语构造 
    &lt;div id=&#34;核心机制与原语构造&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;
    
    &lt;span
        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100&#34;&gt;
        &lt;a class=&#34;group-hover:text-primary-300 dark:group-hover:text-neutral-700 !no-underline&#34; href=&#34;#%e6%a0%b8%e5%bf%83%e6%9c%ba%e5%88%b6%e4%b8%8e%e5%8e%9f%e8%af%ad%e6%9e%84%e9%80%a0&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;
    &lt;/span&gt;        
    
&lt;/h2&gt;
&lt;p&gt;既然没有直接写原语，唯一路径就是：&lt;strong&gt;通过越界释放将目标 &lt;code&gt;cred&lt;/code&gt; 所在的 Slab 页释放回 Buddy -&amp;gt; 喷射内容可控的内核对象回收该物理页 -&amp;gt; 覆盖 &lt;code&gt;cred&lt;/code&gt; 的 &lt;code&gt;uid..fsgid&lt;/code&gt; 字段为 0&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;要让这条链路在 &lt;code&gt;panic_on_warn=1&lt;/code&gt; 下稳定跑通，必须解决以下三个内核机制层面的问题。&lt;/p&gt;

&lt;h3 class=&#34;relative group&#34;&gt;Direct Map 地址换算（免泄露突破 KASLR） 
    &lt;div id=&#34;direct-map-地址换算免泄露突破-kaslr&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;
    
    &lt;span
        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100&#34;&gt;
        &lt;a class=&#34;group-hover:text-primary-300 dark:group-hover:text-neutral-700 !no-underline&#34; href=&#34;#direct-map-%e5%9c%b0%e5%9d%80%e6%8d%a2%e7%ae%97%e5%85%8d%e6%b3%84%e9%9c%b2%e7%aa%81%e7%a0%b4-kaslr&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;
    &lt;/span&gt;        
    
&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;__get_free_pages()&lt;/code&gt; 返回的是 Direct Map 区（线性映射区）的内核虚拟地址，满足：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Virtual Address = Physical Address + page_offset_base
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;因此，在 64MB 的映射窗口 &lt;code&gt;A&lt;/code&gt; 内，任何内核堆指针 &lt;code&gt;V&lt;/code&gt; 指向的对象在 &lt;code&gt;A&lt;/code&gt; 内的字节偏移 &lt;code&gt;off&lt;/code&gt;，都满足线性平移关系：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;V = V_A + off   &amp;lt;===&amp;gt;   V_A = V - off
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中 &lt;code&gt;V_A&lt;/code&gt; 是窗口 &lt;code&gt;A&lt;/code&gt; 起始物理页对应的 Direct Map 虚拟地址。只要我们在窗口 &lt;code&gt;A&lt;/code&gt; 中定位到任意一个进程的 &lt;code&gt;task_struct&lt;/code&gt;（读出指针 &lt;code&gt;C = task-&amp;gt;cred&lt;/code&gt;），再在窗口 &lt;code&gt;A&lt;/code&gt; 中找到该 &lt;code&gt;cred&lt;/code&gt; 结构体所在的实际偏移 &lt;code&gt;coff&lt;/code&gt;，就能直接算出 &lt;code&gt;V_A = C - coff&lt;/code&gt;。后续判断任何内核指针是否落入窗口 &lt;code&gt;A&lt;/code&gt; 或某个映射 &lt;code&gt;B&lt;/code&gt; 的范围内，只需做简单的减法即可，全程无需关心内核代码段 KASLR。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Kernel Direct Map (Virtual)          64MB Read Window A (User mmap)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  +----------------------------+       +----------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  | V_A (Base Virtual Addr)    | &amp;lt;---&amp;gt; | Offset 0x000000            |
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  |   ...                      |       |   ...                      |
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  | V_B = V_A + X              | &amp;lt;---&amp;gt; | Offset X      (B[i] Page)  |
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  |   ...                      |       |   ...                      |
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  | C   = V_A + coff           | &amp;lt;---&amp;gt; | Offset coff   (Target cred)|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  +----------------------------+       +----------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 class=&#34;relative group&#34;&gt;Migratetype 隔离与 &lt;code&gt;msg_msg&lt;/code&gt; 跨层回收 
    &lt;div id=&#34;migratetype-隔离与-msg_msg-跨层回收&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;
    
    &lt;span
        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100&#34;&gt;
        &lt;a class=&#34;group-hover:text-primary-300 dark:group-hover:text-neutral-700 !no-underline&#34; href=&#34;#migratetype-%e9%9a%94%e7%a6%bb%e4%b8%8e-msg_msg-%e8%b7%a8%e5%b1%82%e5%9b%9e%e6%94%b6&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;
    &lt;/span&gt;        
    
&lt;/h3&gt;
&lt;p&gt;目标 &lt;code&gt;cred&lt;/code&gt; 位于 &lt;code&gt;cred_jar&lt;/code&gt; SLUB 缓存页，而映射 &lt;code&gt;B&lt;/code&gt; 是通过 &lt;code&gt;__get_free_pages(GFP_KERNEL, ...)&lt;/code&gt; 分配的。&lt;/p&gt;
&lt;p&gt;当 &lt;code&gt;free_pages(vaddr, 9)&lt;/code&gt; 释放 &lt;code&gt;B&lt;/code&gt; 时，这 512 个物理页归入 Buddy Allocator 的 &lt;strong&gt;&lt;code&gt;MIGRATE_UNMOVABLE&lt;/code&gt;&lt;/strong&gt; 空闲链表（因为 &lt;code&gt;GFP_KERNEL&lt;/code&gt; 不含 &lt;code&gt;__GFP_MOVABLE&lt;/code&gt;）。如果尝试在用户态用匿名页（&lt;code&gt;mmap&lt;/code&gt; + 写入）去堆喷回收，匿名页走的是 &lt;code&gt;GFP_HIGHUSER_MOVABLE&lt;/code&gt;（属于 &lt;strong&gt;&lt;code&gt;MIGRATE_MOVABLE&lt;/code&gt;&lt;/strong&gt;），分配器会在各自的 migratetype 链表内拿页，完全碰不到 &lt;code&gt;UNMOVABLE&lt;/code&gt; 链表里的页。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Buddy Free Lists (Order 0..10)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  +-----------------------+-------------------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  | MIGRATE_UNMOVABLE     | &amp;lt;-- B block freed here (GFP_KERNEL)             |
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  |                       | &amp;lt;-- Reclaimed by msg_msg (GFP_KERNEL_ACCOUNT)   |
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  +-----------------------+-------------------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  | MIGRATE_MOVABLE       | &amp;lt;-- User-space anon page spray lands here (Miss)|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  +-----------------------+-------------------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;因此，必须选用同样从 &lt;code&gt;UNMOVABLE&lt;/code&gt; 拿页、且整页大小与内容可控的 &lt;strong&gt;&lt;code&gt;msg_msg&lt;/code&gt;&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;调用 &lt;code&gt;msgsnd&lt;/code&gt; 发送 &lt;code&gt;4048&lt;/code&gt; 字节消息时，&lt;code&gt;sizeof(struct msg_msg) + 4048 = 0x30 + 0xfd0 = 0x1000&lt;/code&gt;，正好申请一个 &lt;code&gt;kmalloc-cg-4k&lt;/code&gt; 对象（底层直接对应单个 4KB 物理页），分配标志为 &lt;code&gt;GFP_KERNEL_ACCOUNT&lt;/code&gt;（同属 &lt;code&gt;UNMOVABLE&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;页内偏移 &lt;code&gt;0x00..0x2f&lt;/code&gt; 为 &lt;code&gt;msg_msg&lt;/code&gt; 头部，&lt;code&gt;0x30..0xfff&lt;/code&gt; 为完全可控的 &lt;code&gt;mtext&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;只要目标 &lt;code&gt;cred&lt;/code&gt; 的页内偏移 &lt;code&gt;(coff &amp;amp; 0xfff) &amp;gt;= 0x30&lt;/code&gt;，我们就可以先把整个 &lt;code&gt;cred&lt;/code&gt; 页从窗口 &lt;code&gt;A&lt;/code&gt; 原样拷贝出来，将目标 &lt;code&gt;cred&lt;/code&gt; 的 &lt;code&gt;uid..fsgid&lt;/code&gt;（共 32 字节）清零，再截取 &lt;code&gt;[0x30, 0x1000)&lt;/code&gt; 塞进 &lt;code&gt;mtext&lt;/code&gt; 进行喷射。这样当 &lt;code&gt;msg_msg&lt;/code&gt; 落回该物理页时，目标 &lt;code&gt;cred&lt;/code&gt; 原地变为 root，而同页上的其他兄弟 &lt;code&gt;cred&lt;/code&gt; 对象保持原样，不会破坏相邻进程。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Target Cred Page (4096 Bytes) Reclaimed by kmalloc-cg-4k msg_msg:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  +------------------+-----------------+------------------------+-----------+
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  | 0x000 .. 0x02f   | 0x030 .. co-1   | co .. co+0x27          | .. 0xfff  |
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  +------------------+-----------------+------------------------+-----------+
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  | struct msg_msg   | Preserved bytes | Target struct cred     | Preserved |
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  | header + marker  | (copied from A) | usage kept, uid..fsgid | bytes     |
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  |                  |                 | zeroed (32 bytes = 0)  | (from A)  |
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  +------------------+-----------------+------------------------+-----------+
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                     |&amp;lt;---------------- mtext (4048 Bytes) ----------------&amp;gt;|
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 class=&#34;relative group&#34;&gt;规避 &lt;code&gt;kfree(kb_vma)&lt;/code&gt; 触发的 SLUB &lt;code&gt;WARN&lt;/code&gt; 
    &lt;div id=&#34;规避-kfreekb_vma-触发的-slub-warn&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;
    
    &lt;span
        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100&#34;&gt;
        &lt;a class=&#34;group-hover:text-primary-300 dark:group-hover:text-neutral-700 !no-underline&#34; href=&#34;#%e8%a7%84%e9%81%bf-kfreekb_vma-%e8%a7%a6%e5%8f%91%e7%9a%84-slub-warn&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;
    &lt;/span&gt;        
    
&lt;/h3&gt;
&lt;p&gt;这是本题最容易踩的坑。再看一眼清理函数：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;free_pages&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kb_vma&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vaddr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;get_order&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kb_vma&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;kfree&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kb_vma&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;每次 &lt;code&gt;mmap&lt;/code&gt; 时，驱动都会 &lt;code&gt;kmalloc&lt;/code&gt; 一个 32 字节的管理结构 &lt;code&gt;kbfs_vma_struct&lt;/code&gt;（位于 &lt;code&gt;kmalloc-32&lt;/code&gt; Slab 页），并挂入全局链表 &lt;code&gt;kbfs_vma_root&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kbfs_vma_struct&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;u64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;vaddr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;              &lt;span class=&#34;c1&#34;&gt;// 0x00: 分配的虚拟地址 V_B
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;size_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;            &lt;span class=&#34;c1&#34;&gt;// 0x08: 映射大小 0x200000
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;list_head&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 0x10: 链表指针 (next 指向 root + 0x10)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果候选 &lt;code&gt;B&lt;/code&gt; 释放的 &lt;code&gt;[X, X + 2MB)&lt;/code&gt; 物理区间内，恰好包含了 &lt;code&gt;B&lt;/code&gt; 自身的 &lt;code&gt;kb_vma&lt;/code&gt; 所在的 &lt;code&gt;kmalloc-32&lt;/code&gt; Slab 页（或者 &lt;code&gt;kbfs_vma_root&lt;/code&gt; 所在的页），那么第一行的 &lt;code&gt;free_pages()&lt;/code&gt; 会把该页的 &lt;code&gt;PG_slab&lt;/code&gt; 标志抹掉。紧接着第二行执行 &lt;code&gt;kfree(kb_vma)&lt;/code&gt; 时，SLUB 检查发现该页不再是合法的 Slab 页，当场抛出 &lt;code&gt;WARN&lt;/code&gt; 触发 Panic。&lt;/p&gt;
&lt;p&gt;因此，在挑选用于释放的 &lt;code&gt;B&lt;/code&gt; 之前，必须在窗口 &lt;code&gt;A&lt;/code&gt; 中扫描特征对 &lt;code&gt;{V_B, 0x200000}&lt;/code&gt; 找到其对应的 &lt;code&gt;kb_vma&lt;/code&gt;，确保 &lt;code&gt;kb_vma&lt;/code&gt; 自身以及 &lt;code&gt;list.next - 0x10&lt;/code&gt;（即 &lt;code&gt;root&lt;/code&gt; 对象）都不在 &lt;code&gt;[X, X + 2MB)&lt;/code&gt; 区间内。&lt;/p&gt;

&lt;h2 class=&#34;relative group&#34;&gt;Exploit Chain 
    &lt;div id=&#34;exploit-chain&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;
    
    &lt;span
        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100&#34;&gt;
        &lt;a class=&#34;group-hover:text-primary-300 dark:group-hover:text-neutral-700 !no-underline&#34; href=&#34;#exploit-chain&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;
    &lt;/span&gt;        
    
&lt;/h2&gt;
&lt;p&gt;整体利用链分为六个阶段：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  [Stage 1: Mount]      unshare(USER|NS) + loop bind multi.img + mount kbfs
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                  |
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  [Stage 2: Window A]   mmap 64MB Read-Only Window A (allocates 1 page)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                  |
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  [Stage 3: Interleave] 64 rounds: fork child (capset -&amp;gt; new cred)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                 + parent mmaps 3 x 2MB B blocks (MADV_DONTFORK)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                  |
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  [Stage 4: Locate]     Scan A for B[i] markers (&amp;#34;L4MK&amp;#34;), children task_struct,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                        target cred page (coff), and compute V_A = C - coff
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                  |
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  [Stage 5: Filter B]   Pick safe B[pick]: covers coff, small delta (coff - X),
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                        excludes kb_vma / root / task_struct / mm / files pages
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                  |
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  [Stage 6: Reclaim]    Fork sender -&amp;gt; Parent close+munmap B[pick] (Order-9 free)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                        -&amp;gt; Sender sprays 4KB msg_msg until A[coff+8] == 0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                        -&amp;gt; Wake target child to read /flag into 9p share
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 class=&#34;relative group&#34;&gt;Stage 1: 镜像构造与 Userns 无特权挂载 
    &lt;div id=&#34;stage-1-镜像构造与-userns-无特权挂载&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;
    
    &lt;span
        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100&#34;&gt;
        &lt;a class=&#34;group-hover:text-primary-300 dark:group-hover:text-neutral-700 !no-underline&#34; href=&#34;#stage-1-%e9%95%9c%e5%83%8f%e6%9e%84%e9%80%a0%e4%b8%8e-userns-%e6%97%a0%e7%89%b9%e6%9d%83%e6%8c%82%e8%bd%bd&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;
    &lt;/span&gt;        
    
&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;构造特征镜像&lt;/strong&gt;：创建包含单个文件 &lt;code&gt;f&lt;/code&gt; 的镜像 &lt;code&gt;multi.img&lt;/code&gt;，将 &lt;code&gt;i_size&lt;/code&gt; 设为 &lt;code&gt;16&lt;/code&gt;（保证 &lt;code&gt;max_size = 0x1000&lt;/code&gt;，每次 &lt;code&gt;mmap&lt;/code&gt; 仅分配 1 个物理页）。同时在镜像内填充 250 个数据块，第 &lt;code&gt;i&lt;/code&gt; 块头部写入 16 字节特征标记 &lt;code&gt;&amp;quot;L4MK&amp;quot; + u32(i) + &amp;quot;ZZZZZZZZ&amp;quot;&lt;/code&gt;，偏移 16 字节之后全部填充 &lt;code&gt;0xAA&lt;/code&gt;。
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;区分技巧&lt;/strong&gt;：当驱动建立映射 &lt;code&gt;B[i]&lt;/code&gt;（传入页偏移 &lt;code&gt;pgoff = i&lt;/code&gt;）时，只会把第 &lt;code&gt;i&lt;/code&gt; 块的前 16 字节拷进新分配的清零页（&lt;code&gt;__GFP_ZERO&lt;/code&gt;），因此真实的 &lt;code&gt;B[i]&lt;/code&gt; 物理页在偏移 16 处为 &lt;code&gt;0x00&lt;/code&gt;；而镜像文件本身的 Page Cache 页在偏移 16 处为 &lt;code&gt;0xAA&lt;/code&gt;。扫描时判断 &lt;code&gt;q[16] == 0&lt;/code&gt; 即可精准识别 &lt;code&gt;B[i]&lt;/code&gt; 的物理页。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;命名空间挂载&lt;/strong&gt;：通过 &lt;code&gt;unshare(CLONE_NEWUSER | CLONE_NEWNS)&lt;/code&gt; 创建非特权用户与挂载命名空间，将容器内 UID/GID &lt;code&gt;0&lt;/code&gt; 映射至当前用户的 &lt;code&gt;1000&lt;/code&gt;，绑定 &lt;code&gt;/dev/loopN&lt;/code&gt; 后挂载 &lt;code&gt;kbfs&lt;/code&gt;。&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 class=&#34;relative group&#34;&gt;Stage 2: 建立 64MB 物理只读窗口 A 
    &lt;div id=&#34;stage-2-建立-64mb-物理只读窗口-a&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;
    
    &lt;span
        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100&#34;&gt;
        &lt;a class=&#34;group-hover:text-primary-300 dark:group-hover:text-neutral-700 !no-underline&#34; href=&#34;#stage-2-%e5%bb%ba%e7%ab%8b-64mb-%e7%89%a9%e7%90%86%e5%8f%aa%e8%af%bb%e7%aa%97%e5%8f%a3-a&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;
    &lt;/span&gt;        
    
&lt;/h3&gt;
&lt;p&gt;打开挂载目录下的 &lt;code&gt;/tmp/l4mnt/f&lt;/code&gt;，调用 &lt;code&gt;mmap&lt;/code&gt; 建立长度 &lt;code&gt;AL = 64MB&lt;/code&gt; 的私有只读映射 &lt;code&gt;A&lt;/code&gt;。此时驱动仅分配了 1 页，但我们将该页后方 64MB 的物理内存尽收眼底。&lt;/p&gt;

&lt;h3 class=&#34;relative group&#34;&gt;Stage 3: 交错分配布局物理内存 
    &lt;div id=&#34;stage-3-交错分配布局物理内存&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;
    
    &lt;span
        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100&#34;&gt;
        &lt;a class=&#34;group-hover:text-primary-300 dark:group-hover:text-neutral-700 !no-underline&#34; href=&#34;#stage-3-%e4%ba%a4%e9%94%99%e5%88%86%e9%85%8d%e5%b8%83%e5%b1%80%e7%89%a9%e7%90%86%e5%86%85%e5%ad%98&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;
    &lt;/span&gt;        
    
&lt;/h3&gt;
&lt;p&gt;为了让目标 &lt;code&gt;cred&lt;/code&gt; 页刚好落在某个 &lt;code&gt;B[i]&lt;/code&gt; 页后方不远处（满足 &lt;code&gt;X[i] &amp;lt; coff &amp;lt; X[i] + 2MB&lt;/code&gt; 且间距 &lt;code&gt;delta&lt;/code&gt; 尽可能小），不能先集中 &lt;code&gt;fork&lt;/code&gt; 再集中映射 &lt;code&gt;B&lt;/code&gt;，否则两类物理页会分属两个相距甚远的物理簇。&lt;/p&gt;
&lt;p&gt;这里采用 &lt;strong&gt;64 轮交错分配&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;子进程耗尽现有 Slab 并保持新 &lt;code&gt;cred&lt;/code&gt; 页&lt;/strong&gt;：每轮 &lt;code&gt;fork&lt;/code&gt; 一个子进程。子进程先卸载从父进程继承的所有前置 &lt;code&gt;B&lt;/code&gt; 映射，然后调用 &lt;code&gt;capset()&lt;/code&gt; 写入唯一的 &lt;code&gt;inheritable&lt;/code&gt; 值。&lt;code&gt;capset()&lt;/code&gt; 会强制触发 &lt;code&gt;prepare_creds()&lt;/code&gt; 分配新 &lt;code&gt;cred&lt;/code&gt;，64 个子进程同时存活会迫使 &lt;code&gt;cred_jar&lt;/code&gt; 向 Buddy 批发全新的 Slab 页。随后子进程通过管道向父进程上报自己的 PID，并在共享内存数组 &lt;code&gt;gost[idx]&lt;/code&gt; 上自旋等待。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;父进程穿插建立 &lt;code&gt;B&lt;/code&gt; 映射&lt;/strong&gt;：每 &lt;code&gt;fork&lt;/code&gt; 完一个子进程，父进程紧接着建立 3 个映射长度为 &lt;code&gt;BL = 2MB&lt;/code&gt; 的 &lt;code&gt;B[i]&lt;/code&gt;（文件偏移设为 &lt;code&gt;i * 4096&lt;/code&gt; 以加载对应块的 &lt;code&gt;&amp;quot;L4MK&amp;quot;&lt;/code&gt; 标记），并立即对 &lt;code&gt;B[i]&lt;/code&gt; 调用 &lt;code&gt;madvise(..., MADV_DONTFORK)&lt;/code&gt; 防止后续 &lt;code&gt;fork&lt;/code&gt; 的子进程继承该 VMA 引用。&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 class=&#34;relative group&#34;&gt;Stage 4: 扫描窗口 A 建立全局坐标 
    &lt;div id=&#34;stage-4-扫描窗口-a-建立全局坐标&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;
    
    &lt;span
        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100&#34;&gt;
        &lt;a class=&#34;group-hover:text-primary-300 dark:group-hover:text-neutral-700 !no-underline&#34; href=&#34;#stage-4-%e6%89%ab%e6%8f%8f%e7%aa%97%e5%8f%a3-a-%e5%bb%ba%e7%ab%8b%e5%85%a8%e5%b1%80%e5%9d%90%e6%a0%87&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;
    &lt;/span&gt;        
    
&lt;/h3&gt;
&lt;p&gt;交错分配完成后，父进程在 64MB 窗口 &lt;code&gt;A&lt;/code&gt; 内执行三趟扫描（相关结构体偏移基于 Linux 6.7.9 &lt;code&gt;vmlinux&lt;/code&gt;）：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;定位所有 &lt;code&gt;B[i]&lt;/code&gt; 的偏移 &lt;code&gt;X[i]&lt;/code&gt;&lt;/strong&gt;：按 4KB 页边界扫描 &lt;code&gt;&amp;quot;L4MK&amp;quot;&lt;/code&gt; 签名且偏移 16 字节处为 &lt;code&gt;0x00&lt;/code&gt; 的页面，读出编号 &lt;code&gt;i&lt;/code&gt; 并记录 &lt;code&gt;X[i] = offset&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;收集所有候选 &lt;code&gt;kb_vma&lt;/code&gt;&lt;/strong&gt;：按 8 字节步长扫描满足 &lt;code&gt;{页对齐内核指针 v, 0x200000}&lt;/code&gt; 的二元组，保存其虚拟地址 &lt;code&gt;v&lt;/code&gt; 和在 &lt;code&gt;A&lt;/code&gt; 中的偏移 &lt;code&gt;off&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;定位子进程 &lt;code&gt;task_struct&lt;/code&gt; 与 &lt;code&gt;cred&lt;/code&gt; 页&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;父进程在初始化时已通过 &lt;code&gt;prctl(PR_SET_NAME)&lt;/code&gt; 将进程名设为独特的 &lt;code&gt;&amp;quot;l4fc-&amp;lt;pid&amp;gt;&amp;quot;&lt;/code&gt;（子进程会自动继承）。&lt;/li&gt;
&lt;li&gt;在 &lt;code&gt;A&lt;/code&gt; 中搜索该字符串（对应 &lt;code&gt;task_struct + 0x710&lt;/code&gt; 的 &lt;code&gt;comm&lt;/code&gt; 字段），反推 &lt;code&gt;task_struct&lt;/code&gt; 起始偏移 &lt;code&gt;t&lt;/code&gt;，校验 &lt;code&gt;+0x528&lt;/code&gt; (&lt;code&gt;pid&lt;/code&gt;) 与 &lt;code&gt;+0x52c&lt;/code&gt; (&lt;code&gt;tgid&lt;/code&gt;) 是否匹配子进程 PID，并读取 &lt;code&gt;+0x700&lt;/code&gt; 处的 &lt;code&gt;task-&amp;gt;cred&lt;/code&gt; 指针 &lt;code&gt;C&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;提取页内偏移 &lt;code&gt;co = C &amp;amp; 0xfff&lt;/code&gt;（要求 &lt;code&gt;co &amp;gt;= 0x30&lt;/code&gt; 以避开 &lt;code&gt;msg_msg&lt;/code&gt; 头）。遍历 &lt;code&gt;A&lt;/code&gt; 中每个物理页的 &lt;code&gt;+co&lt;/code&gt; 处，检查是否符合 &lt;code&gt;struct cred&lt;/code&gt; 特征（&lt;code&gt;0 &amp;lt; usage &amp;lt;= 100000&lt;/code&gt;、&lt;code&gt;uid..fsgid&lt;/code&gt; 8 个整型字段均为宿主机映射值 &lt;code&gt;1000&lt;/code&gt; 或 &lt;code&gt;0&lt;/code&gt;、&lt;code&gt;+0x90&lt;/code&gt; 处的 &lt;code&gt;user_ns&lt;/code&gt; 为内核指针）。&lt;/li&gt;
&lt;li&gt;匹配成功后即得到目标 &lt;code&gt;cred&lt;/code&gt; 在 &lt;code&gt;A&lt;/code&gt; 中的总偏移 &lt;code&gt;coff = page_offset + co&lt;/code&gt;，进而直接算出窗口基址的内核虚拟地址：&lt;code&gt;V_A = C - coff&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 class=&#34;relative group&#34;&gt;Stage 5: 筛选安全且距离最近的 &lt;code&gt;B[pick]&lt;/code&gt; 
    &lt;div id=&#34;stage-5-筛选安全且距离最近的-bpick&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;
    
    &lt;span
        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100&#34;&gt;
        &lt;a class=&#34;group-hover:text-primary-300 dark:group-hover:text-neutral-700 !no-underline&#34; href=&#34;#stage-5-%e7%ad%9b%e9%80%89%e5%ae%89%e5%85%a8%e4%b8%94%e8%b7%9d%e7%a6%bb%e6%9c%80%e8%bf%91%e7%9a%84-bpick&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;
    &lt;/span&gt;        
    
&lt;/h3&gt;
&lt;p&gt;遍历所有已定位的子进程目标与映射 &lt;code&gt;B[j]&lt;/code&gt;，挑出满足以下全部安全约束且 &lt;code&gt;delta = coff - X[j]&lt;/code&gt; 最小的组合：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;覆盖检查&lt;/strong&gt;：满足 &lt;code&gt;X[j] &amp;lt; coff &amp;amp;&amp;amp; coff &amp;lt; X[j] + 2MB&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;排除 &lt;code&gt;kb_vma&lt;/code&gt; 与 &lt;code&gt;root&lt;/code&gt; 自毁&lt;/strong&gt;：计算 &lt;code&gt;B[j]&lt;/code&gt; 对应的内核虚拟地址 &lt;code&gt;V_B = V_A + X[j]&lt;/code&gt;，在候选 &lt;code&gt;kb_vma&lt;/code&gt; 列表中查找 &lt;code&gt;v == V_B&lt;/code&gt; 的项。若找到，检查该 &lt;code&gt;kb_vma&lt;/code&gt; 自身偏移 &lt;code&gt;o&lt;/code&gt; 以及链表头 &lt;code&gt;R = list.next - 0x10&lt;/code&gt; 换算后的偏移 &lt;code&gt;R - V_A&lt;/code&gt; 是否落在 &lt;code&gt;[X[j], X[j] + 2MB)&lt;/code&gt; 内；若落入则直接排除，避免 &lt;code&gt;kfree(kb_vma)&lt;/code&gt; 触发 SLUB &lt;code&gt;WARN&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;关键进程结构体保护&lt;/strong&gt;：当 &lt;code&gt;delta &amp;gt; 0x8000&lt;/code&gt; 时，回收过程会覆盖较多前置页。此时额外检查目标子进程、父进程以及后续 &lt;code&gt;sender&lt;/code&gt; 进程的 &lt;code&gt;task_struct&lt;/code&gt; 所在页，及其核心指针（&lt;code&gt;mm&lt;/code&gt; &lt;code&gt;+0x4a8&lt;/code&gt;、&lt;code&gt;fs&lt;/code&gt; &lt;code&gt;+0x740&lt;/code&gt;、&lt;code&gt;files&lt;/code&gt; &lt;code&gt;+0x748&lt;/code&gt;、&lt;code&gt;nsproxy&lt;/code&gt; &lt;code&gt;+0x758&lt;/code&gt;、&lt;code&gt;signal&lt;/code&gt; &lt;code&gt;+0x760&lt;/code&gt;、&lt;code&gt;sighand&lt;/code&gt; &lt;code&gt;+0x768&lt;/code&gt;）指向的页是否落在 &lt;code&gt;[X[j], X[j] + 2MB)&lt;/code&gt; 内，若有重合则跳过。&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 class=&#34;relative group&#34;&gt;Stage 6: 触发越界释放与 &lt;code&gt;msg_msg&lt;/code&gt; 原地提权 
    &lt;div id=&#34;stage-6-触发越界释放与-msg_msg-原地提权&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;
    
    &lt;span
        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100&#34;&gt;
        &lt;a class=&#34;group-hover:text-primary-300 dark:group-hover:text-neutral-700 !no-underline&#34; href=&#34;#stage-6-%e8%a7%a6%e5%8f%91%e8%b6%8a%e7%95%8c%e9%87%8a%e6%94%be%e4%b8%8e-msg_msg-%e5%8e%9f%e5%9c%b0%e6%8f%90%e6%9d%83&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;
    &lt;/span&gt;        
    
&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;构造伪造页数据&lt;/strong&gt;：将目标 &lt;code&gt;cred&lt;/code&gt; 所在的 4KB 页 &lt;code&gt;A + (coff &amp;amp; ~0xfff)&lt;/code&gt; 完整拷贝到本地缓冲区 &lt;code&gt;page&lt;/code&gt;，仅将 &lt;code&gt;page + co + 8&lt;/code&gt; 起始的 32 字节（即 &lt;code&gt;uid&lt;/code&gt; 到 &lt;code&gt;fsgid&lt;/code&gt; 共 8 个字段）清零，再将 &lt;code&gt;page + 0x30&lt;/code&gt; 起始的 4048 字节拷入消息正文缓冲区 &lt;code&gt;mt&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;隔离 &lt;code&gt;sender&lt;/code&gt; 进程&lt;/strong&gt;：在触发释放前，先 &lt;code&gt;fork&lt;/code&gt; 出专门负责发消息的 &lt;code&gt;sender&lt;/code&gt; 子进程（并在 &lt;code&gt;Stage 5&lt;/code&gt; 中同样将其纳入保护检查）。
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;设计考量&lt;/strong&gt;：一方面，在 2MB 物理内存被释放并覆写的窗口期内，把所有系统调用集中在独立的 &lt;code&gt;sender&lt;/code&gt; 进程中、让父进程退化为纯用户态共享内存轮询，能最大限度降低踩中损坏页崩溃的概率；另一方面，&lt;code&gt;msgsnd()&lt;/code&gt; 内部会执行 &lt;code&gt;ipcperms() -&amp;gt; in_group_p()&lt;/code&gt; 读取调用者自身的 &lt;code&gt;cred-&amp;gt;group_info&lt;/code&gt;，因此绝不能由正在被改写 &lt;code&gt;cred&lt;/code&gt; 的目标进程自己调用 &lt;code&gt;msgsnd&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;触发 Order-9 越界释放&lt;/strong&gt;：父进程执行 &lt;code&gt;close(fds[pick])&lt;/code&gt; + &lt;code&gt;munmap(B[pick], 2MB)&lt;/code&gt;。此时底层 &lt;code&gt;struct file&lt;/code&gt; 引用归零，触发 &lt;code&gt;kbfs_file_release()&lt;/code&gt; 将 &lt;code&gt;B[pick]&lt;/code&gt; 起始的 512 个物理页（包含目标 &lt;code&gt;cred&lt;/code&gt; 页）释放回 Buddy 的 &lt;code&gt;UNMOVABLE&lt;/code&gt; 链表。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;实时观测喷射与唤醒读 Flag&lt;/strong&gt;：父进程通过管道放行 &lt;code&gt;sender&lt;/code&gt;。&lt;code&gt;sender&lt;/code&gt; 循环调用 &lt;code&gt;msgget&lt;/code&gt; + &lt;code&gt;msgsnd&lt;/code&gt; 发送 4048 字节的消息。每发送一条，就通过依然存活的只读窗口 &lt;code&gt;A&lt;/code&gt; 直接检查 &lt;code&gt;*(volatile uint32_t *)(A + coff + 8) == 0&lt;/code&gt;。一旦观测到 &lt;code&gt;uid&lt;/code&gt; 变为 &lt;code&gt;0&lt;/code&gt;（实测 &lt;code&gt;delta&lt;/code&gt; 为 &lt;code&gt;0x10c0&lt;/code&gt; 时约发送 500 余条即命中），立即停止喷射并通过共享内存置位 &lt;code&gt;gost[tidx] = 1&lt;/code&gt; 唤醒目标子进程。目标子进程醒来后已是全局 root 权限，直接打开 &lt;code&gt;/flag&lt;/code&gt; 并将内容写入 9p 共享目录文件。&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 class=&#34;relative group&#34;&gt;踩坑与实战细节记录 
    &lt;div id=&#34;踩坑与实战细节记录&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;
    
    &lt;span
        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100&#34;&gt;
        &lt;a class=&#34;group-hover:text-primary-300 dark:group-hover:text-neutral-700 !no-underline&#34; href=&#34;#%e8%b8%a9%e5%9d%91%e4%b8%8e%e5%ae%9e%e6%88%98%e7%bb%86%e8%8a%82%e8%ae%b0%e5%bd%95&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;
    &lt;/span&gt;        
    
&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;close(fd)&lt;/code&gt; 与 &lt;code&gt;MADV_DONTFORK&lt;/code&gt; 的引用计数问题&lt;/strong&gt;
&lt;code&gt;kbfs_file_release()&lt;/code&gt; 只有在 &lt;code&gt;struct file&lt;/code&gt; 的引用计数彻底归零时才会执行。由于每次 &lt;code&gt;mmap&lt;/code&gt; 创建的 VMA 也会持有一份 &lt;code&gt;file&lt;/code&gt; 引用，单纯 &lt;code&gt;close(fd)&lt;/code&gt; 不会触发释放，必须配合 &lt;code&gt;munmap()&lt;/code&gt;。同理，如果在交错 &lt;code&gt;fork&lt;/code&gt; 阶段子进程继承了父进程 &lt;code&gt;B&lt;/code&gt; 的 VMA，子进程不退出就会一直占着引用计数，导致父进程 &lt;code&gt;munmap&lt;/code&gt; 时无事发生。因此父进程设置 &lt;code&gt;MADV_DONTFORK&lt;/code&gt; + 子进程主动清理前置 &lt;code&gt;fd/VMA&lt;/code&gt; 缺一不可。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;为什么不直接替换 &lt;code&gt;task-&amp;gt;cred = &amp;amp;init_cred&lt;/code&gt;？&lt;/strong&gt;
早期尝试过释放 &lt;code&gt;task_struct&lt;/code&gt; 所在页，通过 &lt;code&gt;sched_class&lt;/code&gt; 泄露 KASLR slide 后将 &lt;code&gt;task-&amp;gt;cred&lt;/code&gt; 指向 &lt;code&gt;init_cred&lt;/code&gt;。这有两个问题：一是 &lt;code&gt;task_struct&lt;/code&gt; 位于大块 Slab 中，同页往往住着 &lt;code&gt;sshd&lt;/code&gt; 等关键系统进程的 &lt;code&gt;task_struct&lt;/code&gt;，释放极易在 &lt;code&gt;mm_cid_get()&lt;/code&gt; 或 &lt;code&gt;acct_collect()&lt;/code&gt; 处引发连带 Panic；二是进程处于 User Namespace 中，直接换用 &lt;code&gt;init_cred&lt;/code&gt; 会导致安全上下文与命名空间不匹配，只原地清零自身 &lt;code&gt;cred&lt;/code&gt; 的 &lt;code&gt;uid..fsgid&lt;/code&gt; 最干净稳妥。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Order 大小的选择&lt;/strong&gt;
&lt;code&gt;vaddr&lt;/code&gt; 是按 Order 0 分配的物理页，物理地址几乎不可能自然对齐到 2MB 边界。向 &lt;code&gt;free_pages()&lt;/code&gt; 传入未对齐地址和高阶 Order 时，Buddy 在合并伙伴块（&lt;code&gt;__free_one_page&lt;/code&gt;）时阶数越高越容易触发内部校验崩溃。实测 Order 9（2MB）既能提供足够的覆盖半径，又不会在释放瞬间炸死在伙伴合并逻辑里。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SSH 管道损坏与 9p 文件落盘&lt;/strong&gt;
在测试过程中曾遇到过 &amp;ldquo;&lt;code&gt;uid&lt;/code&gt; 已经变成 0，但终端没有任何输出且随后 Panic&amp;rdquo; 的情况。排查发现是 &lt;code&gt;msg_msg&lt;/code&gt; 喷射过程中顺带覆盖了 &lt;code&gt;sshd&lt;/code&gt; 用于转发 stdout 的 &lt;code&gt;pipe_inode_info&lt;/code&gt; 页，子进程退出关闭管道时触发 &lt;code&gt;free_pipe_info()&lt;/code&gt; WARN。解决方案是让子进程读出 &lt;code&gt;/flag&lt;/code&gt; 后，第一时间写入宿主与虚拟机共享的 9p 目录（&lt;code&gt;/home/hacker/kylebotfs/level4/flag.out&lt;/code&gt;），随后直接调用 &lt;code&gt;pause()&lt;/code&gt; 挂起永不退出，彻底绕开后续清理路径。&lt;/li&gt;
&lt;/ol&gt;
</description>
      
    </item>
    
  </channel>
</rss>
