<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"
  xmlns:atom="http://www.w3.org/2005/Atom"
  xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Hc1m1</title>
    <link>https://nobb.site/</link>
    
    <atom:link href="https://nobb.site/rss.xml" rel="self" type="application/rss+xml"/>
    
    <description>水平不济整日被虐这也不会那也得学脑子太蠢天天垫底这看不懂那学不会</description>
    <pubDate>Tue, 16 Dec 2025 07:51:56 GMT</pubDate>
    <generator>http://hexo.io/</generator>
    
    <item>
      <title>IoT固件Fuzz：从Harness编写到QEMU适配</title>
      <link>https://nobb.site/2025/11/13/fuzz2/</link>
      <guid>https://nobb.site/2025/11/13/fuzz2/</guid>
      <pubDate>Thu, 13 Nov 2025 09:04:25 GMT</pubDate>
      
      <description>&lt;p&gt;本文旨在探讨一种针对 IoT 设备的 AFL++ Fuzz 新方案。&lt;/p&gt;</description>
      
      
      
      <content:encoded><![CDATA[<p>本文旨在探讨一种针对 IoT 设备的 AFL++ Fuzz 新方案。</p><span id="more"></span><h1 id="Harness-编写"><a href="#Harness-编写" class="headerlink" title="Harness 编写"></a>Harness 编写</h1><p>目前大部分 Fuzz 工具仅支持标准输入或命令行参数作为输入，而 IoT 设备 Fuzz 的主要对象为网络程序，需通过 Socket 进行输入输出，这构成了技术难点。</p><p>在掌握 Harness 编写技术后，可利用该方案对 IoT 设备的 Socket 通信程序进行 Fuzz 测试。</p><p>本文以 ASUS RT-N56U 设备为例进行阐述。目标 Fuzz 程序为 httpd，通过逆向分析可知，处理 HTTP 流程的代码位于 <code>handle_request</code> 函数中，该函数的第一个参数是 Socket 文件描述符，第二个参数是一个包含连接信息的结构体。</p><p>在 <code>handle_request</code> 函数中，通过 <code>fgets</code> 函数获取 HTTP 请求，如下所示：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">  <span class="keyword">if</span> ( !fgets(v95, <span class="number">4096</span>, a1) )</span><br><span class="line">  &#123;</span><br><span class="line">    v4 = <span class="string">&quot;Bad Request&quot;</span>;</span><br><span class="line">    v5 = <span class="string">&quot;No request found.&quot;</span>;</span><br><span class="line">LABEL_14:</span><br><span class="line">    v6 = <span class="number">400</span>;</span><br><span class="line">LABEL_15:</span><br><span class="line">    v7 = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">return</span> send_error(v6, v4, v7, v5, a1);</span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure><p>基于此，可以构建如下思路：</p><ol><li>Hook httpd 的 main 函数。</li><li>将 HTTP 请求置于文件中，文件名作为 httpd 参数输入。</li><li>伪造一个可读写的文件描述符，将输入的 HTTP 请求写入该描述符，供 httpd 读取。</li><li>伪造 <code>handle_request</code> 所需的参数。</li></ol><p>基于上述逻辑，编写 Fuzz 函数如下：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">void</span> <span class="title function_">fuzz</span><span class="params">(<span class="type">const</span> <span class="type">char</span> *filename)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="type">int</span> memfd;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;do fuzz(%s)\n&quot;</span>, filename);</span><br><span class="line">    chdir(currentPWD);</span><br><span class="line"></span><br><span class="line">    memfd = create_memfd_from_file(filename);</span><br><span class="line">    <span class="keyword">if</span> (memfd == <span class="number">-1</span>) &#123;</span><br><span class="line">        perror(<span class="string">&quot;create_memfd_from_file error.&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    FILE* single_handle = fdopen(memfd, <span class="string">&quot;r+&quot;</span>);</span><br><span class="line">    <span class="keyword">if</span> (!single_handle) &#123;</span><br><span class="line">        perror(<span class="string">&quot;fdopen error.&quot;</span>);</span><br><span class="line">        close(memfd);</span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    chdir(<span class="string">&quot;/www&quot;</span>);</span><br><span class="line">    <span class="type">conn_item_t</span> fake_item;</span><br><span class="line">    fake_item.fd = memfd;</span><br><span class="line">    fake_item.usa.sa_in.sin_family = AF_INET;</span><br><span class="line">    fake_item.usa.sa_in.sin_port = htons(<span class="number">12345</span>);</span><br><span class="line">    inet_pton(AF_INET, <span class="string">&quot;192.168.1.10&quot;</span>, &amp;fake_item.usa.sa_in.sin_addr);</span><br><span class="line">    handle_request(single_handle, &amp;fake_item);</span><br><span class="line">    <span class="keyword">if</span> (getenv(<span class="string">&quot;DEBUG&quot;</span>)) &#123;</span><br><span class="line">        <span class="keyword">if</span> (fseek(single_handle, <span class="number">0</span>, SEEK_SET) != <span class="number">0</span>) &#123;</span><br><span class="line">            perror(<span class="string">&quot;fseek single_handle before dump&quot;</span>);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="type">char</span> buf[<span class="number">4096</span>];</span><br><span class="line">            <span class="type">int</span> write_failed = <span class="number">0</span>;</span><br><span class="line">            <span class="keyword">for</span> (;;) &#123;</span><br><span class="line">                <span class="type">size_t</span> r = fread(buf, <span class="number">1</span>, <span class="keyword">sizeof</span>(buf), single_handle);</span><br><span class="line">                <span class="keyword">if</span> (r == <span class="number">0</span>) &#123;</span><br><span class="line">                    <span class="keyword">if</span> (ferror(single_handle)) &#123;</span><br><span class="line">                        perror(<span class="string">&quot;fread single_handle dump&quot;</span>);</span><br><span class="line">                        clearerr(single_handle);</span><br><span class="line">                    &#125;</span><br><span class="line">                    <span class="keyword">break</span>;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="type">size_t</span> off = <span class="number">0</span>;</span><br><span class="line">                <span class="keyword">while</span> (off &lt; r) &#123;</span><br><span class="line">                    <span class="type">ssize_t</span> w = write(STDOUT_FILENO, buf + off, r - off);</span><br><span class="line">                    <span class="keyword">if</span> (w &lt; <span class="number">0</span>) &#123;</span><br><span class="line">                        perror(<span class="string">&quot;write stdout dump&quot;</span>);</span><br><span class="line">                        write_failed = <span class="number">1</span>;</span><br><span class="line">                        <span class="keyword">break</span>;</span><br><span class="line">                    &#125;</span><br><span class="line">                    off += (<span class="type">size_t</span>)w;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">if</span> (write_failed) &#123;</span><br><span class="line">                    <span class="keyword">break</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (write_failed) &#123;</span><br><span class="line">                <span class="comment">// 如果写失败，确保后续读取状态被清理</span></span><br><span class="line">                clearerr(single_handle);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>首先，Fuzz 函数的参数源于命令行参数。接着，编写 <code>create_memfd_from_file</code> 函数，将文件内容转换为可读写的文件描述符，实现逻辑如下：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 兼容封装：优先使用 memfd_create 系统调用；不可用时回退到匿名临时文件</span></span><br><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">memfd_create_compat</span><span class="params">(<span class="type">const</span> <span class="type">char</span> *name, <span class="type">unsigned</span> <span class="type">int</span> flags)</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="meta">#<span class="keyword">ifdef</span> SYS_memfd_create</span></span><br><span class="line">    <span class="keyword">return</span> (<span class="type">int</span>)syscall(SYS_memfd_create, name, flags);</span><br><span class="line"><span class="meta">#<span class="keyword">elif</span> defined(__NR_memfd_create)</span></span><br><span class="line">    <span class="keyword">return</span> (<span class="type">int</span>)syscall(__NR_memfd_create, name, flags);</span><br><span class="line"><span class="meta">#<span class="keyword">else</span></span></span><br><span class="line">    <span class="comment">// Fallback: 使用匿名临时文件模拟（并非真正的 memfd，但可读写且不落磁盘路径）</span></span><br><span class="line">    FILE *tf = tmpfile();</span><br><span class="line">    <span class="keyword">if</span> (!tf) <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">    <span class="type">int</span> fd = dup(fileno(tf));</span><br><span class="line">    fclose(tf);</span><br><span class="line">    <span class="keyword">return</span> fd;</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 从文件读入全部内容到匿名内存文件（memfd），并回到偏移 0，返回该 fd</span></span><br><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">create_memfd_from_file</span><span class="params">(<span class="type">const</span> <span class="type">char</span> *filename)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="type">int</span> fd = memfd_create_compat(<span class="string">&quot;harness_mem&quot;</span>, MFD_CLOEXEC);</span><br><span class="line">    <span class="keyword">if</span> (fd &lt; <span class="number">0</span>) &#123;</span><br><span class="line">        perror(<span class="string">&quot;memfd_create&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="type">int</span> file_fd = open(filename, O_RDONLY);</span><br><span class="line">    <span class="keyword">if</span> (file_fd &lt; <span class="number">0</span>) &#123;</span><br><span class="line">        perror(<span class="string">&quot;open file&quot;</span>);</span><br><span class="line">        close(fd);</span><br><span class="line">        <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="type">char</span> buf[<span class="number">8192</span>];</span><br><span class="line">    <span class="keyword">for</span> (;;) &#123;</span><br><span class="line">        <span class="type">ssize_t</span> r = read(file_fd, buf, <span class="keyword">sizeof</span>(buf));</span><br><span class="line">        <span class="keyword">if</span> (r == <span class="number">0</span>) <span class="keyword">break</span>; <span class="comment">// EOF</span></span><br><span class="line">        <span class="keyword">if</span> (r &lt; <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="keyword">if</span> (errno == EINTR) <span class="keyword">continue</span>;</span><br><span class="line">            perror(<span class="string">&quot;read file&quot;</span>);</span><br><span class="line">            close(file_fd);</span><br><span class="line">            close(fd);</span><br><span class="line">            <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="type">ssize_t</span> off = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">while</span> (off &lt; r) &#123;</span><br><span class="line">            <span class="type">ssize_t</span> w = write(fd, buf + off, r - off);</span><br><span class="line">            <span class="keyword">if</span> (w &lt; <span class="number">0</span>) &#123;</span><br><span class="line">                <span class="keyword">if</span> (errno == EINTR) <span class="keyword">continue</span>;</span><br><span class="line">                perror(<span class="string">&quot;write memfd&quot;</span>);</span><br><span class="line">                close(file_fd);</span><br><span class="line">                close(fd);</span><br><span class="line">                <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            off += w;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    close(file_fd);</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">if</span> (lseek(fd, <span class="number">0</span>, SEEK_SET) &lt; <span class="number">0</span>) &#123;</span><br><span class="line">        perror(<span class="string">&quot;lseek memfd&quot;</span>);</span><br><span class="line">        close(fd);</span><br><span class="line">        <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> fd;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>随后，使用 <code>fdopen</code> 函数将 <code>int</code> 类型的文件描述符转换为 <code>FILE*</code> 类型。最后构造 <code>fake_item</code> 结构体，作为 <code>handle_request</code> 的第二个参数，<code>fake_item</code> 结构体定义如下：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">qm_trace</span> &#123;</span></span><br><span class="line"><span class="type">char</span> * lastfile;</span><br><span class="line"><span class="type">int</span> lastline;</span><br><span class="line"><span class="type">char</span> * prevfile;</span><br><span class="line"><span class="type">int</span> prevline;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span>TRACEBUFstruct qm_trace trace;</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span>TAILQ_ENTRY(type)\</span></span><br><span class="line"><span class="meta">struct &#123;\</span></span><br><span class="line"><span class="meta">struct type *tqe_next;<span class="comment">/* next element */</span>\</span></span><br><span class="line"><span class="meta">struct type **tqe_prev;<span class="comment">/* address of previous next element */</span>\</span></span><br><span class="line"><span class="meta">TRACEBUF\</span></span><br><span class="line"><span class="meta">&#125;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">union</span> &#123;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">sockaddr</span> <span class="title">sa</span>;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">sockaddr_in</span> <span class="title">sa_in</span>;</span></span><br><span class="line"><span class="meta">#<span class="keyword">if</span> defined (USE_IPV6)</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">sockaddr_in6</span> <span class="title">sa_in6</span>;</span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line">&#125; usockaddr;</span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span> <span class="title">conn_item</span> &#123;</span></span><br><span class="line">    TAILQ_ENTRY(conn_item) entry;</span><br><span class="line">    <span class="type">int</span> fd;</span><br><span class="line"><span class="meta">#<span class="keyword">if</span> defined (SUPPORT_HTTPS)</span></span><br><span class="line">    <span class="type">int</span> ssl;</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line">    usockaddr usa;</span><br><span class="line">&#125; <span class="type">conn_item_t</span>;</span><br></pre></td></tr></table></figure><p>此外，在调试模式下，还需支持输出 HTTP 请求结果。</p><p>Hook main 函数的方法如下：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> __uClibc_main(</span><br><span class="line">    <span class="type">int</span> (*main)(<span class="type">int</span>, <span class="type">char</span> **, <span class="type">char</span> **),</span><br><span class="line">    <span class="type">int</span> argc,</span><br><span class="line">    <span class="type">char</span> **argv,</span><br><span class="line">    <span class="type">void</span> (*app_init)(<span class="type">void</span>),</span><br><span class="line">    <span class="type">void</span> (*app_fini)(<span class="type">void</span>),</span><br><span class="line">    <span class="type">void</span> (*rtld_fini)(<span class="type">void</span>),</span><br><span class="line">    <span class="type">void</span> *stack_end) &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// debug</span></span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;do __uClibc_main(argc=%d, argv=%p)\n&quot;</span>, argc, argv);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (!uClibc_main_orig) &#123;</span><br><span class="line">        LOG(<span class="string">&quot;dlsym(RTLD_NEXT, __uClibc_main_orig) failed: %s\n&quot;</span>, dlerror());</span><br><span class="line">        _exit(<span class="number">1</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    LOG(<span class="string">&quot;uClibc_main_orig = %p\n&quot;</span>, uClibc_main_orig);</span><br><span class="line">    <span class="comment">// ... and call it with our custom main function</span></span><br><span class="line">    <span class="keyword">return</span> uClibc_main_orig(main_hook, argc, argv, app_init, app_fini, rtld_fini, stack_end);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 在 .init 段执行的 constructor</span></span><br><span class="line">__attribute__((constructor))</span><br><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">harness_init</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">    LOG(<span class="string">&quot;constructor executed: harness.so loaded\n&quot;</span>);</span><br><span class="line">    uClibc_main_orig = dlsym(RTLD_NEXT, <span class="string">&quot;__uClibc_main&quot;</span>);</span><br><span class="line">    <span class="keyword">if</span> (!uClibc_main_orig) &#123;</span><br><span class="line">        LOG(<span class="string">&quot;dlsym(RTLD_NEXT, __uClibc_main_orig) failed: %s\n&quot;</span>, dlerror());</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        LOG(<span class="string">&quot;dlsym(RTLD_NEXT, __uClibc_main_orig) success: %p\n&quot;</span>, uClibc_main_orig);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>由于大多数 IoT 设备使用 uClibc 库，因此需要 Hook <code>__uClibc_main</code> 函数。</p><p>针对不同设备，需根据具体情况和架构进行差异化处理。在本例中，目标 httpd 程序在监听 Web 端口之前，也会执行初始化操作，如设置管理员账号密码等，因此需执行同样的初始化动作。如下所示：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">typedef</span> <span class="type">void</span>* (*HANDLE_RESET_LOGIN_DATA) (<span class="type">void</span>);</span><br><span class="line">HANDLE_RESET_LOGIN_DATA handle_reset_login_data = (HANDLE_RESET_LOGIN_DATA) <span class="number">0x402ED8</span>;</span><br><span class="line"><span class="keyword">typedef</span> <span class="type">void</span>* (*HANDLE_LOAD_NVRAM_AUTH) (<span class="type">void</span>);</span><br><span class="line">HANDLE_LOAD_NVRAM_AUTH handle_load_nvram_auth = (HANDLE_LOAD_NVRAM_AUTH) <span class="number">0x402DE0</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">init</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="comment">// httpd处理请求前的初始化</span></span><br><span class="line">    handle_reset_login_data();</span><br><span class="line">    handle_load_nvram_auth();</span><br><span class="line">    currentPWD = <span class="built_in">malloc</span>(MAX_PATH);</span><br><span class="line">    <span class="keyword">if</span> (getcwd(currentPWD, MAX_PATH) != <span class="literal">NULL</span>) &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;Current working directory: %s\n&quot;</span>, currentPWD);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        perror(<span class="string">&quot;Error getting current working directory&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Harness 编写思路至此结束，后续需针对具体 IoT 程序进行差异化操作，以确保程序正常运行。</p><h1 id="处理-Fuzz-程序依赖问题"><a href="#处理-Fuzz-程序依赖问题" class="headerlink" title="处理 Fuzz 程序依赖问题"></a>处理 Fuzz 程序依赖问题</h1><p>本例中，httpd 仅需解决 NVRAM 依赖问题。IoT 设备通常使用 NVRAM 存储配置信息，但运行 Fuzz 的主机通常不包含 NVRAM 驱动，不过部分操作系统可能存在 NVRAM 驱动包，可自行安装。为使 httpd 正常使用 NVRAM，存在以下三种方案：</p><ol><li>若操作系统存在 NVRAM 包，可直接安装并尝试适配使用，该方案最为简便。</li><li>当默认 NVRAM 驱动与 IoT 设备不匹配时，可通过逆向 IoT 固件中的 NVRAM 驱动，参考其代码，借助 AI 编写适配当前机器的 NVRAM 驱动。</li><li>可通过逆向 IoT 固件中的 libnvram 共享库，参考其代码，Hook 核心函数，如：<code>nvram_get</code>, <code>nvram_set</code> 等。</li></ol><p>接下来，需获取设备的配置文件，或导出设备上的 NVRAM 数据并导入当前机器，以实现更真实的仿真。</p><p>鉴于代码篇幅较长，此处仅展示用法，如下所示：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">hexdump -C /var/lib/soft_nvram.bin |<span class="built_in">tail</span></span></span><br><span class="line">00001fd0  74 73 70 3d 30 00 6e 66  5f 61 6c 67 5f 73 69 70  |tsp=0.nf_alg_sip|</span><br><span class="line">00001fe0  3d 30 00 70 72 65 66 65  72 72 65 64 5f 6c 61 6e  |=0.preferred_lan|</span><br><span class="line">00001ff0  67 3d 45 4e 00 6c 6f 67  69 6e 5f 74 69 6d 65 73  |g=EN.login_times|</span><br><span class="line">00002000  74 61 6d 70 3d 33 33 30  38 38 35 39 00 00 00 00  |tamp=3308859....|</span><br><span class="line">00002010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|</span><br><span class="line">*</span><br><span class="line">00010000</span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">make</span></span><br><span class="line">make -C /lib/modules/6.1.0-37-amd64/build M=/home/debian/nvram_driver modules</span><br><span class="line">make[1]: Entering directory &#x27;/usr/src/linux-headers-6.1.0-37-amd64&#x27;</span><br><span class="line">  CC [M]  /home/debian/nvram_driver/soft_nvram.o</span><br><span class="line">  MODPOST /home/debian/nvram_driver/Module.symvers</span><br><span class="line">  CC [M]  /home/debian/nvram_driver/soft_nvram.mod.o</span><br><span class="line">  LD [M]  /home/debian/nvram_driver/soft_nvram.ko</span><br><span class="line">  BTF [M] /home/debian/nvram_driver/soft_nvram.ko</span><br><span class="line">Skipping BTF generation for /home/debian/nvram_driver/soft_nvram.ko due to unavailability of vmlinux</span><br><span class="line">make[1]: Leaving directory &#x27;/usr/src/linux-headers-6.1.0-37-amd64&#x27;</span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash"><span class="built_in">sudo</span> insmod soft_nvram.ko backing_path=/var/lib/soft_nvram.bin</span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash"><span class="built_in">cd</span> romfs</span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash"><span class="built_in">export</span> QEMU_LD_PREFIX=<span class="string">&quot;.&quot;</span></span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">afl-qemu-trace ./usr/sbin/nvram get http_username</span></span><br><span class="line">./usr/sbin/nvram: cache &#x27;/etc/ld.so.cache&#x27; is corrupt</span><br><span class="line">admin</span><br></pre></td></tr></table></figure><h2 id="Patch-QEMU"><a href="#Patch-QEMU" class="headerlink" title="Patch QEMU"></a>Patch QEMU</h2><p>通常情况下，上述 NVRAM 程序尚无法正常运行，因仍缺关键一步。该架构下的 NVRAM 驱动调用需使用 <code>ioctl</code>，而 QEMU 对 <code>ioctl</code> 调用有独立处理逻辑，并非默认使用系统调用。QEMU 默认无法识别 NVRAM 的 ioctl 调用方法。因此，需对 QEMU 进行相应修改，经研究，较为简便的修改方案如下：</p><figure class="highlight patch"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h</span></span><br><span class="line"><span class="comment">index 3b41128fd7..e8b636badc 100644</span></span><br><span class="line"><span class="comment">--- a/linux-user/ioctls.h</span></span><br><span class="line"><span class="comment">+++ b/linux-user/ioctls.h</span></span><br><span class="line"><span class="meta">@@ -758,3 +758,17 @@</span></span><br><span class="line"> #ifdef TUNGETDEVNETNS</span><br><span class="line">   IOCTL(TUNGETDEVNETNS,  IOC_R, TYPE_NULL)</span><br><span class="line"> #endif</span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+// nvram</span></span><br><span class="line"><span class="addition">+#define NVRAM_IOCTL_CLEAR 0x14</span></span><br><span class="line"><span class="addition">+#define TARGET_NVRAM_IOCTL_CLEAR NVRAM_IOCTL_CLEAR</span></span><br><span class="line"><span class="addition">+#define NVRAM_IOCTL_COMMIT  0xA</span></span><br><span class="line"><span class="addition">+#define TARGET_NVRAM_IOCTL_COMMIT NVRAM_IOCTL_COMMIT</span></span><br><span class="line"><span class="addition">+#define NVRAM_IOCTL_GET   0x28</span></span><br><span class="line"><span class="addition">+#define TARGET_NVRAM_IOCTL_GET NVRAM_IOCTL_GET</span></span><br><span class="line"><span class="addition">+#define NVRAM_IOCTL_SET   0x1e</span></span><br><span class="line"><span class="addition">+#define TARGET_NVRAM_IOCTL_SET NVRAM_IOCTL_SET</span></span><br><span class="line"><span class="addition">+IOCTL(NVRAM_IOCTL_COMMIT, 0, TYPE_NULL)</span></span><br><span class="line"><span class="addition">+IOCTL(NVRAM_IOCTL_CLEAR,  0, TYPE_NULL)</span></span><br><span class="line"><span class="addition">+IOCTL(NVRAM_IOCTL_SET, IOC_W, MK_PTR(MK_STRUCT(STRUCT_anvram_ioctl_t)))</span></span><br><span class="line"><span class="addition">+IOCTL(NVRAM_IOCTL_GET, IOC_RW, MK_PTR(MK_STRUCT(STRUCT_anvram_ioctl_t)))</span></span><br><span class="line"></span><br><span class="line"><span class="comment">diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h</span></span><br><span class="line"><span class="comment">index 6dd7a80ce5..e82b654df3 100644</span></span><br><span class="line"><span class="comment">--- a/linux-user/syscall_types.h</span></span><br><span class="line"><span class="comment">+++ b/linux-user/syscall_types.h</span></span><br><span class="line"><span class="meta">@@ -642,3 +642,11 @@</span> STRUCT(usbdevfs_disconnect_claim,</span><br><span class="line">         TYPE_INT, /* flags */</span><br><span class="line">         MK_ARRAY(TYPE_CHAR, USBDEVFS_MAXDRIVERNAME + 1)) /* driver */</span><br><span class="line"> #endif /* CONFIG_USBFS */</span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+STRUCT(anvram_ioctl_t,</span></span><br><span class="line"><span class="addition">+       TYPE_INT, // size</span></span><br><span class="line"><span class="addition">+       TYPE_INT, // is_temp</span></span><br><span class="line"><span class="addition">+       TYPE_INT, // len_param</span></span><br><span class="line"><span class="addition">+       TYPE_INT, // len_value</span></span><br><span class="line"><span class="addition">+       TYPE_PTRVOID, // param</span></span><br><span class="line"><span class="addition">+       TYPE_PTRVOID) // value</span></span><br></pre></td></tr></table></figure><p>然而，测试发现 QEMU 5.X 版本中 NVRAM 读写操作会因未知原因失败，而 QEMU 10.X 版本则能成功运行。鉴于 QEMU 代码库庞大，排查难度较高，因此考虑采用 QEMU 10.X 进行 AFL Fuzz。</p><p>目前公开的 QEMUAFL 支持的最高版本为 QEMU 5.X。若要使用 QEMU 10.X，需自行进行 Patch 适配。相关的 Patch 方案及过程将在后续文章中进行分享。</p>]]></content:encoded>
      
      
      
      <category domain="https://nobb.site/tags/bin/">bin</category>
      
      <category domain="https://nobb.site/tags/fuzz/">fuzz</category>
      
      
      <comments>https://nobb.site/2025/11/13/fuzz2/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>QEMU v10 适配 AFL：架构变更与 MIPS 延迟槽 Bug 分析</title>
      <link>https://nobb.site/2025/11/13/fuzz4/</link>
      <guid>https://nobb.site/2025/11/13/fuzz4/</guid>
      <pubDate>Thu, 13 Nov 2025 09:04:25 GMT</pubDate>
      
      <description>&lt;p&gt;本文将探讨将 qemuafl 的补丁应用到 QEMU v10.x 版本时可能遇到的困难及解决方案。&lt;/p&gt;</description>
      
      
      
      <content:encoded><![CDATA[<p>本文将探讨将 qemuafl 的补丁应用到 QEMU v10.x 版本时可能遇到的困难及解决方案。</p><span id="more"></span><p>前文分析了 AFL++ 对 QEMU 5.X 版本的补丁内容，以及在 QEMU 5.X 版本中通过 ioctl 操作 nvram 时可能出现的未知 Bug。鉴于此，计划将 qemuafl 的补丁迁移至 QEMU 的最新版本中。</p><p>QEMU 当前最新版本为：v10.1.3。</p><p>在尝试将 qemuafl 的补丁迁移至该版本时，遇到了因 QEMU 架构变更导致的严重问题。</p><p>在新版本的 QEMU 中，为了加速文件的编译速度，对代码结构进行了区分。例如，一部分代码的编译只依赖主机架构，而另一部分代码的编译则依赖目标架构。</p><p>以 <code>accel/tcg</code> 目录下的代码为例，在最新版的 QEMU 中，该部分被认为仅需考虑主机架构，因此只需编译一次。例如在首次编译 mips 架构的 QEMU 后，再次编译 <code>arm</code> 架构时，这部分代码无需重新编译，仅需编译与架构相关的代码。</p><p>然而，qemuafl 的补丁在仅需考虑主机架构的目录代码中引入了对目标架构参数的依赖，从而导致编译失败。</p><p>研究发现，自 v10.1 版本起，QEMU 已完全变更为新架构。若在此版本中添加 AFL 相关补丁，需要进行大量修改。进一步分析发现，v10.0.6 版本的 QEMU 架构尚未完全变更，若在该架构中进行相关补丁适配，可节省大量时间。</p><p>以下是需要修改的代码部分说明。</p><p>首先是 <code>accel/tcg</code> 目录下的代码，<code>accel/tcg/meson.build</code> 文件的部分代码如下所示：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">common_ss.add(when: &#x27;CONFIG_TCG&#x27;, if_true: files(</span><br><span class="line">  &#x27;cpu-exec-common.c&#x27;,</span><br><span class="line">  &#x27;tcg-runtime.c&#x27;,</span><br><span class="line">  &#x27;tcg-runtime-gvec.c&#x27;,</span><br><span class="line">))</span><br><span class="line">tcg_specific_ss = ss.source_set()</span><br><span class="line">tcg_specific_ss.add(files(</span><br><span class="line">  &#x27;tcg-all.c&#x27;,</span><br><span class="line">  &#x27;cpu-exec.c&#x27;,</span><br><span class="line">  &#x27;tb-maint.c&#x27;,</span><br><span class="line">  &#x27;translate-all.c&#x27;,</span><br><span class="line">  &#x27;translator.c&#x27;,</span><br><span class="line">))</span><br></pre></td></tr></table></figure><p><code>common_ss</code> 集合中的文件表明该部分代码是通用代码，无需考虑目标架构。<code>tcg_specific_ss</code> 集合中的代码为需要考虑目标架构的 tcg 代码。</p><p>在 <code>tcg-runtime.h</code> 的代码中，补丁内容大量使用了 <code>tl</code> 类型，如下所示：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">DEF_HELPER_FLAGS_2(qasan_load1, TCG_CALL_NO_RWG, <span class="type">void</span>, env, tl)</span><br></pre></td></tr></table></figure><p>将宏展开后可以发现，<code>tl</code> 类型的定义位于 <code>include/exec/helper-head.h.inc</code> 文件中，如下所示：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> dh_alias(t) glue(dh_alias_, t)</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">ifdef</span> COMPILING_PER_TARGET</span></span><br><span class="line"><span class="meta"># <span class="keyword">ifdef</span> TARGET_LONG_BITS</span></span><br><span class="line"><span class="meta">#  <span class="keyword">if</span> TARGET_LONG_BITS == 32</span></span><br><span class="line"><span class="meta">#   <span class="keyword">define</span> dh_alias_tl i32</span></span><br><span class="line"><span class="meta">#   <span class="keyword">define</span> dh_typecode_tl dh_typecode_i32</span></span><br><span class="line"><span class="meta">#  <span class="keyword">else</span></span></span><br><span class="line"><span class="meta">#   <span class="keyword">define</span> dh_alias_tl i64</span></span><br><span class="line"><span class="meta">#   <span class="keyword">define</span> dh_typecode_tl dh_typecode_i64</span></span><br><span class="line"><span class="meta">#  <span class="keyword">endif</span></span></span><br><span class="line"><span class="meta"># <span class="keyword">endif</span></span></span><br><span class="line"><span class="meta"># <span class="keyword">define</span> dh_ctype_tl target_ulong</span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span> <span class="comment">/* COMPILING_PER_TARGET */</span></span></span><br></pre></td></tr></table></figure><p><code>dh_alias(t)</code> &#x3D;&gt; <code>dh_alias_tl</code>，该类型只有当存在 <code>COMPILING_PER_TARGET</code> 定义时，才会被声明。</p><p>通过最外层的 <code>meson.build</code> 代码可以看到，只有在编译需要考虑目标架构的代码时，才会设置该值，代码如下所示：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">...</span><br><span class="line">foreach target : target_dirs</span><br><span class="line">  config_target = config_target_mak[target]</span><br><span class="line">  target_name = config_target[&#x27;TARGET_NAME&#x27;]</span><br><span class="line">  target_base_arch = config_target[&#x27;TARGET_BASE_ARCH&#x27;]</span><br><span class="line">  arch_srcs = [config_target_h[target]]</span><br><span class="line">  arch_deps = []</span><br><span class="line">  c_args = [&#x27;-DCOMPILING_PER_TARGET&#x27;,</span><br><span class="line">            &#x27;-DCONFIG_TARGET=&quot;@0@-config-target.h&quot;&#x27;.format(target),</span><br><span class="line">  ]</span><br><span class="line">...</span><br></pre></td></tr></table></figure><p>因此，需要将 <code>tcg-runtime.c</code> 和 <code>tcg-runtime.h</code> 文件中 AFL 补丁的代码提取出来，放入 <code>tcg-runtime_afl.c</code> 和 <code>tcg-runtime_afl.h</code> 文件中。</p><p>在这部分的补丁代码中，受影响最大的是 <code>TCP Helper</code> 函数，该部分代码的实现逻辑在前文中已说明，此处不再赘述。</p><p>在 <code>tcg-runtime_afl.c</code> 文件中，代码主要是 Helper 函数的实现，为了防止 <code>missing-prototypes</code> 错误，需要添加以下头文件：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> HELPER_H  <span class="string">&quot;accel/tcg/tcg-runtime_afl.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;exec/helper-proto.h.inc&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">undef</span>  HELPER_H</span></span><br></pre></td></tr></table></figure><p>经测试，需包含的最简头文件如下所示：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;qemu/osdep.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;qemu/host-utils.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;exec/cpu-common.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;user/page-protection.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;accel/tcg/getpc.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;user/abitypes.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;exec/cpu-all.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;qemuafl/common.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;tcg/tcg-op.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;qemuafl/qemu-ijon-support.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> HELPER_H  <span class="string">&quot;accel/tcg/tcg-runtime_afl.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;exec/helper-proto.h.inc&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;exec/helper-info.c.inc&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">undef</span>  HELPER_H</span></span><br></pre></td></tr></table></figure><p>最后修改 <code>accel/tcg/meson.build</code>，如下所示：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">tcg_specific_ss.add(files(</span><br><span class="line">  <span class="string">&#x27;tcg-all.c&#x27;</span>,</span><br><span class="line">  <span class="string">&#x27;cpu-exec.c&#x27;</span>,</span><br><span class="line">  <span class="string">&#x27;tb-maint.c&#x27;</span>,</span><br><span class="line">  <span class="string">&#x27;translate-all.c&#x27;</span>,</span><br><span class="line">  <span class="string">&#x27;translator.c&#x27;</span>,</span><br><span class="line">  <span class="string">&#x27;tcg-runtime_afl.c&#x27;</span></span><br><span class="line">))</span><br></pre></td></tr></table></figure><p>QASAN核心代码位于<code>tcg</code>目录下，该部分代码也发生了变化，代码从<code>tcg/tcg-op.c</code>文件迁移到了<code>tcg/tcg-op-ldst.c</code>文件中。并且<code>tcg</code>目录下的代码都为通用代码，不考虑目标架构，但是AFL patch的头文件需要考虑目标架构，因此还需要对头文件进行修改。</p><h3 id="build-qemu-support-sh-兼容性修改"><a href="#build-qemu-support-sh-兼容性修改" class="headerlink" title="build_qemu_support.sh 兼容性修改"></a>build_qemu_support.sh 兼容性修改</h3><p>QEMU v10.0.6 不存在以下配置，需从 <code>build_qemu_support.sh</code> 文件中删除：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">--disable-blobs</span><br><span class="line">--disable-live-block-migration</span><br><span class="line">--disable-sheepdog</span><br><span class="line">--disable-vhost-scsi</span><br><span class="line">--disable-vhost-vsock</span><br><span class="line">--disable-vnc-png</span><br><span class="line">--disable-xfsctl</span><br></pre></td></tr></table></figure><h3 id="qemuafl-x2F-asan-giovese-inl-h"><a href="#qemuafl-x2F-asan-giovese-inl-h" class="headerlink" title="qemuafl&#x2F;asan-giovese-inl.h"></a>qemuafl&#x2F;asan-giovese-inl.h</h3><p>在 <code>qemuafl/asan-giovese-inl.h</code> 文件中需要添加一个声明，如下所示：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">void</span> <span class="title function_">queue_signal</span><span class="params">(CPUArchState *env, <span class="type">int</span> sig, <span class="type">int</span> si_type,</span></span><br><span class="line"><span class="params">                 <span class="type">target_siginfo_t</span> *info)</span>;</span><br></pre></td></tr></table></figure><h3 id="函数变化"><a href="#函数变化" class="headerlink" title="函数变化"></a>函数变化</h3><ol><li><code>tcg_const_tl</code> -&gt; <code>tcg_constant_tl</code></li><li><code>tcg_const_ptr</code>-&gt;<code>tcg_constant_ptr</code></li><li><code>tcg_constant_tl</code> 得到的值不再需要使用 <code>tcg_temp_free</code> 释放，该 free 函数也已不再存在。因此需要搜索所有 <code>tcg_temp_free</code> 调用并将其注释。考虑到 AFL 补丁代码中该部分可能仍需释放，因此进行了以下修改：</li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// include/tcg/tcg-op.h</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;tcg/tcg-temp-internal.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">if</span> TARGET_LONG_BITS == 32</span></span><br><span class="line"><span class="keyword">typedef</span> TCGv_i32 TCGv;</span><br><span class="line"><span class="meta">#<span class="keyword">define</span> tcg_temp_new() tcg_temp_new_i32()</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> tcg_temp_free(v) tcg_temp_free_i32(v)    <span class="comment">// 添加32位的free</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> tcg_global_mem_new tcg_global_mem_new_i32</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> tcgv_tl_temp tcgv_i32_temp</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> tcg_gen_qemu_ld_tl tcg_gen_qemu_ld_i32</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> tcg_gen_qemu_st_tl tcg_gen_qemu_st_i32</span></span><br><span class="line"><span class="meta">#<span class="keyword">elif</span> TARGET_LONG_BITS == 64</span></span><br><span class="line"><span class="keyword">typedef</span> TCGv_i64 TCGv;</span><br><span class="line"><span class="meta">#<span class="keyword">define</span> tcg_temp_new() tcg_temp_new_i64()</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> tcg_temp_free(v) tcg_temp_free_i64(v)  <span class="comment">// 添加64位的free</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> tcg_global_mem_new tcg_global_mem_new_i64</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> tcgv_tl_temp tcgv_i64_temp</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> tcg_gen_qemu_ld_tl tcg_gen_qemu_ld_i64</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> tcg_gen_qemu_st_tl tcg_gen_qemu_st_i64</span></span><br><span class="line"><span class="meta">#<span class="keyword">else</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">error</span> Unhandled TARGET_LONG_BITS value</span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br></pre></td></tr></table></figure><h3 id="修复编译警告"><a href="#修复编译警告" class="headerlink" title="修复编译警告"></a>修复编译警告</h3><p>针对一些编译警告的修复如下：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line">../accel/tcg/cpu-exec.c:<span class="number">586</span>:<span class="number">10</span>: warning: no previous prototype <span class="keyword">for</span> ‘ijon_simple_hash’ [-Wmissing-prototypes]</span><br><span class="line">  <span class="number">586</span> | <span class="type">uint64_t</span> <span class="title function_">ijon_simple_hash</span><span class="params">(<span class="type">uint64_t</span> x)</span> &#123;</span><br><span class="line">      |          ^~~~~~~~~~~~~~~~</span><br><span class="line"><span class="comment">// 在accel/tcg/cpu-exec.c实现的一些函数缺少声明</span></span><br><span class="line"><span class="comment">// 在qemuafl/common.h添加以下声明</span></span><br><span class="line"><span class="type">uint64_t</span> <span class="title function_">ijon_simple_hash</span><span class="params">(<span class="type">uint64_t</span> x)</span>;</span><br><span class="line"><span class="type">uint32_t</span> <span class="title function_">ijon_hashint</span><span class="params">(<span class="type">uint32_t</span> old, <span class="type">uint32_t</span> val)</span>;</span><br><span class="line"><span class="type">uint32_t</span> <span class="title function_">ijon_hashstr</span><span class="params">(<span class="type">uint32_t</span> old, <span class="type">char</span> *val)</span>;</span><br><span class="line"><span class="type">void</span> <span class="title function_">ijon_max_variadic</span><span class="params">(<span class="type">uint32_t</span> addr, ...)</span>;</span><br><span class="line"><span class="type">void</span> <span class="title function_">ijon_min_variadic</span><span class="params">(<span class="type">uint32_t</span> addr, ...)</span>;</span><br><span class="line"><span class="type">uint32_t</span> <span class="title function_">ijon_strdist</span><span class="params">(<span class="type">char</span> *a, <span class="type">char</span> *b)</span>;</span><br><span class="line">-----------</span><br><span class="line">../accel/tcg/cpu-exec.c:<span class="number">1342</span>:<span class="number">42</span>: warning: implicit declaration of function ‘open_self_maps’; did you mean ‘free_self_maps’? [-Wimplicit-function-declaration]</span><br><span class="line"> <span class="number">1342</span> |       <span class="keyword">if</span> (getenv(<span class="string">&quot;AFL_QEMU_DEBUG_MAPS&quot;</span>)) open_self_maps(env, <span class="number">1</span>);</span><br><span class="line">      |                                          ^~~~~~~~~~~~~~</span><br><span class="line">      |                                          free_self_maps</span><br><span class="line"><span class="comment">// 在accel/tcg/cpu-exec.c中patch代码使用到open_self_maps函数，该函数声明的头文件未包含。</span></span><br><span class="line"><span class="comment">// open_self_maps函数的实现位于linux-user/syscall.c，并且被声明为静态函数，因此我们需要把该函数的静态声明去除。</span></span><br><span class="line"><span class="comment">// linux-user/syscall.c修改内容：</span></span><br><span class="line">-<span class="type">static</span> <span class="type">int</span> <span class="title function_">open_self_maps</span><span class="params">(CPUArchState *cpu_env, <span class="type">int</span> fd)</span></span><br><span class="line">+<span class="type">int</span> <span class="title function_">open_self_maps</span><span class="params">(CPUArchState *cpu_env, <span class="type">int</span> fd)</span></span><br><span class="line"><span class="comment">// 然后在qemuafl/common.h中添加函数声明</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">open_self_maps</span><span class="params">(CPUArchState *cpu_env, <span class="type">int</span> fd)</span>;</span><br><span class="line">------------</span><br><span class="line">./qemuafl/imported/snapshot-inl.h:<span class="number">110</span>:<span class="number">13</span>: warning: ‘afl_snapshot_clean’ defined but not used [-Wunused-function]</span><br><span class="line">  <span class="number">110</span> | <span class="type">static</span> <span class="type">void</span> <span class="title function_">afl_snapshot_clean</span><span class="params">(<span class="type">void</span>)</span> &#123;</span><br><span class="line">      |             ^~~~~~~~~~~~~~~~~~</span><br><span class="line">./qemuafl/imported/snapshot-inl.h:<span class="number">98</span>:<span class="number">12</span>: warning: ‘afl_snapshot_do’ defined but not used [-Wunused-function]</span><br><span class="line">   <span class="number">98</span> | <span class="type">static</span> <span class="type">int</span> <span class="title function_">afl_snapshot_do</span><span class="params">(<span class="type">void</span>)</span> &#123;</span><br><span class="line">      |            ^~~~~~~~~~~~~~~</span><br><span class="line">./qemuafl/imported/snapshot-inl.h:<span class="number">76</span>:<span class="number">13</span>: warning: ‘afl_snapshot_exclude_vmrange’ defined but not used [-Wunused-function]</span><br><span class="line">   <span class="number">76</span> | <span class="type">static</span> <span class="type">void</span> <span class="title function_">afl_snapshot_exclude_vmrange</span><span class="params">(<span class="type">void</span> *start, <span class="type">void</span> *end)</span> &#123;</span><br><span class="line">      |             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~</span><br><span class="line"><span class="comment">// 有几个函数声明的未使用，暂时注释掉</span></span><br><span class="line">--------------</span><br><span class="line">../linux-user/syscall.c: In function ‘do_execv’:</span><br><span class="line">../linux-user/syscall.c:<span class="number">8649</span>:<span class="number">23</span>: warning: declaration of ‘p’ shadows a previous local [-Wshadow=local]</span><br><span class="line"> <span class="number">8649</span> |                 <span class="type">char</span> *p, *q, *r;</span><br><span class="line">      |                       ^</span><br><span class="line">../linux-user/syscall.c:<span class="number">8612</span>:<span class="number">11</span>: note: shadowed declaration is here</span><br><span class="line"> <span class="number">8612</span> |     <span class="type">void</span> *p;</span><br><span class="line">      |           ^</span><br><span class="line">../linux-user/syscall.c:<span class="number">8649</span>:<span class="number">27</span>: warning: declaration of ‘q’ shadows a previous local [-Wshadow=local]</span><br><span class="line"> <span class="number">8649</span> |                 <span class="type">char</span> *p, *q, *r;</span><br><span class="line">      |                           ^</span><br><span class="line">../linux-user/syscall.c:<span class="number">8611</span>:<span class="number">12</span>: note: shadowed declaration is here</span><br><span class="line"> <span class="number">8611</span> |     <span class="type">char</span> **q;</span><br><span class="line">      |            ^</span><br><span class="line"><span class="comment">// 还有变量重复声明的问题，改个变量名就好</span></span><br></pre></td></tr></table></figure><h3 id="QEMU-V10-1-3-修改方案"><a href="#QEMU-V10-1-3-修改方案" class="headerlink" title="QEMU V10.1.3 修改方案"></a>QEMU V10.1.3 修改方案</h3><p>主要查看 QEMU V10.1.3 版本的三个配置文件，如下所示：</p><ol><li><code>accel/tcg/meson.build</code> 代码如下所示：</li></ol><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line">if not have_tcg</span><br><span class="line">   subdir_done()</span><br><span class="line">endif</span><br><span class="line"></span><br><span class="line">tcg_ss = ss.source_set()</span><br><span class="line"></span><br><span class="line">tcg_ss.add(files(</span><br><span class="line">  &#x27;cpu-exec.c&#x27;,</span><br><span class="line">  &#x27;cpu-exec-common.c&#x27;,</span><br><span class="line">  &#x27;tcg-runtime.c&#x27;,</span><br><span class="line">  &#x27;tcg-runtime-gvec.c&#x27;,</span><br><span class="line">  &#x27;tb-maint.c&#x27;,</span><br><span class="line">  &#x27;tcg-all.c&#x27;,</span><br><span class="line">  &#x27;tcg-stats.c&#x27;,</span><br><span class="line">  &#x27;translate-all.c&#x27;,</span><br><span class="line">  &#x27;translator.c&#x27;,</span><br><span class="line">))</span><br><span class="line">if get_option(&#x27;plugins&#x27;)</span><br><span class="line">  tcg_ss.add(files(&#x27;plugin-gen.c&#x27;))</span><br><span class="line">endif</span><br><span class="line"></span><br><span class="line">user_ss.add_all(tcg_ss)</span><br><span class="line">system_ss.add_all(tcg_ss)</span><br><span class="line"></span><br><span class="line">user_ss.add(files(</span><br><span class="line">  &#x27;user-exec.c&#x27;,</span><br><span class="line">  &#x27;user-exec-stub.c&#x27;,</span><br><span class="line">))</span><br><span class="line"></span><br><span class="line">system_ss.add(files(</span><br><span class="line">  &#x27;cputlb.c&#x27;,</span><br><span class="line">  &#x27;icount-common.c&#x27;,</span><br><span class="line">  &#x27;monitor.c&#x27;,</span><br><span class="line">  &#x27;tcg-accel-ops.c&#x27;,</span><br><span class="line">  &#x27;tcg-accel-ops-icount.c&#x27;,</span><br><span class="line">  &#x27;tcg-accel-ops-mttcg.c&#x27;,</span><br><span class="line">  &#x27;tcg-accel-ops-rr.c&#x27;,</span><br><span class="line">  &#x27;watchpoint.c&#x27;,</span><br><span class="line">))</span><br></pre></td></tr></table></figure><p>从上述代码可以看出，在当前架构，配置文件不区分 <code>common_ss</code> 通用代码和 <code>tcg_specific_ss</code> tcg 特定架构代码。而是分成 <code>user_ss</code> user 模式编译的代码和 <code>system_ss</code> system 模型编译的代码。</p><ol start="2"><li><code>accel/meson.build</code> 代码如下所示：</li></ol><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">common_ss.add(files(&#x27;accel-common.c&#x27;))</span><br><span class="line">specific_ss.add(files(&#x27;accel-target.c&#x27;))</span><br><span class="line">system_ss.add(files(&#x27;accel-system.c&#x27;, &#x27;accel-blocker.c&#x27;, &#x27;accel-qmp.c&#x27;))</span><br><span class="line">user_ss.add(files(&#x27;accel-user.c&#x27;))</span><br><span class="line"></span><br><span class="line">subdir(&#x27;tcg&#x27;)</span><br><span class="line">if have_system</span><br><span class="line">  subdir(&#x27;hvf&#x27;)</span><br><span class="line">  subdir(&#x27;qtest&#x27;)</span><br><span class="line">  subdir(&#x27;kvm&#x27;)</span><br><span class="line">  subdir(&#x27;xen&#x27;)</span><br><span class="line">  subdir(&#x27;stubs&#x27;)</span><br><span class="line">endif</span><br><span class="line"></span><br><span class="line"># qtest</span><br><span class="line">system_ss.add(files(&#x27;dummy-cpus.c&#x27;))</span><br></pre></td></tr></table></figure><ol start="3"><li><code>meson.build</code> 部分代码如下所示：</li></ol><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">user_ss = ss.source_set()</span><br><span class="line">......</span><br><span class="line">libuser = static_library(&#x27;user&#x27;,</span><br><span class="line">                         user_ss.all_sources() + genh,</span><br><span class="line">                         c_args: [&#x27;-DCONFIG_USER_ONLY&#x27;,</span><br><span class="line">                                  &#x27;-DCOMPILING_SYSTEM_VS_USER&#x27;],</span><br><span class="line">                         include_directories: common_user_inc,</span><br><span class="line">                         dependencies: user_ss.all_dependencies(),</span><br><span class="line">                         build_by_default: false)</span><br></pre></td></tr></table></figure><p>在当前架构中，<code>accel/tcg/</code> 目录下的代码在第一次编译的时候都会被编译到 <code>libuser</code> 库中，无需考虑目标架构。但是该目录下有大量 AFL 补丁的代码，且 AFL 的代码有大量需要考虑目标架构。这就导致 AFL 的补丁代码无法直接迁移到该版本中。</p><p>不过，查看<code>accel/meson.build</code>的编译代码可以发现，仍然存在 <code>specific_ss</code> 配置，只需将 AFL 需要依赖目标架构的代码，迁移到 <code>accel</code> 目录下，然后把文件加入到 <code>specific_ss</code> 当中，即可在 QEMU V10.1.3 版本中成功编译 AFL 补丁版本。</p><h3 id="QEMU-V10-0-6-版本存在的-BUG"><a href="#QEMU-V10-0-6-版本存在的-BUG" class="headerlink" title="QEMU V10.0.6 版本存在的 BUG"></a>QEMU V10.0.6 版本存在的 BUG</h3><p>测试版本为 QEMU V10.0.6 linux-user 模式，目标架构为 mips。（V10.1.3 版本仍然存在）</p><p>成功编译 V10.0.6 版本的 qemuafl 后，开始尝试运行 afl fuzz。</p><p>前文曾提及 AFL 的 qemu 模式运行逻辑，默认情况下采用 forkserver 模式。在 fuzz 程序首次运行时，程序能正常运行，但在第二次执行到某个指令时，却会重新跳转回 main 函数，导致执行失败。</p><p>最终通过 QEMU 的 <code>exec_tb</code>、<code>translate_block</code> 日志信息定位到了问题根源。</p><p>测试脚本如下所示：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line"><span class="keyword">import</span> os</span><br><span class="line"><span class="keyword">import</span> sys</span><br><span class="line"><span class="keyword">import</span> struct</span><br><span class="line"><span class="keyword">import</span> time</span><br><span class="line"><span class="keyword">import</span> subprocess</span><br><span class="line"><span class="keyword">import</span> multiprocessing</span><br><span class="line"></span><br><span class="line"><span class="comment"># 模拟管道文件描述符，使用 os.pipe()</span></span><br><span class="line">ctl_read, ctl_write = os.pipe()   <span class="comment"># 父→子 控制通道</span></span><br><span class="line">st_read, st_write = os.pipe()     <span class="comment"># 子→父 状态通道</span></span><br><span class="line"></span><br><span class="line">FORKSRV_FD = <span class="number">198</span>   <span class="comment"># 模拟 AFL 使用的固定 FD</span></span><br><span class="line">FUZZ_BIN = <span class="string">&quot;/home/debian/fuzz/AFLplusplus/afl-qemu-trace&quot;</span></span><br><span class="line">MAGIC = <span class="number">0x41464c01</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">run_target</span>(<span class="params">exec_bin</span>):</span><br><span class="line">    pid = os.fork()</span><br><span class="line">    <span class="keyword">if</span> pid == <span class="number">0</span>:  <span class="comment"># 子进程</span></span><br><span class="line">        <span class="comment"># 先把管道 dup 到期望的 FD（模拟 forkserver 子进程环境）</span></span><br><span class="line">        os.dup2(ctl_read, FORKSRV_FD)</span><br><span class="line">        os.dup2(st_write, FORKSRV_FD + <span class="number">1</span>)</span><br><span class="line">        <span class="comment"># 关闭不需要的文件描述符</span></span><br><span class="line">        os.close(ctl_write)</span><br><span class="line">        os.close(st_read)</span><br><span class="line">        os.execve(exec_bin, [exec_bin, <span class="string">&quot;./usr/sbin/httpd_patch&quot;</span>] + sys.argv[<span class="number">1</span>:], os.environ)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">parent_process</span>():</span><br><span class="line">    run_target(FUZZ_BIN)</span><br><span class="line">    status = os.read(st_read, <span class="number">4</span>)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;status = <span class="subst">&#123;status&#125;</span>&quot;</span>)</span><br><span class="line">    reply = MAGIC ^ <span class="number">0xFFFFFFFF</span></span><br><span class="line">    os.write(ctl_write, reply.to_bytes(<span class="number">4</span>, <span class="string">&quot;little&quot;</span>))</span><br><span class="line">    option = os.read(st_read, <span class="number">4</span>)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;option = <span class="subst">&#123;option&#125;</span>&quot;</span>)</span><br><span class="line">    map_size = os.read(st_read, <span class="number">4</span>)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;map_size = <span class="subst">&#123;map_size&#125;</span>&quot;</span>)</span><br><span class="line">    version = os.read(st_read, <span class="number">4</span>)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;version = <span class="subst">&#123;version&#125;</span>&quot;</span>)</span><br><span class="line">    <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">        was_killed = <span class="number">0</span></span><br><span class="line">        os.write(ctl_write, was_killed.to_bytes(<span class="number">4</span>, <span class="string">&quot;little&quot;</span>))</span><br><span class="line">        child_pid = os.read(st_read, <span class="number">4</span>)</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">f&quot;child pid = <span class="subst">&#123;<span class="built_in">int</span>.from_bytes(child_pid, <span class="string">&#x27;little&#x27;</span>)&#125;</span>&quot;</span>)</span><br><span class="line">        status = os.read(st_read, <span class="number">4</span>)</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">f&quot;status = <span class="subst">&#123;status&#125;</span>&quot;</span>)</span><br><span class="line">        r = <span class="built_in">input</span>(<span class="string">&quot;continue?&quot;</span>)</span><br><span class="line">        <span class="keyword">if</span> <span class="string">&quot;q&quot;</span> <span class="keyword">in</span> r:</span><br><span class="line">            <span class="keyword">break</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">&quot;__main__&quot;</span>:</span><br><span class="line">    parent_process()</span><br></pre></td></tr></table></figure><p>调试命令如下所示：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">QEMU_LOG_FILENAME=&quot;/tmp/debug.txt&quot; QEMU_LOG=&quot;in_asm,out_asm&quot; python3 afl-py.py</span><br></pre></td></tr></table></figure><p>出现错误的流程大致如下：</p><ol><li>qemu 第一次 fork 出子进程，正常执行完整个流程。</li><li>父进程在第一个子进程执行的过程中，通过 <code>afl_wait_tsl</code> 函数，在父进程的内存空间中同步翻译指令块。这样，在下次 fork 出的子进程执行到同样的块时，就无需再翻译一次，可以节省代码执行时间。</li><li>第二个 fork 出的子进程按照父进程翻译的结果执行，在某个代码处开始出错。</li></ol><p>经定位，错误代码位于 <code>libuClibc</code> 库的 <code>strchr</code> 函数中，关键代码如下所示：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line">.text:00038FA0 03 00 43 30                 andi    $v1, $v0, 3</span><br><span class="line">.text:00038FA4 F9 FF 60 54                 bnezl   $v1, loc_38F8C</span><br><span class="line">.text:00038FA8 00 00 43 90                 lbu     $v1, 0($v0)</span><br><span class="line">.text:00038FAC 00 1A 05 00                 sll     $v1, $a1, 8</span><br><span class="line">.text:00038FB0 25 18 65 00                 or      $v1, $a1</span><br><span class="line">.text:00038FB4 00 5C 03 00                 sll     $t3, $v1, 16</span><br><span class="line">.text:00038FB8 FE 7E 06 3C                 lui     $a2, 0x7EFE</span><br><span class="line">.text:00038FBC 01 81 0A 3C                 lui     $t2, 0x8101</span><br><span class="line">.text:00038FC0 25 58 63 01                 or      $t3, $v1</span><br><span class="line">.text:00038FC4 FF FE C6 34                 li      $a2, 0x7EFEFEFF</span><br><span class="line">.text:00038FC8 21 18 40 00                 move    $v1, $v0</span><br><span class="line">.text:00038FCC 00 01 4A 35                 li      $t2, 0x81010100</span><br><span class="line">.text:00038FD0</span><br><span class="line">.text:00038FD0             loc_38FD0:                               # CODE XREF: index+7C↓j</span><br><span class="line">.text:00038FD0 00 00 64 8C                 lw      $a0, 0($v1)</span><br><span class="line">.text:00038FD4</span><br><span class="line">.text:00038FD4             loc_38FD4:                               # CODE XREF: index+D8↓j</span><br><span class="line">.text:00038FD4 04 00 63 24                 addiu   $v1, 4</span><br><span class="line">.text:00038FD8 26 38 8B 00                 xor     $a3, $a0, $t3</span><br><span class="line">.text:00038FDC 21 40 E6 00                 addu    $t0, $a3, $a2</span><br><span class="line">.text:00038FE0 21 10 86 00                 addu    $v0, $a0, $a2</span><br><span class="line">.text:00038FE4 27 38 07 00                 nor     $a3, $zero, $a3</span><br><span class="line">.text:00038FE8 27 20 04 00                 nor     $a0, $zero, $a0</span><br><span class="line">.text:00038FEC 26 38 E8 00                 xor     $a3, $t0</span><br><span class="line">.text:00038FF0 26 20 82 00                 xor     $a0, $v0</span><br><span class="line">.text:00038FF4 25 20 E4 00                 or      $a0, $a3, $a0</span><br><span class="line">.text:00038FF8 24 20 8A 00                 and     $a0, $t2</span><br><span class="line">.text:00038FFC F4 FF 80 10                 beqz    $a0, loc_38FD0</span><br><span class="line">.text:00039000 FC FF 69 24                 addiu   $t1, $v1, -4</span><br><span class="line">.text:00039004 FC FF 64 90                 lbu     $a0, -4($v1)</span><br><span class="line">.text:00039008 FD FF 62 24                 addiu   $v0, $v1, -3</span><br><span class="line">.text:0003900C 03 00 85 14                 bne     $a0, $a1, loc_3901C</span><br><span class="line">.text:00039010 FE FF 68 24                 addiu   $t0, $v1, -2</span><br><span class="line">.text:00039014 08 00 E0 03                 jr      $ra</span><br><span class="line">.text:00039018 21 10 20 01                 move    $v0, $t1</span><br></pre></td></tr></table></figure><p>按照 QEMU 分块的逻辑，<code>0x00038FAC - 0x0039000</code> 算一个代码块。</p><p>但是在 <code>target/mips/tcg/translate.c</code> 文件的 <code>mips_tr_translate_insn</code> 函数中，有以下代码：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">mips_tr_translate_insn</span><span class="params">(DisasContextBase *dcbase, CPUState *cs)</span></span><br><span class="line">&#123;</span><br><span class="line">......</span><br><span class="line">    <span class="comment">/*</span></span><br><span class="line"><span class="comment">     * End the TB on (most) page crossings.</span></span><br><span class="line"><span class="comment">     * See mips_tr_init_disas_context about single-stepping a branch</span></span><br><span class="line"><span class="comment">     * together with its delay slot.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">if</span> (ctx-&gt;base.pc_next - ctx-&gt;page_start &gt;= TARGET_PAGE_SIZE</span><br><span class="line">        &amp;&amp; !(tb_cflags(ctx-&gt;base.tb) &amp; CF_SINGLE_STEP)) &#123;</span><br><span class="line">        ctx-&gt;base.is_jmp = DISAS_TOO_MANY;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在上面的代码中 <code>TARGET_PAGE_SIZE=4096=0x1000</code>，通过注释也能知道，该部分代码是代码块按照页进行分割，一页的大小就是 <code>0x1000</code>。</p><p>MIPS 指令集中存在 <code>delay slot</code>（延迟槽）机制，即在执行跳转指令之前，会先执行下一条指令。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">比如以下指令</span><br><span class="line">.text:00038FFC F4 FF 80 10                 beqz    $a0, loc_38FD0</span><br><span class="line">.text:00039000 FC FF 69 24                 addiu   $t1, $v1, -4</span><br><span class="line">实际执行过程如下：</span><br><span class="line">$t1 = $v1-4</span><br><span class="line">if $a0 == 0:</span><br><span class="line">  jump</span><br><span class="line">else</span><br><span class="line">  no jump</span><br></pre></td></tr></table></figure><p>但根据 QEMU 的分页机制，<code>0x00038FAC - 0x0039000</code> 块将会被分成：<code>0x00038FAC - 0x0038FFC</code> 和 <code>0x0039000</code> 两个代码块。</p><p>不过，QEMU 的开发者也考虑到了这种情况，因此有以下代码：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">mips_tr_tb_stop</span><span class="params">(DisasContextBase *dcbase, CPUState *cs)</span></span><br><span class="line">&#123;</span><br><span class="line">    DisasContext *ctx = container_of(dcbase, DisasContext, base);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">switch</span> (ctx-&gt;base.is_jmp) &#123;</span><br><span class="line">    <span class="keyword">case</span> DISAS_STOP:</span><br><span class="line">        gen_save_pc(ctx-&gt;base.pc_next);</span><br><span class="line">        tcg_gen_lookup_and_goto_ptr();</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">case</span> DISAS_NEXT:</span><br><span class="line">    <span class="keyword">case</span> DISAS_TOO_MANY:</span><br><span class="line">        save_cpu_state(ctx, <span class="number">0</span>);</span><br><span class="line">        gen_goto_tb(ctx, <span class="number">0</span>, ctx-&gt;base.pc_next);</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">case</span> DISAS_EXIT:</span><br><span class="line">        tcg_gen_exit_tb(<span class="literal">NULL</span>, <span class="number">0</span>);</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">case</span> DISAS_NORETURN:</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">default</span>:</span><br><span class="line">        g_assert_not_reached();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>当 <code>is_jmp == DISAS_TOO_MANY</code> 时，首先保存上下文的 cpu 状态信息，然后设置当前块的下一跳为 <code>delay slot</code> 指令。</p><p>从这点看，QEMU 本身逻辑并无问题。分页是为了减少内存开销，同时也处理了被分开的代码块。</p><p>但是和 AFL 结合后，就会导致兼容性问题，产生 bug。下面将通过 QEMU 的日志信息，来展示该 BUG。</p><p>首先，第一个子进程在翻译代码块时的日志如下所示：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br></pre></td><td class="code"><pre><span class="line">IN(子进程):</span><br><span class="line">0x2b506fac:  sll        v1,a1,0x8</span><br><span class="line">0x2b506fb0:  or v1,v1,a1</span><br><span class="line">0x2b506fb4:  sll        t3,v1,0x10</span><br><span class="line">0x2b506fb8:  lui        a2,0x7efe</span><br><span class="line">0x2b506fbc:  lui        t2,0x8101</span><br><span class="line">0x2b506fc0:  or t3,t3,v1</span><br><span class="line">0x2b506fc4:  ori        a2,a2,0xfeff</span><br><span class="line">0x2b506fc8:  move       v1,v0</span><br><span class="line">0x2b506fcc:  ori        t2,t2,0x100</span><br><span class="line">0x2b506fd0:  lw a0,0(v1)</span><br><span class="line">0x2b506fd4:  addiu      v1,v1,4</span><br><span class="line">0x2b506fd8:  xor        a3,a0,t3</span><br><span class="line">0x2b506fdc:  addu       t0,a3,a2</span><br><span class="line">0x2b506fe0:  addu       v0,a0,a2</span><br><span class="line">0x2b506fe4:  nor        a3,zero,a3</span><br><span class="line">0x2b506fe8:  nor        a0,zero,a0</span><br><span class="line">0x2b506fec:  xor        a3,a3,t0</span><br><span class="line">0x2b506ff0:  xor        a0,a0,v0</span><br><span class="line">0x2b506ff4:  or a0,a3,a0</span><br><span class="line">0x2b506ff8:  and        a0,a0,t2</span><br><span class="line">0x2b506ffc:  beqz       a0,0x2b506fd0</span><br><span class="line"></span><br><span class="line">  -- guest addr 0x000000002b506ffc</span><br><span class="line">0x7f0cd4028655:  41 83 fc 01              cmpl     $1, %r12d</span><br><span class="line">0x7f0cd4028659:  1b db                    sbbl     %ebx, %ebx</span><br><span class="line">0x7f0cd402865b:  f7 db                    negl     %ebx</span><br><span class="line">0x7f0cd402865d:  89 9d 24 1b 00 00        movl     %ebx, 0x1b24(%rbp)</span><br><span class="line">0x7f0cd4028663:  c7 85 1c 1b 00 00 a2 10  movl     $0x110a2, 0x1b1c(%rbp)</span><br><span class="line">0x7f0cd402866b:  01 00</span><br><span class="line">0x7f0cd402866d:  c7 85 20 1b 00 00 d0 6f  movl     $0x2b506fd0, 0x1b20(%rbp)</span><br><span class="line">0x7f0cd4028675:  50 2b</span><br><span class="line">0x7f0cd4028677:  c7 85 80 00 00 00 00 70  movl     $0x2b507000, 0x80(%rbp)</span><br><span class="line">0x7f0cd402867f:  50 2b</span><br><span class="line">0x7f0cd4028681:  48 8b fd                 movq     %rbp, %rdi</span><br><span class="line">0x7f0cd4028684:  ff 15 2e 00 00 00        callq    *0x2e(%rip)</span><br><span class="line">0x7f0cd402868a:  ff e0                    jmpq     *%rax</span><br><span class="line">0x7f0cd402868c:  48 8d 05 70 fe ff ff     leaq     -0x190(%rip), %rax</span><br><span class="line">0x7f0cd4028693:  e9 80 79 fd ff           jmp      0x7f0cd4000018</span><br><span class="line"></span><br><span class="line">IN(子进程):</span><br><span class="line">0x2b507000:  addiu      t1,v1,-4</span><br><span class="line"></span><br><span class="line">OUT: [size=120]</span><br><span class="line">-- guest addr 0x000000002b507000 + tb prologue</span><br><span class="line">0x7f0cd4028800:  8b 5d f8                 movl     -8(%rbp), %ebx</span><br><span class="line">0x7f0cd4028803:  85 db                    testl    %ebx, %ebx</span><br><span class="line">0x7f0cd4028805:  0f 8c 58 00 00 00        jl       0x7f0cd4028863</span><br><span class="line">0x7f0cd402880b:  c6 45 fc 01              movb     $1, -4(%rbp)</span><br><span class="line">0x7f0cd402880f:  8b 5d 0c                 movl     0xc(%rbp), %ebx</span><br><span class="line">0x7f0cd4028812:  83 c3 fc                 addl     $-4, %ebx</span><br><span class="line">0x7f0cd4028815:  89 5d 24                 movl     %ebx, 0x24(%rbp)</span><br><span class="line">0x7f0cd4028818:  c7 85 1c 1b 00 00 a2 00  movl     $0xa2, 0x1b1c(%rbp)</span><br><span class="line">0x7f0cd4028820:  00 00</span><br><span class="line">0x7f0cd4028822:  8b 9d 24 1b 00 00        movl     0x1b24(%rbp), %ebx</span><br><span class="line">0x7f0cd4028828:  85 db                    testl    %ebx, %ebx</span><br><span class="line">0x7f0cd402882a:  0f 85 1e 00 00 00        jne      0x7f0cd402884e</span><br><span class="line">0x7f0cd4028830:  66 66 90                 nop</span><br><span class="line">0x7f0cd4028833:  e9 00 00 00 00           jmp      0x7f0cd4028838</span><br><span class="line">0x7f0cd4028838:  c7 85 80 00 00 00 04 70  movl     $0x2b507004, 0x80(%rbp)</span><br><span class="line">0x7f0cd4028840:  50 2b</span><br><span class="line">0x7f0cd4028842:  48 8d 05 f8 fe ff ff     leaq     -0x108(%rip), %rax</span><br><span class="line">0x7f0cd4028849:  e9 ca 77 fd ff           jmp      0x7f0cd4000018</span><br><span class="line">0x7f0cd402884e:  c7 85 80 00 00 00 d0 6f  movl     $0x2b506fd0, 0x80(%rbp)</span><br><span class="line">0x7f0cd4028856:  50 2b</span><br><span class="line">0x7f0cd4028858:  48 8b fd                 movq     %rbp, %rdi</span><br><span class="line">0x7f0cd402885b:  ff 15 0f 00 00 00        callq    *0xf(%rip)</span><br><span class="line">0x7f0cd4028861:  ff e0                    jmpq     *%rax</span><br><span class="line">0x7f0cd4028863:  48 8d 05 d9 fe ff ff     leaq     -0x127(%rip), %rax</span><br><span class="line">0x7f0cd402886a:  e9 a9 77 fd ff           jmp      0x7f0cd4000018</span><br></pre></td></tr></table></figure><p>观察上述指令发现，QEMU 翻译的跳转目标地址出现了偏差：<code>movl     $0x402ac0, 0x80(%rbp)</code>。<code>0x402ac0</code> 地址为 <code>httpd</code> 程序的 <code>_start</code> 函数起始地址。</p><p>经过详细分析与调试，明确了该 Bug 的成因。</p><p>将原本的分支指令块设为 <code>TB_A</code>，把被分片的 <code>delay slot</code> 指令块设为 <code>TB_B</code>。</p><p>当 QEMU 翻译完 <code>TB_A</code> 代码块后，将会执行 <code>mips_tr_tb_stop</code> 函数，然后调用 <code>save_cpu_state</code> 函数：代码如下所示：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="keyword">inline</span> <span class="type">void</span> <span class="title function_">save_cpu_state</span><span class="params">(DisasContext *ctx, <span class="type">int</span> do_save_pc)</span></span><br><span class="line">&#123;</span><br><span class="line">    LOG_DISAS(<span class="string">&quot;hflags %08x saved %08x\n&quot;</span>, ctx-&gt;hflags, ctx-&gt;saved_hflags);</span><br><span class="line">    <span class="keyword">if</span> (do_save_pc &amp;&amp; ctx-&gt;base.pc_next != ctx-&gt;saved_pc) &#123;</span><br><span class="line">        gen_save_pc(ctx-&gt;base.pc_next);</span><br><span class="line">        ctx-&gt;saved_pc = ctx-&gt;base.pc_next;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (ctx-&gt;hflags != ctx-&gt;saved_hflags) &#123;</span><br><span class="line">        tcg_gen_movi_i32(hflags, ctx-&gt;hflags);</span><br><span class="line">        ctx-&gt;saved_hflags = ctx-&gt;hflags;</span><br><span class="line">        <span class="keyword">switch</span> (ctx-&gt;hflags &amp; MIPS_HFLAG_BMASK_BASE) &#123;</span><br><span class="line">        <span class="keyword">case</span> MIPS_HFLAG_BR:</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        <span class="keyword">case</span> MIPS_HFLAG_BC:</span><br><span class="line">        <span class="keyword">case</span> MIPS_HFLAG_BL:</span><br><span class="line">        <span class="keyword">case</span> MIPS_HFLAG_B:</span><br><span class="line">            tcg_gen_movi_tl(btarget, ctx-&gt;btarget);</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>因为在 <code>mips_tr_tb_stop</code> 函数中调用的是 <code>save_cpu_state(ctx, 0);</code>，因此 <code>do_save_pc=0</code>。最终只执行了三句指令：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">tcg_gen_movi_i32(hflags, ctx-&gt;hflags);</span><br><span class="line">ctx-&gt;saved_hflags = ctx-&gt;hflags;</span><br><span class="line">tcg_gen_movi_tl(btarget, ctx-&gt;btarget);</span><br></pre></td></tr></table></figure><p>这三句指令可以对应到之前 QEMU 日志中的指令，如下所示：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"># 设置hflags</span><br><span class="line">tcg_gen_movi_i32(hflags, ctx-&gt;hflags); </span><br><span class="line">-&gt; 0x7f0cd4028663: movl     $0x110a2, 0x1b1c(%rbp)</span><br><span class="line"># 设置btarget</span><br><span class="line">tcg_gen_movi_tl(btarget, ctx-&gt;btarget);</span><br><span class="line">-&gt; 0x7f0cd402866d: movl     $0x2b506fd0, 0x1b20(%rbp)</span><br></pre></td></tr></table></figure><p>当前代码块翻译完成后，接下来翻译 <code>TB_B</code> 块。在翻译块的开头调用 <code>mips_tr_init_disas_context</code> 函数进行上下文变量初始化，将会调用 <code>restore_cpu_state</code> 函数，恢复 <code>btarget</code> 值，相关代码如下所示：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="keyword">inline</span> <span class="type">void</span> <span class="title function_">restore_cpu_state</span><span class="params">(CPUMIPSState *env, DisasContext *ctx)</span></span><br><span class="line">&#123;</span><br><span class="line">    ctx-&gt;saved_hflags = ctx-&gt;hflags;</span><br><span class="line">    <span class="keyword">switch</span> (ctx-&gt;hflags &amp; MIPS_HFLAG_BMASK_BASE) &#123;</span><br><span class="line">    <span class="keyword">case</span> MIPS_HFLAG_BR:</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">case</span> MIPS_HFLAG_BC:</span><br><span class="line">    <span class="keyword">case</span> MIPS_HFLAG_BL:</span><br><span class="line">    <span class="keyword">case</span> MIPS_HFLAG_B:</span><br><span class="line">        ctx-&gt;btarget = env-&gt;btarget;</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>上述代码是导致本次 Bug 的另一个核心点，下文将详细说明。在初始化完上下文信息后，将会调用 <code>mips_tr_translate_insn</code> 翻译代码，首先翻译 <code>add</code> 指令。翻译完成后，因为 <code>is_slot=True</code>，所以将会调用 <code>gen_branch(ctx, insn_bytes);</code> 函数生成分支跳转代码。关键代码如下所示：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">mips_tr_translate_insn</span><span class="params">(DisasContextBase *dcbase, CPUState *cs)</span></span><br><span class="line">&#123;</span><br><span class="line">......</span><br><span class="line">    <span class="keyword">if</span> (is_slot) &#123;</span><br><span class="line">        gen_branch(ctx, insn_bytes);</span><br><span class="line">    &#125;</span><br><span class="line">......</span><br><span class="line">&#125;</span><br><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">gen_branch</span><span class="params">(DisasContext *ctx, <span class="type">int</span> insn_bytes)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">if</span> (ctx-&gt;hflags &amp; MIPS_HFLAG_BMASK) &#123;</span><br><span class="line">        <span class="type">int</span> proc_hflags = ctx-&gt;hflags &amp; MIPS_HFLAG_BMASK;</span><br><span class="line">        <span class="comment">/* Branches completion */</span></span><br><span class="line">        clear_branch_hflags(ctx);</span><br><span class="line">        ctx-&gt;base.is_jmp = DISAS_NORETURN;</span><br><span class="line">        <span class="keyword">switch</span> (proc_hflags &amp; MIPS_HFLAG_BMASK_BASE) &#123;</span><br><span class="line">......</span><br><span class="line">        <span class="keyword">case</span> MIPS_HFLAG_BC:</span><br><span class="line">            <span class="comment">/* Conditional branch */</span></span><br><span class="line">            &#123;</span><br><span class="line">                TCGLabel *l1 = gen_new_label();</span><br><span class="line"></span><br><span class="line">                tcg_gen_brcondi_tl(TCG_COND_NE, bcond, <span class="number">0</span>, l1);</span><br><span class="line">                gen_goto_tb(ctx, <span class="number">1</span>, ctx-&gt;base.pc_next + insn_bytes);</span><br><span class="line">                gen_set_label(l1);</span><br><span class="line">                gen_goto_tb(ctx, <span class="number">0</span>, ctx-&gt;btarget);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">......</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>该部分代码可以和上面 QEMU 日志信息进行一一对应，如下所示：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">tcg_gen_brcondi_tl(TCG_COND_NE, bcond, 0, l1);</span><br><span class="line">-&gt; </span><br><span class="line">0x7f0cd4028822:  movl     0x1b24(%rbp), %ebx</span><br><span class="line">0x7f0cd4028828:  testl    %ebx, %ebx</span><br><span class="line">0x7f0cd402882a:  jne      0x7f0cd402884e (l1地址)</span><br><span class="line">gen_goto_tb(ctx, 1, ctx-&gt;base.pc_next + insn_bytes);</span><br><span class="line">-&gt; </span><br><span class="line">0x7f0cd4028833:  jmp      0x7f0cd4028838</span><br><span class="line">0x7f0cd4028838:  movl     $0x2b507004, 0x80(%rbp)</span><br><span class="line">gen_set_label(l1);</span><br><span class="line">gen_goto_tb(ctx, 0, ctx-&gt;btarget);</span><br><span class="line">-&gt;</span><br><span class="line">l1:</span><br><span class="line">0x7f0cd402884e:  c7 85 80 00 00 00 d0 6f  movl     $0x2b506fd0, 0x80(%rbp)</span><br></pre></td></tr></table></figure><p>至此，相关流程已梳理完毕。该 Bug 情况总体概括如下：AFL 在翻译 <code>TB_B</code> 代码块时，由于 <code>ctx-&gt;btarget</code> 的值错误地等于 <code>0x402ac0</code>，导致翻译出来的指令为：<code>movl     0x402ac0, 0x80(%rbp)</code>。在代码执行到该分支后，将会错误地跳转回程序的 <code>_start</code> 函数，最终导致程序崩溃。</p><p>总体梳理一下该 BUG 的成因：</p><ol><li>QMEU 会根据 0x1000 大小对代码块进行分片。这可能会导致分支跳转指令和其 delay slot 指令被分成两块：<code>TB_A</code> 和 <code>TB_B</code>。</li><li>QEMU 考虑到分片会影响 <code>delay slot</code> 的情况，因此在翻译完 <code>TB_A</code> 后，会调用 <code>save_cpu_state</code> 函数保存跳转地址信息。</li><li><code>save_cpu_state</code> 函数保存 <code>btarget</code> 的方案是翻译成 TCG 代码（<code>movl $0x2b506fd0, 0x1b20(%rbp)</code>）。</li><li><code>restore_cpu_state</code> 函数恢复 <code>btarget</code> 的方案是从 <code>env-&gt;btarget</code> 上下文中获取。</li></ol><p>上述的 3, 4 两点就产生了冲突，最终导致 BUG 的产生。</p><p>在原版的 QEMU 中，因为性能考虑，不会一次性把所有代码都翻译成 TCG 指令。而是运行到哪，翻译到哪。因此在翻译完 <code>TB_A</code> 指令后，将会执行 <code>TB_A</code> 指令。<code>TB_A</code> 翻译出的 TCG 指令最终会跳转到 <code>TB_B</code> 地址，因此下一步将会翻译 <code>TB_B</code> 指令。由于已经执行了 <code>TB_A</code> TCG 指令中的 <code>movl $0x2b506fd0, 0x1b20(%rbp)</code> 指令，因此 <code>env-&gt;btarget</code> 已经被成功设置成正确的 <code>btarget</code> 地址了。所以在后面翻译 <code>TB_B</code> 指令的流程中没有出错。</p><p>在 qemuafl 中，第一个子进程的翻译过程就是按照 QEMU 原版的逻辑来运行，因此不会出错。但是，随后父进程将会跟着开始翻译代码块，却不执行，这就导致 <code>env-&gt;btarget</code> 无法被正确设置，最终代码出错，程序崩溃。</p><p>简单来说，原版 QEMU 的流程为：<code>翻译TB_A -&gt; 执行TB_A -&gt; 翻译TB_B -&gt; 执行TB_B</code>。<br>qemuafl 父进程的流程为：<code>翻译TB_A -&gt; 翻译TB_B -&gt; ...</code>。</p><p>随后对原版 qemuafl（QEMU V5 版本）进行的简要分析显示，该 Bug 仍然存在，如下所示：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line">OUT: [size=114]</span><br><span class="line">  -- guest addr 0x3fd87000 + tb prologue</span><br><span class="line">0x7fe6dc01ce9b:  44 8b e3                 movl     %ebx, %r12d</span><br><span class="line">0x7fe6dc01ce9e:  41 83 e4 01              andl     $1, %r12d</span><br><span class="line">0x7fe6dc01cea2:  44 8b ad 9c 1a 00 00     movl     0x1a9c(%rbp), %r13d</span><br><span class="line">0x7fe6dc01cea9:  41 81 e5 ff fb ff ff     andl     $0xfffffbff, %r13d</span><br><span class="line">0x7fe6dc01ceb0:  41 c1 e4 0a              shll     $0xa, %r12d</span><br><span class="line">0x7fe6dc01c240:  8b 5d f8                 movl     -8(%rbp), %ebx</span><br><span class="line">0x7fe6dc01ceb4:  45 0b ec                 orl      %r12d, %r13d</span><br><span class="line">0x7fe6dc01c243:  85 db                    testl    %ebx, %ebx</span><br><span class="line">0x7fe6dc01ceb7:  44 89 ad 9c 1a 00 00     movl     %r13d, 0x1a9c(%rbp)</span><br><span class="line">0x7fe6dc01c245:  0f 8c 5b 00 00 00        jl       0x7fe6dc01c2a6</span><br><span class="line">0x7fe6dc01cebe:  83 e3 fe                 andl     $0xfffffffe, %ebx</span><br><span class="line">0x7fe6dc01c24b:  8b 5d 0c                 movl     0xc(%rbp), %ebx</span><br><span class="line">0x7fe6dc01cec1:  89 9d 80 00 00 00        movl     %ebx, 0x80(%rbp)</span><br><span class="line">0x7fe6dc01c24e:  83 c3 fc                 addl     $-4, %ebx</span><br><span class="line">0x7fe6dc01cec7:  48 8b fd                 movq     %rbp, %rdi</span><br><span class="line">0x7fe6dc01c251:  89 5d 24                 movl     %ebx, 0x24(%rbp)</span><br><span class="line">0x7fe6dc01ceca:  ff 15 10 00 00 00        callq    *0x10(%rip)</span><br><span class="line">0x7fe6dc01c254:  c7 85 9c 1a 00 00 a2 00  movl     $0xa2, 0x1a9c(%rbp)</span><br><span class="line">0x7fe6dc01ced0:  ff e0                    jmpq     *%rax</span><br><span class="line">0x7fe6dc01c25c:  00 00</span><br><span class="line">0x7fe6dc01ced2:  48 8d 05 2a ff ff ff     leaq     -0xd6(%rip), %rax</span><br><span class="line">0x7fe6dc01c25e:  8b 9d a4 1a 00 00        movl     0x1aa4(%rbp), %ebx</span><br><span class="line">0x7fe6dc01ced9:  e9 3a 31 fe ff           jmp      0x7fe6dc000018</span><br><span class="line">0x7fe6dc01c264:  85 db                    testl    %ebx, %ebx</span><br><span class="line">  -- tb slow paths + alignment</span><br><span class="line">0x7fe6dc01c266:  0f 85 1e 00 00 00        jne      0x7fe6dc01c28a</span><br><span class="line">0x7fe6dc01c26c:  66 66 90                 nop</span><br><span class="line">0x7fe6dc01c26f:  e9 00 00 00 00           jmp      0x7fe6dc01c274</span><br><span class="line">0x7fe6dc01c274:  c7 85 80 00 00 00 04 70  movl     $0x3fd87004, 0x80(%rbp)</span><br><span class="line">0x7fe6dc01c27c:  d8 3f</span><br><span class="line">0x7fe6dc01cede:  90                       nop</span><br><span class="line">0x7fe6dc01c27e:  48 8d 05 3c ff ff ff     leaq     -0xc4(%rip), %rax</span><br><span class="line">0x7fe6dc01cedf:  90                       nop</span><br><span class="line">0x7fe6dc01c285:  e9 8e 3d fe ff           jmp      0x7fe6dc000018</span><br><span class="line">  data: [size=8]</span><br><span class="line">0x7fe6dc01c28a:  90                       nop</span><br><span class="line">0x7fe6dc01cee0:  .quad  0x55ad16a506f0</span><br><span class="line">0x7fe6dc01c28b:  e9 00 00 00 00           jmp      0x7fe6dc01c290</span><br><span class="line"></span><br><span class="line">0x7fe6dc01c290:  c7 85 80 00 00 00 c0 2a  movl     $0x402ac0, 0x80(%rbp)</span><br><span class="line">0x7fe6dc01c298:  40 00</span><br><span class="line">0x7fe6dc01c29a:  48 8d 05 1f ff ff ff     leaq     -0xe1(%rip), %rax</span><br><span class="line">0x7fe6dc01c2a1:  e9 72 3d fe ff           jmp      0x7fe6dc000018</span><br><span class="line">0x7fe6dc01c2a6:  48 8d 05 16 ff ff ff     leaq     -0xea(%rip), %rax</span><br><span class="line">0x7fe6dc01c2ad:  e9 66 3d fe ff           jmp      0x7fe6dc000018</span><br></pre></td></tr></table></figure><p><code>0x7fe6dc01c290</code> 地址的指令仍然出错，至于为何未能触发该 Bug，需要进一步调试分析，感兴趣的读者可自行探索。</p><h4 id="修复方案"><a href="#修复方案" class="headerlink" title="修复方案"></a>修复方案</h4><ol><li>不把 <code>delay slot</code> 进行分片，patch 代码如下所示：</li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * End the TB on (most) page crossings.</span></span><br><span class="line"><span class="comment"> * See mips_tr_init_disas_context about single-stepping a branch</span></span><br><span class="line"><span class="comment"> * together with its delay slot.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">if</span> (ctx-&gt;base.pc_next - ctx-&gt;page_start &gt;= TARGET_PAGE_SIZE</span><br><span class="line">    &amp;&amp; !(tb_cflags(ctx-&gt;base.tb) &amp; CF_SINGLE_STEP)</span><br><span class="line">    &amp;&amp; !(ctx-&gt;hflags &amp; MIPS_HFLAG_BMASK) <span class="comment">// patch代码</span></span><br><span class="line">) &#123;</span><br><span class="line">    ctx-&gt;base.is_jmp = DISAS_TOO_MANY;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>该修复方案优点在于快捷简单，缺点是可能会影响代码分片，从而对 QEMU 执行效率产生一定影响。</p><ol start="2"><li>修改<code>gen_branch</code>函数的逻辑，如下所示：</li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">gen_goto_tb(ctx, <span class="number">0</span>, ctx-&gt;btarget);</span><br><span class="line">修改成-&gt;</span><br><span class="line">tcg_gen_mov_tl(cpu_PC, btarget);</span><br><span class="line">tcg_gen_lookup_and_goto_ptr();</span><br></pre></td></tr></table></figure><p>该修复方案同样快捷简单，把所有分支跳转的btarget都修改成从内存中获取。缺点是性能开销大，这步骤需要进行内存寻址操作，性能开销远大于硬编码。mips代码中肯定会存在大量分支跳转指令，这会大大影响的程序的执行效率。</p><ol start="3"><li>只针对该BUG，修改<code>gen_branch</code>函数的逻辑，如下所示：</li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br></pre></td><td class="code"><pre><span class="line">target/mips/tcg/translate.h 中：</span><br><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span> <span class="title">DisasContext</span> &#123;</span></span><br><span class="line">    DisasContextBase base;</span><br><span class="line">    <span class="comment">// ... 原有字段 ...</span></span><br><span class="line">    <span class="type">bool</span> mi;</span><br><span class="line">    <span class="type">int</span> gi;</span><br><span class="line">    <span class="comment">// 新增字段</span></span><br><span class="line">    <span class="type">bool</span> btarget_from_env; </span><br><span class="line">&#125; DisasContext;</span><br><span class="line"></span><br><span class="line">target/mips/tcg/translate.c </span><br><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">mips_tr_init_disas_context</span><span class="params">(DisasContextBase *dcbase, CPUState *cs)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="comment">// ... 原有代码 ...</span></span><br><span class="line">    restore_cpu_state(env, ctx); <span class="comment">// 这里 ctx-&gt;btarget 被赋值为 env-&gt;btarget</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// 新增代码：如果当前处于 Branch Mask 状态，说明是在 delay slot 中开始的 TB</span></span><br><span class="line">    ctx-&gt;btarget_from_env = (ctx-&gt;hflags &amp; MIPS_HFLAG_BMASK) != <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// ... 原有代码 ...</span></span><br><span class="line">&#125;</span><br><span class="line">...</span><br><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">gen_branch</span><span class="params">(DisasContext *ctx, <span class="type">int</span> insn_bytes)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">if</span> (ctx-&gt;hflags &amp; MIPS_HFLAG_BMASK) &#123;</span><br><span class="line">        <span class="type">int</span> proc_hflags = ctx-&gt;hflags &amp; MIPS_HFLAG_BMASK;</span><br><span class="line">        <span class="comment">// ... 原有代码 ...</span></span><br><span class="line">        <span class="keyword">switch</span> (proc_hflags &amp; MIPS_HFLAG_BMASK_BASE) &#123;</span><br><span class="line">        <span class="comment">// ...</span></span><br><span class="line">        <span class="keyword">case</span> MIPS_HFLAG_B:</span><br><span class="line">            <span class="comment">/* unconditional branch */</span></span><br><span class="line">           <span class="keyword">if</span> (proc_hflags &amp; MIPS_HFLAG_BX) &#123;</span><br><span class="line">               tcg_gen_xori_i32(hflags, hflags, MIPS_HFLAG_M16);</span><br><span class="line">           &#125;</span><br><span class="line">           <span class="comment">// 修改开始</span></span><br><span class="line">           <span class="keyword">if</span> (ctx-&gt;btarget_from_env) &#123;</span><br><span class="line">               tcg_gen_mov_tl(cpu_PC, btarget);</span><br><span class="line">               tcg_gen_lookup_and_goto_ptr();</span><br><span class="line">           &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">               gen_goto_tb(ctx, <span class="number">0</span>, ctx-&gt;btarget);</span><br><span class="line">           &#125;</span><br><span class="line">           <span class="comment">// 修改结束</span></span><br><span class="line">           <span class="keyword">break</span>;</span><br><span class="line">       <span class="keyword">case</span> MIPS_HFLAG_BL:</span><br><span class="line">           <span class="comment">/* blikely taken case */</span></span><br><span class="line">           <span class="comment">// 修改开始</span></span><br><span class="line">           <span class="keyword">if</span> (ctx-&gt;btarget_from_env) &#123;</span><br><span class="line">               tcg_gen_mov_tl(cpu_PC, btarget);</span><br><span class="line">               tcg_gen_lookup_and_goto_ptr();</span><br><span class="line">           &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">               gen_goto_tb(ctx, <span class="number">0</span>, ctx-&gt;btarget);</span><br><span class="line">           &#125;</span><br><span class="line">           <span class="comment">// 修改结束</span></span><br><span class="line">           <span class="keyword">break</span>;</span><br><span class="line">       <span class="keyword">case</span> MIPS_HFLAG_BC:</span><br><span class="line">           <span class="comment">/* Conditional branch */</span></span><br><span class="line">           &#123;</span><br><span class="line">               TCGLabel *l1 = gen_new_label();</span><br><span class="line"></span><br><span class="line">               tcg_gen_brcondi_tl(TCG_COND_NE, bcond, <span class="number">0</span>, l1);</span><br><span class="line">               gen_goto_tb(ctx, <span class="number">1</span>, ctx-&gt;base.pc_next + insn_bytes);</span><br><span class="line">               gen_set_label(l1);</span><br><span class="line">               <span class="comment">// 修改开始</span></span><br><span class="line">               <span class="keyword">if</span> (ctx-&gt;btarget_from_env) &#123;</span><br><span class="line">                   tcg_gen_mov_tl(cpu_PC, btarget);</span><br><span class="line">                   tcg_gen_lookup_and_goto_ptr();</span><br><span class="line">               &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                   gen_goto_tb(ctx, <span class="number">0</span>, ctx-&gt;btarget);</span><br><span class="line">               &#125;</span><br><span class="line">               <span class="comment">// 修改结束</span></span><br><span class="line">           &#125;</span><br><span class="line">           <span class="keyword">break</span>;</span><br><span class="line">       <span class="comment">// ... MIPS_HFLAG_BR 本身已经是动态跳转了，无需修改 ...</span></span><br><span class="line">       &#125;</span><br><span class="line">   &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>该方案由AI生成，修改起来稍微复杂一点，但是性能损失小。</p>]]></content:encoded>
      
      
      
      <category domain="https://nobb.site/tags/bin/">bin</category>
      
      <category domain="https://nobb.site/tags/fuzz/">fuzz</category>
      
      
      <comments>https://nobb.site/2025/11/13/fuzz4/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>AFL Fuzz QEMU新版适配：深度解析 Patch 细节</title>
      <link>https://nobb.site/2025/11/13/fuzz3/</link>
      <guid>https://nobb.site/2025/11/13/fuzz3/</guid>
      <pubDate>Thu, 13 Nov 2025 09:04:25 GMT</pubDate>
      
      <description>&lt;p&gt;本文将深度解析 AFL++ 对 QEMU 的 patch 细节。&lt;/p&gt;</description>
      
      
      
      <content:encoded><![CDATA[<p>本文将深度解析 AFL++ 对 QEMU 的 patch 细节。</p><span id="more"></span><h1 id="AFL对-QEMU-的修改"><a href="#AFL对-QEMU-的修改" class="headerlink" title="AFL对 QEMU 的修改"></a>AFL对 QEMU 的修改</h1><p>首先，下面列出 AFL对 QEMU 的修改目录：</p><figure class="highlight patch"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line">accel/tcg/cpu-exec.c                          | 1582 +++++++++++++++++</span><br><span class="line">accel/tcg/tcg-runtime.c                       |  824 +++++++++</span><br><span class="line">accel/tcg/tcg-runtime.h                       |   28 +</span><br><span class="line">accel/tcg/translate-all.c                     |  212 +++</span><br><span class="line">accel/tcg/translator.c                        |   30 +</span><br><span class="line">linux-user/elfload.c                          |   55 +</span><br><span class="line">linux-user/main.c                             |  120 ++</span><br><span class="line">linux-user/mips/cpu_loop.c                    |   15 +</span><br><span class="line">linux-user/mmap.c                             |   63 +</span><br><span class="line">linux-user/signal.c                           |   42 +-</span><br><span class="line">linux-user/syscall.c                          |   52 +-</span><br><span class="line">qemuafl/api.h                                 |  215 +++</span><br><span class="line">qemuafl/asan-giovese-inl.h                    | 1536 ++++++++++++++++</span><br><span class="line">qemuafl/asan-giovese.h                        |  155 ++</span><br><span class="line">qemuafl/common.h                              |  200 +++</span><br><span class="line">qemuafl/cpu-translate.h                       |  177 ++</span><br><span class="line">qemuafl/imported/afl_hash.h                   |   74 +</span><br><span class="line">qemuafl/imported/cmplog.h                     |  106 ++</span><br><span class="line">qemuafl/imported/config.h                     |  591 ++++++</span><br><span class="line">qemuafl/imported/snapshot-inl.h               |  115 ++</span><br><span class="line">qemuafl/imported/types.h                      |  253 +++</span><br><span class="line">qemuafl/interval-tree/.gitignore              |    3 +</span><br><span class="line">qemuafl/interval-tree/COPYING                 |   20 +</span><br><span class="line">qemuafl/interval-tree/compiler.h              |   17 +</span><br><span class="line">qemuafl/interval-tree/interval-tree.inl       |    2 +</span><br><span class="line">qemuafl/interval-tree/interval_tree_generic.h |  193 ++</span><br><span class="line">qemuafl/interval-tree/rbtree.h                |  108 ++</span><br><span class="line">qemuafl/interval-tree/rbtree.inl              |  549 ++++++</span><br><span class="line">qemuafl/interval-tree/rbtree_augmented.h      |  245 +++</span><br><span class="line">qemuafl/qasan-qemu.h                          |  143 ++</span><br><span class="line">qemuafl/qasan.h                               |  264 +++</span><br><span class="line">qemuafl/qemu-ijon-support.h                   |   65 +</span><br><span class="line">target/mips/tcg/translate.c                   |  146 ++</span><br><span class="line">tcg/tcg-op.c                                  |   19 +</span><br><span class="line">tcg/tcg.c                                     |   13 +</span><br></pre></td></tr></table></figure><p>不过上面的目录并不完全，只针对了目标架构为 mips 的情况，不同架构的以下文件不会一样：</p><figure class="highlight patch"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">linux-user/&#123;arch&#125;/cpu_loop.c</span><br><span class="line">target/&#123;arch&#125;/tcg/translate.c</span><br></pre></td></tr></table></figure><p>首先，<code>qemuafl</code>目录下的文件为 AFL 相关的头文件，包含相关全局变量结构体类型声明等等。若需查看 AFL 对 QEMU 进行了哪些修改，可以通过检查该文件代码是否包含<code>qemuafl</code>目录下的头文件。</p><p>由于 AFL 的 QEMU 使用的是user-mode，因此应从 <code>linux-user</code> 目录下的代码开始分析。</p><ol><li><code>linux-user/main.c</code>文件的代码，patch 内容如下所示：</li></ol><figure class="highlight patch"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">diff --git a/linux-user/main.c b/linux-user/main.c</span></span><br><span class="line"><span class="comment">index 2cd867491b..b0172d86fb 100644</span></span><br><span class="line"><span class="comment">--- a/linux-user/main.c</span></span><br><span class="line"><span class="comment">+++ b/linux-user/main.c</span></span><br><span class="line"><span class="meta">@@ -68,6 +68,9 @@</span></span><br><span class="line"> #define AT_FLAGS_PRESERVE_ARGV0 (1 &lt;&lt; AT_FLAGS_PRESERVE_ARGV0_BIT)</span><br><span class="line"> #endif</span><br><span class="line"> </span><br><span class="line"><span class="addition">+#include &quot;tcg/tcg-op.h&quot;</span></span><br><span class="line"><span class="addition">+#include &quot;qemuafl/qasan-qemu.h&quot;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"> char *exec_path;</span><br><span class="line"> char real_exec_path[PATH_MAX];</span><br><span class="line"> </span><br><span class="line"><span class="meta">@@ -267,6 +270,73 @@</span> CPUArchState *cpu_copy(CPUArchState *env)</span><br><span class="line">     return new_env;</span><br><span class="line"> &#125;</span><br><span class="line"> </span><br><span class="line"><span class="addition">+/* A shorthand way to suppress the warnings that you are ignoring the return value of asprintf() */</span></span><br><span class="line"><span class="addition">+static inline void ignore_result(long long int unused_result)</span></span><br><span class="line"><span class="addition">+&#123;</span></span><br><span class="line"><span class="addition">+    (void) unused_result;</span></span><br><span class="line"><span class="addition">+&#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+/* Get libqasan path. */</span></span><br><span class="line"><span class="addition">+#ifndef AFL_PATH</span></span><br><span class="line"><span class="addition">+  #define AFL_PATH &quot;/usr/local/lib/afl/&quot;</span></span><br><span class="line"><span class="addition">+#endif</span></span><br><span class="line"><span class="addition">+static char *get_libqasan_path(char *own_loc)</span></span><br><span class="line"><span class="addition">+&#123;</span></span><br><span class="line"><span class="addition">+    if (!unlikely(own_loc)) &#123;</span></span><br><span class="line"><span class="addition">+        fprintf(stderr, &quot;BUG: param own_loc is NULL\n&quot;);</span></span><br><span class="line"><span class="addition">+        exit(EXIT_FAILURE);</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    char *tmp, *cp = NULL, *rsl, *own_copy;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    tmp = getenv(&quot;AFL_PATH&quot;);</span></span><br><span class="line"><span class="addition">+    if (tmp) &#123;</span></span><br><span class="line"><span class="addition">+        ignore_result(asprintf(&amp;cp, &quot;%s/libqasan.so&quot;, tmp));</span></span><br><span class="line"><span class="addition">+        if (access(cp, X_OK)) &#123;</span></span><br><span class="line"><span class="addition">+            fprintf(stderr, &quot;Unable to find &#x27;%s&#x27;\n&quot;, tmp);</span></span><br><span class="line"><span class="addition">+            exit(EXIT_FAILURE);</span></span><br><span class="line"><span class="addition">+        &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+        return cp;</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    own_copy = strdup(own_loc);</span></span><br><span class="line"><span class="addition">+    rsl = strrchr(own_copy, &#x27;/&#x27;);</span></span><br><span class="line"><span class="addition">+    if (rsl) &#123;</span></span><br><span class="line"><span class="addition">+        *rsl = 0;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+        ignore_result(asprintf(&amp;cp, &quot;%s/libqasan.so&quot;, own_copy));</span></span><br><span class="line"><span class="addition">+        free(own_copy);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+        if (!access(cp, X_OK)) &#123; return cp; &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    &#125; else &#123;</span></span><br><span class="line"><span class="addition">+        free(own_copy);</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    if (!access(AFL_PATH &quot;/libqasan.so&quot;, X_OK)) &#123;</span></span><br><span class="line"><span class="addition">+        if (cp) &#123; free(cp); &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+        return strdup(AFL_PATH &quot;/libqasan.so&quot;);</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    /* This is an AFL error message, but since it is in QEMU it can&#x27;t</span></span><br><span class="line"><span class="addition">+       have all the pretty formatting of AFL without importing</span></span><br><span class="line"><span class="addition">+       a bunch of AFL pieces. */</span></span><br><span class="line"><span class="addition">+    fprintf(stderr, &quot;\n&quot; &quot;&quot; &quot;[-] &quot; &quot;&quot;</span></span><br><span class="line"><span class="addition">+        &quot;Oops, unable to find the &#x27;libqasan.so&#x27; binary. The binary must be &quot;</span></span><br><span class="line"><span class="addition">+        &quot;built\n&quot;</span></span><br><span class="line"><span class="addition">+        &quot;    separately by following the instructions in &quot;</span></span><br><span class="line"><span class="addition">+        &quot;qemu_mode/libqasan/README.md. &quot;</span></span><br><span class="line"><span class="addition">+        &quot;If you\n&quot;</span></span><br><span class="line"><span class="addition">+        &quot;    already have the binary installed, you may need to specify &quot;</span></span><br><span class="line"><span class="addition">+        &quot;AFL_PATH in the\n&quot;</span></span><br><span class="line"><span class="addition">+        &quot;    environment.\n&quot;);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    fprintf(stderr, &quot;Failed to locate &#x27;libqasan.so&#x27;.\n&quot;);</span></span><br><span class="line"><span class="addition">+    exit(EXIT_FAILURE);</span></span><br><span class="line"><span class="addition">+&#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"> static void handle_arg_help(const char *arg)</span><br><span class="line"> &#123;</span><br><span class="line">     usage(EXIT_SUCCESS);</span><br><span class="line"><span class="meta">@@ -713,6 +783,18 @@</span> int main(int argc, char **argv, char **envp)</span><br><span class="line">     unsigned long max_reserved_va;</span><br><span class="line">     bool preserve_argv0;</span><br><span class="line"> </span><br><span class="line"><span class="addition">+    use_qasan = !!getenv(&quot;AFL_USE_QASAN&quot;);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    if (getenv(&quot;QASAN_MAX_CALL_STACK&quot;))</span></span><br><span class="line"><span class="addition">+      qasan_max_call_stack = atoi(getenv(&quot;QASAN_MAX_CALL_STACK&quot;));</span></span><br><span class="line"><span class="addition">+    if (getenv(&quot;QASAN_SYMBOLIZE&quot;))</span></span><br><span class="line"><span class="addition">+      qasan_symbolize = atoi(getenv(&quot;QASAN_SYMBOLIZE&quot;));</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+#if defined(ASAN_GIOVESE) &amp;&amp; !defined(DO_NOT_USE_QASAN)</span></span><br><span class="line"><span class="addition">+    if (use_qasan)</span></span><br><span class="line"><span class="addition">+      asan_giovese_init();</span></span><br><span class="line"><span class="addition">+#endif</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line">     error_init(argv[0]);</span><br><span class="line">     module_call_init(MODULE_INIT_TRACE);</span><br><span class="line">     qemu_init_cpu_list();</span><br><span class="line"><span class="meta">@@ -733,6 +815,45 @@</span> int main(int argc, char **argv, char **envp)</span><br><span class="line">         (void) envlist_setenv(envlist, *wrk);</span><br><span class="line">     &#125;</span><br><span class="line"> </span><br><span class="line"><span class="addition">+    /* Add AFL_PRELOAD for qasan if it is enabled */</span></span><br><span class="line"><span class="addition">+    if(use_qasan) &#123;</span></span><br><span class="line"><span class="addition">+        char *preload = getenv(&quot;AFL_PRELOAD&quot;);</span></span><br><span class="line"><span class="addition">+        char *libqasan = get_libqasan_path(argv[0]);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+        if (!preload) &#123;</span></span><br><span class="line"><span class="addition">+            setenv(&quot;AFL_PRELOAD&quot;, libqasan, 0);</span></span><br><span class="line"><span class="addition">+        &#125; else &#123;</span></span><br><span class="line"><span class="addition">+            /* NOTE: If there is more than one in the list, LD_PRELOAD allows spaces or colons</span></span><br><span class="line"><span class="addition">+                     as separators (but no escaping provided), but DYLD_INSERT_LIBRARIES allows only colons.</span></span><br><span class="line"><span class="addition">+                     Prefer colons for maximum compatibility, but use space if the string already has any. */</span></span><br><span class="line"><span class="addition">+            char * afl_preload;</span></span><br><span class="line"><span class="addition">+            if (strchr(preload, &#x27; &#x27;)) &#123;</span></span><br><span class="line"><span class="addition">+                ignore_result(asprintf(&amp;afl_preload, &quot;%s %s&quot;, libqasan, preload));</span></span><br><span class="line"><span class="addition">+            &#125; else &#123;</span></span><br><span class="line"><span class="addition">+                ignore_result(asprintf(&amp;afl_preload, &quot;%s:%s&quot;, libqasan, preload));</span></span><br><span class="line"><span class="addition">+            &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+            setenv(&quot;AFL_PRELOAD&quot;, afl_preload, 1);</span></span><br><span class="line"><span class="addition">+            free(afl_preload);</span></span><br><span class="line"><span class="addition">+        &#125;</span></span><br><span class="line"><span class="addition">+        free(libqasan);</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    /* Expand AFL_PRELOAD to append preload libraries */</span></span><br><span class="line"><span class="addition">+    char *afl_preload = getenv(&quot;AFL_PRELOAD&quot;);</span></span><br><span class="line"><span class="addition">+    if (afl_preload) &#123;</span></span><br><span class="line"><span class="addition">+        /* NOTE: If there is more than one in the list, LD_PRELOAD allows spaces or colons</span></span><br><span class="line"><span class="addition">+                 as separators, but DYLD_INSERT_LIBRARIES allows only colons.</span></span><br><span class="line"><span class="addition">+                 Maybe we should attempt to normalize the list here before we assign it? */</span></span><br><span class="line"><span class="addition">+        char * ld_preload;</span></span><br><span class="line"><span class="addition">+        ignore_result(asprintf(&amp;ld_preload, &quot;LD_PRELOAD=%s&quot;, afl_preload));</span></span><br><span class="line"><span class="addition">+        envlist_setenv(envlist, ld_preload);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+        char * dyld_insert;</span></span><br><span class="line"><span class="addition">+        ignore_result(asprintf(&amp;dyld_insert, &quot;DYLD_INSERT_LIBRARIES=%s&quot;, afl_preload));</span></span><br><span class="line"><span class="addition">+        envlist_setenv(envlist, dyld_insert);</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line">     /* Read the stack limit from the kernel.  If it&#x27;s &quot;unlimited&quot;,</span><br><span class="line">        then we can do little else besides use the default.  */</span><br><span class="line">     &#123;</span><br></pre></td></tr></table></figure><p><code>main.c</code> 代码中添加的内容旨在让 QEMU 支持 <code>QASan</code>。关于 <code>QASan</code>，ChatGPT 的解释如下：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">QASan（QEMU Address Sanitizer）</span><br><span class="line">是 AFL++ 专为 QEMU 模式实现的一种轻量级 Address Sanitizer（内存错误检测）。</span><br><span class="line">在 QEMU 的 linux-user 模式中，通过 LD_PRELOAD + runtime hook 去检测目标程序的内存错误。</span><br><span class="line">QASan 可以检测：</span><br><span class="line">✔️ 堆缓冲区越界（heap OOB）</span><br><span class="line">例如 malloc 100 字节，但写到 100 以外的区域。</span><br><span class="line">✔️ Use-after-free（UAF）</span><br><span class="line">free 之后继续使用。</span><br><span class="line">✔️ Double-free</span><br><span class="line">同一个指针重复释放。</span><br><span class="line">✔️ Invalid free</span><br><span class="line">释放不是 malloc 得到的地址。</span><br><span class="line">✔️ 一些栈溢出触发崩溃行为</span><br><span class="line">（栈上的 shadow memory 不完整，所以能力有限，但比没有强。）</span><br><span class="line">✔️ 内存泄漏检测（部分）</span><br><span class="line">它覆盖的是 heap 和全局区内存错误。</span><br><span class="line">栈检测有限，但也能帮助 fuzzing 提升覆盖率和能检测更多 bug。</span><br></pre></td></tr></table></figure><ol start="2"><li><code>linux-user/elfload.c</code>文件patch 内容如下所示：</li></ol><figure class="highlight patch"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">diff --git a/linux-user/elfload.c b/linux-user/elfload.c</span></span><br><span class="line"><span class="comment">index fa83d78667..e8b1a946fb 100644</span></span><br><span class="line"><span class="comment">--- a/linux-user/elfload.c</span></span><br><span class="line"><span class="comment">+++ b/linux-user/elfload.c</span></span><br><span class="line"><span class="meta">@@ -33,6 +33,8 @@</span></span><br><span class="line"> #include &quot;target/arm/cpu-features.h&quot;</span><br><span class="line"> #endif</span><br><span class="line"> </span><br><span class="line"><span class="addition">+#include &quot;qemuafl/common.h&quot;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"> #ifdef _ARCH_PPC64</span><br><span class="line"> #undef ARCH_DLINFO</span><br><span class="line"> #undef ELF_PLATFORM</span><br><span class="line"><span class="meta">@@ -3463,9 +3465,11 @@</span> static void load_elf_image(const char *image_name, const ImageSource *src,</span><br><span class="line">             if (elf_prot &amp; PROT_EXEC) &#123;</span><br><span class="line">                 if (vaddr &lt; info-&gt;start_code) &#123;</span><br><span class="line">                     info-&gt;start_code = vaddr;</span><br><span class="line"><span class="addition">+                    if (!afl_start_code) afl_start_code = vaddr;</span></span><br><span class="line">                 &#125;</span><br><span class="line">                 if (vaddr_ef &gt; info-&gt;end_code) &#123;</span><br><span class="line">                     info-&gt;end_code = vaddr_ef;</span><br><span class="line"><span class="addition">+                    if (!afl_end_code) afl_end_code = vaddr_ef;</span></span><br><span class="line">                 &#125;</span><br><span class="line">             &#125;</span><br><span class="line">             if (elf_prot &amp; PROT_WRITE) &#123;</span><br><span class="line"><span class="meta">@@ -3499,6 +3503,57 @@</span> static void load_elf_image(const char *image_name, const ImageSource *src,</span><br><span class="line">         load_symbols(ehdr, src, load_bias);</span><br><span class="line">     &#125;</span><br><span class="line"> </span><br><span class="line"><span class="addition">+    if (getenv(&quot;AFL_QEMU_BLOCK_COV&quot;)) &#123;</span></span><br><span class="line"><span class="addition">+      block_cov = 1;</span></span><br><span class="line"><span class="addition">+      block_id = 5;</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    if (!afl_exit_point) &#123;</span></span><br><span class="line"><span class="addition">+      char *ptr;</span></span><br><span class="line"><span class="addition">+      if ((ptr = getenv(&quot;AFL_EXITPOINT&quot;)) != NULL) &#123;</span></span><br><span class="line"><span class="addition">+        afl_exit_point = strtoul(ptr, NULL, 16);</span></span><br><span class="line"><span class="addition">+#ifdef TARGET_ARM</span></span><br><span class="line"><span class="addition">+      /* The least significant bit indicates Thumb mode. */</span></span><br><span class="line"><span class="addition">+        afl_exit_point = afl_exit_point &amp; ~(target_ulong)1;</span></span><br><span class="line"><span class="addition">+#endif</span></span><br><span class="line"><span class="addition">+        if (getenv(&quot;AFL_DEBUG&quot;) != NULL)</span></span><br><span class="line"><span class="addition">+          fprintf(stderr, &quot;AFL exitpoint: 0x%lx\n&quot;,</span></span><br><span class="line"><span class="addition">+                  (unsigned long)afl_exit_point);</span></span><br><span class="line"><span class="addition">+      &#125;</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    if (!afl_entry_point) &#123;</span></span><br><span class="line"><span class="addition">+      char *ptr;</span></span><br><span class="line"><span class="addition">+      if ((ptr = getenv(&quot;AFL_ENTRYPOINT&quot;)) != NULL) &#123;</span></span><br><span class="line"><span class="addition">+        afl_entry_point = strtoul(ptr, NULL, 16);</span></span><br><span class="line"><span class="addition">+      &#125; else &#123;</span></span><br><span class="line"><span class="addition">+        // On PowerPC64 the entry point is the _function descriptor_</span></span><br><span class="line"><span class="addition">+        // of the entry function. For AFL to properly initialize,</span></span><br><span class="line"><span class="addition">+        // afl_entry_point needs to be set to the actual first instruction</span></span><br><span class="line"><span class="addition">+        // as opposed executed by the target program. This as opposed to</span></span><br><span class="line"><span class="addition">+        // where the function&#x27;s descriptor sits in memory.</span></span><br><span class="line"><span class="addition">+        // copied from PPC init_thread</span></span><br><span class="line"><span class="addition">+#if defined(TARGET_PPC64) &amp;&amp; !defined(TARGET_ABI32)</span></span><br><span class="line"><span class="addition">+        if (get_ppc64_abi(info) &lt; 2) &#123;</span></span><br><span class="line"><span class="addition">+            uint64_t val;</span></span><br><span class="line"><span class="addition">+            get_user_u64(val, info-&gt;entry);</span></span><br><span class="line"><span class="addition">+            afl_entry_point = val + info-&gt;load_bias;</span></span><br><span class="line"><span class="addition">+        &#125; else &#123;</span></span><br><span class="line"><span class="addition">+            afl_entry_point = info-&gt;entry;</span></span><br><span class="line"><span class="addition">+        &#125;</span></span><br><span class="line"><span class="addition">+#else</span></span><br><span class="line"><span class="addition">+        afl_entry_point = info-&gt;entry;</span></span><br><span class="line"><span class="addition">+#endif</span></span><br><span class="line"><span class="addition">+      &#125;</span></span><br><span class="line"><span class="addition">+#ifdef TARGET_ARM</span></span><br><span class="line"><span class="addition">+      /* The least significant bit indicates Thumb mode. */</span></span><br><span class="line"><span class="addition">+      afl_entry_point = afl_entry_point &amp; ~(target_ulong)1;</span></span><br><span class="line"><span class="addition">+#endif</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+    if (getenv(&quot;AFL_DEBUG&quot;) != NULL)</span></span><br><span class="line"><span class="addition">+      fprintf(stderr, &quot;AFL forkserver entrypoint: 0x%lx\n&quot;,</span></span><br><span class="line"><span class="addition">+              (unsigned long)afl_entry_point);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line">     debuginfo_report_elf(image_name, src-&gt;fd, load_bias);</span><br><span class="line"> </span><br><span class="line">     mmap_unlock();</span><br></pre></td></tr></table></figure><p><code>elfload.c</code> 文件主要用于读取目标 ELF 文件结构信息。AFL 在该文件中进行全局变量的初始化，比如获取该 ELF 文件的代码段访问。还可以通过<code>AFL_EXITPOINT</code>环境变量设置程序fuzz 的结束地址。还可以使用<code>AFL_ENTRYPOINT</code>环境变量设置fuzz 的入口地址。如果没设置，默认为 ELF 程序的代码起始地址。</p><ol start="3"><li><code>linux-user/mmap.c</code>文件patch 内容如下所示：</li></ol><figure class="highlight patch"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">diff --git a/linux-user/mmap.c b/linux-user/mmap.c</span></span><br><span class="line"><span class="comment">index d1f36e6f16..c080a739bf 100644</span></span><br><span class="line"><span class="comment">--- a/linux-user/mmap.c</span></span><br><span class="line"><span class="comment">+++ b/linux-user/mmap.c</span></span><br><span class="line"><span class="meta">@@ -34,6 +34,25 @@</span></span><br><span class="line"> #include &quot;target/arm/cpu-features.h&quot;</span><br><span class="line"> #endif</span><br><span class="line"> </span><br><span class="line"><span class="addition">+#include &quot;qemuafl/common.h&quot;</span></span><br><span class="line"><span class="addition">+#include &quot;qemuafl/interval-tree/interval-tree.inl&quot;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+struct mmap_tree_node &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  struct rb_node rb;</span></span><br><span class="line"><span class="addition">+  abi_long start, end;</span></span><br><span class="line"><span class="addition">+  abi_long __subtree_last;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+&#125;;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+#define MMAP_TREE_START(node) ((node)-&gt;start)</span></span><br><span class="line"><span class="addition">+#define MMAP_TREE_LAST(node) ((node)-&gt;end)</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+INTERVAL_TREE_DEFINE(struct mmap_tree_node, rb, abi_long, __subtree_last,</span></span><br><span class="line"><span class="addition">+                     MMAP_TREE_START, MMAP_TREE_LAST, static, mmap_tree)</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+static struct rb_root mmap_tree_root = RB_ROOT;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"> static pthread_mutex_t mmap_mutex = PTHREAD_MUTEX_INITIALIZER;</span><br><span class="line"> static __thread int mmap_lock_count;</span><br><span class="line"> </span><br><span class="line"><span class="meta">@@ -585,6 +604,12 @@</span> static abi_long mmap_end(abi_ulong start, abi_ulong last,</span><br><span class="line">             qemu_log_unlock(f);</span><br><span class="line">         &#125;</span><br><span class="line">     &#125;</span><br><span class="line"><span class="addition">+    if (afl_fork_child &amp;&amp; persistent_memory) &#123;</span></span><br><span class="line"><span class="addition">+        struct mmap_tree_node* node = calloc(sizeof(struct mmap_tree_node), 1);</span></span><br><span class="line"><span class="addition">+        node-&gt;start = start;</span></span><br><span class="line"><span class="addition">+        node-&gt;end = last;</span></span><br><span class="line"><span class="addition">+        mmap_tree_insert(node, &amp;mmap_tree_root);</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line">     return start;</span><br><span class="line"> &#125;</span><br><span class="line"> </span><br><span class="line"><span class="meta">@@ -1095,6 +1120,17 @@</span> int target_munmap(abi_ulong start, abi_ulong len)</span><br><span class="line">     if (likely(ret == 0)) &#123;</span><br><span class="line">         page_set_flags(start, start + len - 1, 0);</span><br><span class="line">         shm_region_rm_complete(start, start + len - 1);</span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+        if (afl_fork_child &amp;&amp; persistent_memory) &#123;</span></span><br><span class="line"><span class="addition">+            struct mmap_tree_node* node = mmap_tree_iter_first(&amp;mmap_tree_root,</span></span><br><span class="line"><span class="addition">+                                            start, start + len - 1);</span></span><br><span class="line"><span class="addition">+            while (node) &#123;</span></span><br><span class="line"><span class="addition">+                struct mmap_tree_node* next = mmap_tree_iter_next(node, start,</span></span><br><span class="line"><span class="addition">+                                                start + len - 1);</span></span><br><span class="line"><span class="addition">+                mmap_tree_remove(node, &amp;mmap_tree_root);</span></span><br><span class="line"><span class="addition">+                node = next;</span></span><br><span class="line"><span class="addition">+            &#125;</span></span><br><span class="line"><span class="addition">+        &#125;</span></span><br><span class="line">     &#125;</span><br><span class="line">     mmap_unlock();</span><br><span class="line"> </span><br><span class="line"><span class="meta">@@ -1189,6 +1225,21 @@</span> abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,</span><br><span class="line">         page_set_flags(new_addr, new_addr + new_size - 1,</span><br><span class="line">                        prot | PAGE_VALID | PAGE_RESET);</span><br><span class="line">         shm_region_rm_complete(new_addr, new_addr + new_size - 1);</span><br><span class="line"><span class="addition">+        if (afl_fork_child &amp;&amp; persistent_memory) &#123;</span></span><br><span class="line"><span class="addition">+            struct mmap_tree_node* node = mmap_tree_iter_first(&amp;mmap_tree_root,</span></span><br><span class="line"><span class="addition">+                                            old_addr, old_addr + old_size - 1);</span></span><br><span class="line"><span class="addition">+            while (node) &#123;</span></span><br><span class="line"><span class="addition">+                struct mmap_tree_node* next = mmap_tree_iter_next(node, old_addr,</span></span><br><span class="line"><span class="addition">+                                                old_addr + old_size - 1);</span></span><br><span class="line"><span class="addition">+                mmap_tree_remove(node, &amp;mmap_tree_root);</span></span><br><span class="line"><span class="addition">+                node = next;</span></span><br><span class="line"><span class="addition">+            &#125;</span></span><br><span class="line"><span class="addition">+            </span></span><br><span class="line"><span class="addition">+            node = calloc(sizeof(struct mmap_tree_node), 1);</span></span><br><span class="line"><span class="addition">+            node-&gt;start = new_addr;</span></span><br><span class="line"><span class="addition">+            node-&gt;end = new_addr + new_size - 1;</span></span><br><span class="line"><span class="addition">+            mmap_tree_insert(node, &amp;mmap_tree_root);</span></span><br><span class="line"><span class="addition">+        &#125;</span></span><br><span class="line">     &#125;</span><br><span class="line">     mmap_unlock();</span><br><span class="line">     return new_addr;</span><br><span class="line"><span class="meta">@@ -1486,3 +1537,15 @@</span> abi_long target_shmdt(abi_ulong shmaddr)</span><br><span class="line">     &#125;</span><br><span class="line">     return rv;</span><br><span class="line"> &#125;</span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+void afl_target_unmap_trackeds(void) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    struct mmap_tree_node* node = mmap_tree_iter_first(&amp;mmap_tree_root, 0,</span></span><br><span class="line"><span class="addition">+                                                        (abi_ulong)-1);</span></span><br><span class="line"><span class="addition">+    while (node) &#123;</span></span><br><span class="line"><span class="addition">+        struct mmap_tree_node* next = mmap_tree_iter_next(node, 0, (abi_ulong)-1);</span></span><br><span class="line"><span class="addition">+        target_munmap(node-&gt;start, node-&gt;end - node-&gt;start);</span></span><br><span class="line"><span class="addition">+        node = next;</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+&#125;</span></span><br></pre></td></tr></table></figure><p><code>mmap.c</code> 文件涉及内存管理。在 <code>persistent</code> 模式下，AFL 需要自动跟踪目标应用的所有 mmap 内存区域。</p><ol start="4"><li><code>linux-user/signal.c</code>文件patch 内容如下所示：</li></ol><figure class="highlight patch"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">diff --git a/linux-user/signal.c b/linux-user/signal.c</span></span><br><span class="line"><span class="comment">index 4dafc2c3a2..8c99829023 100644</span></span><br><span class="line"><span class="comment">--- a/linux-user/signal.c</span></span><br><span class="line"><span class="comment">+++ b/linux-user/signal.c</span></span><br><span class="line"><span class="meta">@@ -39,6 +39,9 @@</span></span><br><span class="line"> #include &quot;user/signal.h&quot;</span><br><span class="line"> #include &quot;tcg/tcg.h&quot;</span><br><span class="line"> </span><br><span class="line"><span class="addition">+#include &quot;tcg/tcg-op.h&quot;</span></span><br><span class="line"><span class="addition">+#include &quot;qemuafl/qasan-qemu.h&quot;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"> /* target_siginfo_t must fit in gdbstub&#x27;s siginfo save area. */</span><br><span class="line"> QEMU_BUILD_BUG_ON(sizeof(target_siginfo_t) &gt; MAX_SIGINFO_LENGTH);</span><br><span class="line"> </span><br><span class="line"><span class="meta">@@ -1293,19 +1296,55 @@</span> static void handle_pending_signal(CPUArchState *cpu_env, int sig,</span><br><span class="line">         print_taken_signal(sig, &amp;unswapped);</span><br><span class="line">     &#125;</span><br><span class="line"> </span><br><span class="line"><span class="deletion">-    if (handler == TARGET_SIG_DFL) &#123;</span></span><br><span class="line"><span class="deletion">-        /* default handler : ignore some signal. The other are job control or fatal */</span></span><br><span class="line"><span class="addition">+    int ignore_handling = !!getenv(&quot;AFL_QEMU_FORCE_DFL&quot;);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    if (handler == TARGET_SIG_DFL || ignore_handling) &#123;</span></span><br><span class="line"><span class="addition">+    /* default handler : ignore some signal. The other are job control or fatal */</span></span><br><span class="line">         if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) &#123;</span><br><span class="line">             kill(getpid(),SIGSTOP);</span><br><span class="line">         &#125; else if (sig != TARGET_SIGCHLD &amp;&amp;</span><br><span class="line">                    sig != TARGET_SIGURG &amp;&amp;</span><br><span class="line">                    sig != TARGET_SIGWINCH &amp;&amp;</span><br><span class="line">                    sig != TARGET_SIGCONT) &#123;</span><br><span class="line"><span class="addition">+#if defined(ASAN_GIOVESE) &amp;&amp; !defined(DO_NOT_USE_QASAN)</span></span><br><span class="line"><span class="addition">+            if (use_qasan) &#123;</span></span><br><span class="line"><span class="addition">+              if (sig == TARGET_SIGILL ||</span></span><br><span class="line"><span class="addition">+                  sig != TARGET_SIGFPE ||</span></span><br><span class="line"><span class="addition">+                  sig != TARGET_SIGSEGV ||</span></span><br><span class="line"><span class="addition">+                  sig != TARGET_SIGBUS)</span></span><br><span class="line"><span class="addition">+                asan_giovese_deadly_signal(target_to_host_signal(sig),</span></span><br><span class="line"><span class="addition">+                                           k-&gt;info._sifields._sigfault._addr,</span></span><br><span class="line"><span class="addition">+                                           PC_GET(cpu_env), BP_GET(cpu_env),</span></span><br><span class="line"><span class="addition">+                                           SP_GET(cpu_env));</span></span><br><span class="line"><span class="addition">+              else</span></span><br><span class="line"><span class="addition">+                asan_giovese_deadly_signal(target_to_host_signal(sig),</span></span><br><span class="line"><span class="addition">+                                           PC_GET(cpu_env),</span></span><br><span class="line"><span class="addition">+                                           PC_GET(cpu_env), BP_GET(cpu_env),</span></span><br><span class="line"><span class="addition">+                                           SP_GET(cpu_env));</span></span><br><span class="line"><span class="addition">+            &#125;</span></span><br><span class="line"><span class="addition">+#endif</span></span><br><span class="line">             dump_core_and_abort(cpu_env, sig);</span><br><span class="line">         &#125;</span><br><span class="line">     &#125; else if (handler == TARGET_SIG_IGN) &#123;</span><br><span class="line">         /* ignore sig */</span><br><span class="line">     &#125; else if (handler == TARGET_SIG_ERR) &#123;</span><br><span class="line"><span class="addition">+#if defined(ASAN_GIOVESE) &amp;&amp; !defined(DO_NOT_USE_QASAN)</span></span><br><span class="line"><span class="addition">+      if (use_qasan) &#123;</span></span><br><span class="line"><span class="addition">+        if (sig == TARGET_SIGILL ||</span></span><br><span class="line"><span class="addition">+            sig == TARGET_SIGFPE ||</span></span><br><span class="line"><span class="addition">+            sig == TARGET_SIGSEGV ||</span></span><br><span class="line"><span class="addition">+            sig == TARGET_SIGBUS)</span></span><br><span class="line"><span class="addition">+          asan_giovese_deadly_signal(target_to_host_signal(sig),</span></span><br><span class="line"><span class="addition">+                                     k-&gt;info._sifields._sigfault._addr,</span></span><br><span class="line"><span class="addition">+                                     PC_GET(cpu_env), BP_GET(cpu_env),</span></span><br><span class="line"><span class="addition">+                                     SP_GET(cpu_env));</span></span><br><span class="line"><span class="addition">+        else</span></span><br><span class="line"><span class="addition">+          asan_giovese_deadly_signal(target_to_host_signal(sig),</span></span><br><span class="line"><span class="addition">+                                     PC_GET(cpu_env),</span></span><br><span class="line"><span class="addition">+                                     PC_GET(cpu_env), BP_GET(cpu_env),</span></span><br><span class="line"><span class="addition">+                                     SP_GET(cpu_env));</span></span><br><span class="line"><span class="addition">+      &#125;</span></span><br><span class="line"><span class="addition">+#endif</span></span><br><span class="line">         dump_core_and_abort(cpu_env, sig);</span><br></pre></td></tr></table></figure><p><code>signal.c</code> 文件主要处理信号相关内容。AFL 主要通过信号来判断目标程序是否 crash，比如：<code>SIGILL</code>, <code>SIGFPE</code>, <code>SIGSEGV</code>, <code>SIGBUS</code>。</p><p>然而，当目标程序自行编写信号处理函数时，AFL 可能无法捕获相关信号。因此，可通过</p><p>除此之外，还有添加跟<code>QASan</code>相关的代码，在 fatal signals 之前调用 QASan。</p><ol start="5"><li><code>linux-user/syscall.c</code>文件patch 内容如下所示：</li></ol><figure class="highlight patch"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">diff --git a/linux-user/syscall.c b/linux-user/syscall.c</span></span><br><span class="line"><span class="comment">index 3a25abfaca..d6612ace5a 100644</span></span><br><span class="line"><span class="comment">--- a/linux-user/syscall.c</span></span><br><span class="line"><span class="comment">+++ b/linux-user/syscall.c</span></span><br><span class="line"><span class="meta">@@ -148,6 +148,9 @@</span></span><br><span class="line"> #include &quot;fd-trans.h&quot;</span><br><span class="line"> #include &quot;user/cpu_loop.h&quot;</span><br><span class="line"> </span><br><span class="line"><span class="addition">+#include &quot;qemuafl/common.h&quot;</span></span><br><span class="line"><span class="addition">+#include &quot;qemuafl/qasan-qemu.h&quot;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"> #ifndef CLONE_IO</span><br><span class="line"> #define CLONE_IO                0x80000000      /* Clone io context */</span><br><span class="line"> #endif</span><br><span class="line"><span class="meta">@@ -847,6 +850,15 @@</span> void target_set_brk(abi_ulong new_brk)</span><br><span class="line">     initial_target_brk = target_brk;</span><br><span class="line"> &#125;</span><br><span class="line"> </span><br><span class="line"><span class="addition">+abi_ulong afl_get_brk(void) &#123;</span></span><br><span class="line"><span class="addition">+  return target_brk;</span></span><br><span class="line"><span class="addition">+&#125;</span></span><br><span class="line"><span class="addition">+abi_ulong afl_set_brk(abi_ulong new_brk) &#123;</span></span><br><span class="line"><span class="addition">+  abi_ulong old_brk = target_brk;</span></span><br><span class="line"><span class="addition">+  target_brk = new_brk;</span></span><br><span class="line"><span class="addition">+  return old_brk;</span></span><br><span class="line"><span class="addition">+&#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"> /* do_brk() must return target values and target errnos. */</span><br><span class="line"> abi_long do_brk(abi_ulong brk_val)</span><br><span class="line"> &#123;</span><br><span class="line"><span class="meta">@@ -8590,7 +8602,7 @@</span> static int do_execv(CPUArchState *cpu_env, int dirfd,</span><br><span class="line">                     abi_long guest_envp, int flags, bool is_execveat)</span><br><span class="line"> &#123;</span><br><span class="line">     int ret;</span><br><span class="line"><span class="deletion">-    char **argp, **envp;</span></span><br><span class="line"><span class="addition">+    char **argp = NULL, **envp = NULL;</span></span><br><span class="line">     int argc, envc;</span><br><span class="line">     abi_ulong gp;</span><br><span class="line">     abi_ulong addr;</span><br><span class="line"><span class="meta">@@ -8616,6 +8628,35 @@</span> static int do_execv(CPUArchState *cpu_env, int dirfd,</span><br><span class="line">         if (!addr) &#123;</span><br><span class="line">             break;</span><br><span class="line">         &#125;</span><br><span class="line"><span class="addition">+        /* QASAN: remove preloaded library */</span></span><br><span class="line"><span class="addition">+        if (use_qasan &amp;&amp; !getenv(&quot;QASAN_PRESERVE_EXECVE&quot;)) &#123;</span></span><br><span class="line"><span class="addition">+            /*</span></span><br><span class="line"><span class="addition">+            * If we need to clear the LD_PRELOAD list, run the memory</span></span><br><span class="line"><span class="addition">+            * lock and unlock methods to inspect the contents within</span></span><br><span class="line"><span class="addition">+            * the strings.</span></span><br><span class="line"><span class="addition">+            */</span></span><br><span class="line"><span class="addition">+            abi_long len = target_strlen(gp);</span></span><br><span class="line"><span class="addition">+            if (len &lt; 0) &#123;</span></span><br><span class="line"><span class="addition">+                return -TARGET_EFAULT;</span></span><br><span class="line"><span class="addition">+            &#125;</span></span><br><span class="line"><span class="addition">+            char *env = lock_user(VERIFY_WRITE, gp, (long)(len + 1), 0);</span></span><br><span class="line"><span class="addition">+            if (!env)</span></span><br><span class="line"><span class="addition">+                goto execve_efault;</span></span><br><span class="line"><span class="addition">+            if (!strncmp(&quot;LD_PRELOAD=&quot;, env, 11)) &#123;</span></span><br><span class="line"><span class="addition">+                char *p, *q, *r;</span></span><br><span class="line"><span class="addition">+                if ((q = r = strstr(env +11, &quot;libqasan.so&quot;)) != NULL) &#123;</span></span><br><span class="line"><span class="addition">+                    size_t mlen = strlen(&quot;libqasan.so&quot;);</span></span><br><span class="line"><span class="addition">+                    while ((r = strstr(p = r + mlen, &quot;libqasan.so&quot;)) != NULL) &#123;</span></span><br><span class="line"><span class="addition">+                        while (p &lt; r)</span></span><br><span class="line"><span class="addition">+                            *q++ = *p++;</span></span><br><span class="line"><span class="addition">+                    &#125;</span></span><br><span class="line"><span class="addition">+                    while ((*q++ = *p++) != &#x27;\0&#x27;)</span></span><br><span class="line"><span class="addition">+                        continue;</span></span><br><span class="line"><span class="addition">+                &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+            &#125;</span></span><br><span class="line"><span class="addition">+            unlock_user(env, gp, (long)(len + 1));</span></span><br><span class="line"><span class="addition">+        &#125;</span></span><br><span class="line">         envc++;</span><br><span class="line">     &#125;</span><br><span class="line"> </span><br><span class="line"><span class="meta">@@ -13864,6 +13905,15 @@</span> static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,</span><br><span class="line">         return ret;</span><br><span class="line"> #endif</span><br><span class="line"> </span><br><span class="line"><span class="addition">+    case QASAN_FAKESYS_NR:</span></span><br><span class="line"><span class="addition">+        /* QASAN syscall */</span></span><br><span class="line"><span class="addition">+        if (use_qasan) &#123;</span></span><br><span class="line"><span class="addition">+          return qasan_actions_dispatcher(cpu_env, arg1, arg2, arg3, arg4);</span></span><br><span class="line"><span class="addition">+        &#125; else &#123;</span></span><br><span class="line"><span class="addition">+          fprintf(stderr, &quot;QAsan syscall unsupported without enabling QASan mode (AFL_USE_QASAN)\n&quot;);</span></span><br><span class="line"><span class="addition">+          return -TARGET_ENOSYS;</span></span><br><span class="line"><span class="addition">+        &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"> #if defined(TARGET_NR_pivot_root)</span><br></pre></td></tr></table></figure><p><code>syscall.c</code> 文件主要处理系统调用相关指令。该补丁主要进行了三类修改：</p><ul><li>新增 brk 相关的 AFL&#x2F;QASAN 辅助函数</li><li>execve 环境变量处理增强：自动移除 LD_PRELOAD 中的 libqasan.so</li><li>新增 QASAN 的 “fake syscall” 接口，用于与 QASAN 交互</li></ul><ol start="6"><li><code>linux-user/mips/cpu_loop.c</code>文件patch 内容如下所示：</li></ol><figure class="highlight patch"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">diff --git a/linux-user/mips/cpu_loop.c b/linux-user/mips/cpu_loop.c</span></span><br><span class="line"><span class="comment">index 6405806eb0..ce6a620b7f 100644</span></span><br><span class="line"><span class="comment">--- a/linux-user/mips/cpu_loop.c</span></span><br><span class="line"><span class="comment">+++ b/linux-user/mips/cpu_loop.c</span></span><br><span class="line"><span class="meta">@@ -26,6 +26,9 @@</span></span><br><span class="line"> #include &quot;internal.h&quot;</span><br><span class="line"> #include &quot;fpu_helper.h&quot;</span><br><span class="line"> </span><br><span class="line"><span class="addition">+/* MIPS_PATCH */</span></span><br><span class="line"><span class="addition">+#include &quot;qemuafl/common.h&quot;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"> # ifdef TARGET_ABI_MIPSO32</span><br><span class="line"> #  define MIPS_SYSCALL_NUMBER_UNUSED -1</span><br><span class="line"> static const int8_t mips_syscall_args[] = &#123;</span><br><span class="line"><span class="meta">@@ -78,6 +81,18 @@</span> void cpu_loop(CPUMIPSState *env)</span><br><span class="line"> </span><br><span class="line">         switch(trapnr) &#123;</span><br><span class="line">         case EXCP_SYSCALL:</span><br><span class="line"><span class="addition">+            if (</span></span><br><span class="line"><span class="addition">+                persistent_exits &amp;&amp;</span></span><br><span class="line"><span class="addition">+                (</span></span><br><span class="line"><span class="addition">+                     env-&gt;active_tc.gpr[2] == TARGET_NR_exit_group ||</span></span><br><span class="line"><span class="addition">+                     // uclibc may use the following signal instead of</span></span><br><span class="line"><span class="addition">+                     // exit_group:</span></span><br><span class="line"><span class="addition">+                     env-&gt;active_tc.gpr[2] == TARGET_NR_exit</span></span><br><span class="line"><span class="addition">+                )</span></span><br><span class="line"><span class="addition">+            ) &#123;</span></span><br><span class="line"><span class="addition">+              env-&gt;active_tc.PC = afl_persistent_addr;</span></span><br><span class="line"><span class="addition">+              continue;</span></span><br><span class="line"><span class="addition">+            &#125;</span></span><br><span class="line">             env-&gt;active_tc.PC += 4;</span><br><span class="line"> # ifdef TARGET_ABI_MIPSO32</span><br><span class="line">             syscall_num = env-&gt;active_tc.gpr[2] - 4000;</span><br></pre></td></tr></table></figure><p><code>linux-user/&#123;arch&#125;/cpu_loop.c</code> 文件包含 QEMU 执行客户端代码的主要函数。AFL 在该文件中添加的内容为：在<code>persistent</code>模式下，如果遇到<code>exit</code>或<code>exit_group</code>函数，并不会真正的退出，而是跳转到<code>afl_persistent_addr</code>地址。</p><p>接下来是<code>accel/tcg</code>目录下的代码，在默认情况下，QEMU 仿真的流程为：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Guest CPU 指令  →  TCG IR（中间指令） →  Host 机器码 → 执行</span><br></pre></td></tr></table></figure><p><code>TCG IR</code> 翻译为主机指令的操作即在该目录下完成。</p><ol><li><code>accel/tcg/tcg-runtime.h</code>文件patch 内容如下所示：</li></ol><figure class="highlight patch"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">diff --git a/accel/tcg/tcg-runtime.h b/accel/tcg/tcg-runtime.h</span></span><br><span class="line"><span class="comment">index c23b5e66c4..e71cf0ca52 100644</span></span><br><span class="line"><span class="comment">--- a/accel/tcg/tcg-runtime.h</span></span><br><span class="line"><span class="comment">+++ b/accel/tcg/tcg-runtime.h</span></span><br><span class="line"><span class="meta">@@ -323,3 +323,31 @@</span> DEF_HELPER_FLAGS_4(gvec_leus32, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32)</span><br><span class="line"> DEF_HELPER_FLAGS_4(gvec_leus64, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32)</span><br><span class="line"> </span><br><span class="line"> DEF_HELPER_FLAGS_5(gvec_bitsel, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32)</span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+DEF_HELPER_FLAGS_1(afl_entry_routine, TCG_CALL_NO_RWG, void, env)</span></span><br><span class="line"><span class="addition">+DEF_HELPER_FLAGS_1(afl_persistent_routine, TCG_CALL_NO_RWG, void, env)</span></span><br><span class="line"><span class="addition">+DEF_HELPER_FLAGS_1(afl_maybe_log, TCG_CALL_NO_RWG, void, tl)</span></span><br><span class="line"><span class="addition">+DEF_HELPER_FLAGS_1(afl_maybe_log2, TCG_CALL_NO_RWG, void, tl)</span></span><br><span class="line"><span class="addition">+DEF_HELPER_FLAGS_1(afl_maybe_log_trace, TCG_CALL_NO_RWG, void, tl)</span></span><br><span class="line"><span class="addition">+DEF_HELPER_FLAGS_3(afl_compcov_16, TCG_CALL_NO_RWG, void, tl, tl, tl)</span></span><br><span class="line"><span class="addition">+DEF_HELPER_FLAGS_3(afl_compcov_32, TCG_CALL_NO_RWG, void, tl, tl, tl)</span></span><br><span class="line"><span class="addition">+DEF_HELPER_FLAGS_3(afl_compcov_64, TCG_CALL_NO_RWG, void, tl, tl, tl)</span></span><br><span class="line"><span class="addition">+DEF_HELPER_FLAGS_3(afl_cmplog_8, TCG_CALL_NO_RWG, void, tl, tl, tl)</span></span><br><span class="line"><span class="addition">+DEF_HELPER_FLAGS_3(afl_cmplog_16, TCG_CALL_NO_RWG, void, tl, tl, tl)</span></span><br><span class="line"><span class="addition">+DEF_HELPER_FLAGS_3(afl_cmplog_32, TCG_CALL_NO_RWG, void, tl, tl, tl)</span></span><br><span class="line"><span class="addition">+DEF_HELPER_FLAGS_3(afl_cmplog_64, TCG_CALL_NO_RWG, void, tl, tl, tl)</span></span><br><span class="line"><span class="addition">+DEF_HELPER_FLAGS_1(afl_cmplog_rtn, TCG_CALL_NO_RWG, void, env)</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+DEF_HELPER_FLAGS_5(qasan_fake_instr, TCG_CALL_NO_RWG, tl, env, tl, tl, tl, tl)</span></span><br><span class="line"><span class="addition">+DEF_HELPER_FLAGS_2(qasan_load1, TCG_CALL_NO_RWG, void, env, tl)</span></span><br><span class="line"><span class="addition">+DEF_HELPER_FLAGS_2(qasan_load2, TCG_CALL_NO_RWG, void, env, tl)</span></span><br><span class="line"><span class="addition">+DEF_HELPER_FLAGS_2(qasan_load4, TCG_CALL_NO_RWG, void, env, tl)</span></span><br><span class="line"><span class="addition">+DEF_HELPER_FLAGS_2(qasan_load8, TCG_CALL_NO_RWG, void, env, tl)</span></span><br><span class="line"><span class="addition">+DEF_HELPER_FLAGS_2(qasan_store1, TCG_CALL_NO_RWG, void, env, tl)</span></span><br><span class="line"><span class="addition">+DEF_HELPER_FLAGS_2(qasan_store2, TCG_CALL_NO_RWG, void, env, tl)</span></span><br><span class="line"><span class="addition">+DEF_HELPER_FLAGS_2(qasan_store4, TCG_CALL_NO_RWG, void, env, tl)</span></span><br><span class="line"><span class="addition">+DEF_HELPER_FLAGS_2(qasan_store8, TCG_CALL_NO_RWG, void, env, tl)</span></span><br><span class="line"><span class="addition">+DEF_HELPER_FLAGS_1(qasan_shadow_stack_push, TCG_CALL_NO_RWG, void, tl)</span></span><br><span class="line"><span class="addition">+DEF_HELPER_FLAGS_1(qasan_shadow_stack_pop, TCG_CALL_NO_RWG, void, tl)</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+DEF_HELPER_FLAGS_4(ijon_func_call, TCG_CALL_NO_RWG, void, tl, tl, tl, tl)</span></span><br></pre></td></tr></table></figure><p><code>accel/tcg/tcg-runtime.h</code>头文件主要是用来声明 <code>TCG Helper</code>函数，AFL 在该文件中新增了一些 AFL 相关的<code>Helper</code> 函数。</p><p>下面介绍 <code>TCG Helper</code> 函数的结构。</p><p>1). 在<code>include/exec/helper-proto.h.inc</code>函数中定义了Helper 函数声明的宏。</p><p><code>DEF_HELPER_FLAGS_x</code>为Helper 函数宏，其中 x 标识有几个参数，比如：<code>DEF_HELPER_FLAGS_2</code>表示该函数有两个参数。</p><p>在<code>helper-proto.h.inc</code>文件中的宏为：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> DEF_HELPER_FLAGS_2(name, flags, ret, t1, t2) \</span></span><br><span class="line"><span class="meta">dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2)) DEF_HELPER_ATTR;</span></span><br></pre></td></tr></table></figure><p>若将 <code>DEF_HELPER_FLAGS_2(qasan_load2, TCG_CALL_NO_RWG, void, env, tl)</code> 展开，函数声明为：<code>void helper_qasan_load2(CPUArchState *, i32) __attribute__((noinline));</code>。</p><p>2). 在<code>include/exec/helper-info.h.inc</code>函数中定义了 Helper 函数相关的结构体宏。</p><p>在<code>helper-info.h.inc</code>文件中的宏为：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> DEF_HELPER_FLAGS_2(NAME, FLAGS, RET, T1, T2)                    \</span></span><br><span class="line"><span class="meta">    TCGHelperInfo glue(helper_info_, NAME) = &#123;                          \</span></span><br><span class="line"><span class="meta">        .func = HELPER(NAME), .name = str(NAME),                        \</span></span><br><span class="line"><span class="meta">        .flags = FLAGS | dh_callflag(RET),                              \</span></span><br><span class="line"><span class="meta">        .typemask = dh_typemask(RET, 0) | dh_typemask(T1, 1)            \</span></span><br><span class="line"><span class="meta">                  | dh_typemask(T2, 2)                                  \</span></span><br><span class="line"><span class="meta">    &#125;;</span></span><br></pre></td></tr></table></figure><p>把该宏展开，如下所示：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">TCGHelperInfo helper_info_qasan_load2 = &#123;</span><br><span class="line">.func = helper_qasan_load2, .name = qasan_load2,</span><br><span class="line">.flags = TCG_CALL_NO_RWG | dh_callflag_void,</span><br><span class="line">.typemask = ......</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>3). 在<code>include/exec/helper-gen.h.inc</code>函数中定义了 Helper 函数调用函数宏。</p><p>在<code>helper-gen.h.inc</code>文件中的宏为：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> DEF_HELPER_FLAGS_2(name, flags, ret, t1, t2)                    \</span></span><br><span class="line"><span class="meta">extern TCGHelperInfo glue(helper_info_, name);                          \</span></span><br><span class="line"><span class="meta">static inline void glue(gen_helper_, name)(dh_retvar_decl(ret)          \</span></span><br><span class="line"><span class="meta">    dh_arg_decl(t1, 1), dh_arg_decl(t2, 2))                             \</span></span><br><span class="line"><span class="meta">&#123;                                                                       \</span></span><br><span class="line"><span class="meta">    tcg_gen_call2(glue(helper_info_,name).func,                         \</span></span><br><span class="line"><span class="meta">                  &amp;glue(helper_info_,name), dh_retvar(ret),             \</span></span><br><span class="line"><span class="meta">                  dh_arg(t1, 1), dh_arg(t2, 2));                        \</span></span><br><span class="line"><span class="meta">&#125;</span></span><br></pre></td></tr></table></figure><p>把该宏展开，如下所示：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">extern</span> TCGHelperInfo helper_info_qasan_load2;</span><br><span class="line"><span class="type">static</span> <span class="keyword">inline</span> <span class="type">void</span> <span class="title function_">gen_helper_qasan_load2</span><span class="params">(TCGv_ptr arg1, TCGv_i32 arg2)</span></span><br><span class="line">&#123;</span><br><span class="line">tcg_gen_call2(helper_info_qasan_load2.func,</span><br><span class="line">&amp;helper_info_qasan_load2, <span class="literal">NULL</span>,</span><br><span class="line">tcgv_ptr_temp(arg1), tcgv_i32_temp(arg2));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>最后就是HELPER 函数的实现，如下所示：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">void</span> <span class="title function_">HELPER</span><span class="params">(qasan_load2)</span><span class="params">(CPUArchState *env, target_ulong addr)</span> &#123;</span><br><span class="line">......</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">宏展开后变为：</span><br><span class="line"><span class="type">void</span> <span class="title function_">helper_qasan_load2</span><span class="params">(CPUArchState *env, target_ulong addr)</span> &#123;</span><br><span class="line">......</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>当需要调用 helper 函数时，调用的不是<code>helper_qasan_load2(x, x)</code>，而是<code>gen_helper_qasan_load2(x, x)</code>。</p><ol start="2"><li><code>accel/tcg/tcg-runtime.c</code>文件patch 内容如下所示：</li></ol><figure class="highlight patch"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">diff --git a/accel/tcg/tcg-runtime.c b/accel/tcg/tcg-runtime.c</span></span><br><span class="line"><span class="comment">index fa7ed9739c..56ebdb1261 100644</span></span><br><span class="line"><span class="comment">--- a/accel/tcg/tcg-runtime.c</span></span><br><span class="line"><span class="comment">+++ b/accel/tcg/tcg-runtime.c</span></span><br><span class="line"><span class="meta">@@ -31,6 +31,292 @@</span></span><br><span class="line"> #include &quot;exec/helper-info.c.inc&quot;</span><br><span class="line"> #undef  HELPER_H</span><br><span class="line"> </span><br><span class="line"><span class="addition">+#include &quot;qemuafl/common.h&quot;</span></span><br><span class="line"><span class="addition">+#include &quot;qemuafl/qemu-ijon-support.h&quot;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+uint32_t afl_hash_ip(uint64_t);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+void HELPER(ijon_func_call)(target_ulong var_addr, target_ulong var_len, target_ulong itype, target_ulong idx)</span></span><br><span class="line"><span class="addition">+&#123;</span></span><br><span class="line"><span class="addition">+  uint64_t buf = 0;</span></span><br><span class="line"><span class="addition">+  memcpy(&amp;buf, var_addr, var_len);</span></span><br><span class="line"><span class="addition">+  ijon_dispatch(itype, idx, buf);</span></span><br><span class="line"><span class="addition">+  fprintf(stderr, &quot;trigger ijon: addr=0x%016&quot; PRIx64 &quot; tag=%s value %ld\n&quot;, var_addr, ijon_to_str(itype), buf);</span></span><br><span class="line"><span class="addition">+&#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+void HELPER(afl_entry_routine)(CPUArchState *env) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  afl_forkserver(env_cpu(env));</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+&#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line">...</span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+#include &lt;sys/mman.h&gt;</span></span><br><span class="line"><span class="addition">+#include &quot;linux-user/qemu.h&quot; /* access_ok decls. */</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+/*</span></span><br><span class="line"><span class="addition">+static int area_is_mapped(void *ptr, size_t len) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  char *p = ptr;</span></span><br><span class="line"><span class="addition">+  char *page = (char *)((uintptr_t)p &amp; ~(sysconf(_SC_PAGE_SIZE) - 1));</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  int r = msync(page, (p - page) + len, MS_ASYNC);</span></span><br><span class="line"><span class="addition">+  if (r &lt; 0) return errno != ENOMEM;</span></span><br><span class="line"><span class="addition">+  return 1;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+&#125;</span></span><br><span class="line"><span class="addition">+*/</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line">... </span><br><span class="line"><span class="addition">+/////////////////////////////////////////////////</span></span><br><span class="line"><span class="addition">+//                   QASAN</span></span><br><span class="line"><span class="addition">+/////////////////////////////////////////////////</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+#include &quot;qemuafl/qasan-qemu.h&quot;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+// options</span></span><br><span class="line"><span class="addition">+int qasan_max_call_stack = 16; // QASAN_MAX_CALL_STACK</span></span><br><span class="line"><span class="addition">+int qasan_symbolize = 1; // QASAN_SYMBOLIZE</span></span><br><span class="line"><span class="addition">+int use_qasan = 0;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+__thread int qasan_disabled;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+__thread struct shadow_stack qasan_shadow_stack;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+#ifdef ASAN_GIOVESE</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+#ifndef DO_NOT_USE_QASAN</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+#include &quot;qemuafl/asan-giovese-inl.h&quot;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+#include &lt;sys/types.h&gt;</span></span><br><span class="line"><span class="addition">+#include &lt;sys/syscall.h&gt;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line">...</span><br><span class="line"><span class="addition">+</span></span><br><span class="line"> int32_t HELPER(rem_i32)(int32_t arg1, int32_t arg2)</span><br></pre></td></tr></table></figure><p><code>tcg-runtime.c</code> 原本用于实现 <code>TCG Helper</code> 函数。AFL 在该文件中增加了相关 Helper 函数的实现代码。</p><ol start="3"><li><code>accel/tcg/translator.c</code>文件patch 内容如下所示：</li></ol><figure class="highlight patch"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c</span></span><br><span class="line"><span class="comment">index ef1538b4fc..f33048f522 100644</span></span><br><span class="line"><span class="comment">--- a/accel/tcg/translator.c</span></span><br><span class="line"><span class="comment">+++ b/accel/tcg/translator.c</span></span><br><span class="line"><span class="meta">@@ -21,6 +21,8 @@</span></span><br><span class="line"> #include &quot;disas/disas.h&quot;</span><br><span class="line"> #include &quot;tb-internal.h&quot;</span><br><span class="line"> </span><br><span class="line"><span class="addition">+#include &quot;qemuafl/common.h&quot;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"> static void set_can_do_io(DisasContextBase *db, bool val)</span><br><span class="line"> &#123;</span><br><span class="line">     QEMU_BUILD_BUG_ON(sizeof_field(CPUState, neg.can_do_io) != 1);</span><br><span class="line"><span class="meta">@@ -167,6 +169,34 @@</span> void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns,</span><br><span class="line">             plugin_gen_insn_start(cpu, db);</span><br><span class="line">         &#125;</span><br><span class="line"> </span><br><span class="line"><span class="addition">+        if (db-&gt;pc_next == afl_entry_point) &#123;</span></span><br><span class="line"><span class="addition">+            static bool first = true;</span></span><br><span class="line"><span class="addition">+            /*</span></span><br><span class="line"><span class="addition">+             * We guard this section since we flush the translation cache after</span></span><br><span class="line"><span class="addition">+             * we load the configuration, which in turn means we will need to</span></span><br><span class="line"><span class="addition">+             * re-translate our block. If we were to perform this flush every</span></span><br><span class="line"><span class="addition">+             * time (rather than just when our configuration is first loaded),</span></span><br><span class="line"><span class="addition">+             * we would just end up translation this block repeatedly.</span></span><br><span class="line"><span class="addition">+             */</span></span><br><span class="line"><span class="addition">+            if (first) &#123;</span></span><br><span class="line"><span class="addition">+                afl_setup();</span></span><br><span class="line"><span class="addition">+                /*</span></span><br><span class="line"><span class="addition">+                 * We flush the translation cache here since we may already have</span></span><br><span class="line"><span class="addition">+                 * translated some blocks and included instrumentation in them</span></span><br><span class="line"><span class="addition">+                 * before we have processed the configuration from the</span></span><br><span class="line"><span class="addition">+                 * environment variables which configures which ranges to</span></span><br><span class="line"><span class="addition">+                 * include and exclude. Therefore we may have some blocks in our</span></span><br><span class="line"><span class="addition">+                 * cache which are incorrectly instrumented and cause some</span></span><br><span class="line"><span class="addition">+                 * fuzzing stability or performance problems.</span></span><br><span class="line"><span class="addition">+                 */</span></span><br><span class="line"><span class="addition">+                tb_flush(cpu);</span></span><br><span class="line"><span class="addition">+                first = false;</span></span><br><span class="line"><span class="addition">+            &#125;</span></span><br><span class="line"><span class="addition">+            gen_helper_afl_entry_routine(cpu_env);</span></span><br><span class="line"><span class="addition">+        &#125; else if (db-&gt;pc_next == afl_exit_point) &#123;</span></span><br><span class="line"><span class="addition">+            _exit(0);</span></span><br><span class="line"><span class="addition">+        &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line">         /*</span><br><span class="line">          * Disassemble one instruction.  The translate_insn hook should</span><br><span class="line">          * update db-&gt;pc_next and db-&gt;is_jmp to indicate what should be</span><br></pre></td></tr></table></figure><p>QEMU 进行 <code>Guest CPU 指令 → TCG IR（中间指令）</code> 翻译的主要流程代码位于 <code>translator.c</code> 的 <code>translator_loop</code> 函数中。</p><p>AFL 在该函数中添加了入口流程的代码，当翻译的地址为<code>afl_entry_point</code>时，则调用<code>gen_helper_afl_entry_routine</code>函数，而该函数就是 AFL forkserver 模式通信的核心函数。</p><p>AFL forkserver 工作模式如下：</p><p>AFL 首先 fork 出一个子进程，随后创建两个管道，一个负责输入，一个负责输出。默认情况下，这两个管道的描述符为：<code>FORKSRV_FD</code>, <code>FORKSRV_FD+1</code>。</p><p>在<code>qemuafl/imported/config.h</code>中定义了：<code>#define FORKSRV_FD 198</code>。</p><p>其中<code>FORKSRV_FD</code>负责 AFL-&gt;QEMU 通信，<code>FORKSRV_FD+1</code>负责QEMU-&gt;AFL 通信。</p><p>创建该管道的子进程使用 execve 执行 QEMU，QEMU 进程将继承这两个管道，从而实现 AFL 和 QEMU 的进程间通信。</p><p><code>gen_helper_afl_entry_routine</code>函数的实现代码为：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">void</span> <span class="title function_">HELPER</span><span class="params">(afl_entry_routine)</span><span class="params">(CPUArchState *env)</span> &#123;</span><br><span class="line">  afl_forkserver(env_cpu(env));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>实际上调用的是 <code>afl_forkserver</code> 函数，该函数用于与 AFL 进行握手。若握手失败，则退出并进入原本的 QEMU 流程；若握手成功，则该进程保持与 AFL 通信，并 fork 出一个子进程以继续 QEMU 的后续流程。</p><p>由于是 fork 出的子进程，将完全拷贝一份内存数据，且不影响父进程的内存空间结构。AFL 可借此快速执行每次 fuzz 流程。</p><p>在 <code>afl_forkserver</code> 函数中，还会通过 <code>afl_wait_tsl</code> 函数接收子进程指令翻译的情况，并同步至父进程。这样父进程下次 fork 的子进程可直接执行 <code>Host 机器码</code>，无需重复指令翻译流程，从而大幅提升 QEMU 仿真速度。</p><ol start="4"><li><code>accel/tcg/translate-all.c</code>文件patch 内容如下所示：</li></ol><figure class="highlight patch"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c</span></span><br><span class="line"><span class="comment">index a497c54b80..7a6554b730 100644</span></span><br><span class="line"><span class="comment">--- a/accel/tcg/translate-all.c</span></span><br><span class="line"><span class="comment">+++ b/accel/tcg/translate-all.c</span></span><br><span class="line"><span class="meta">@@ -67,6 +67,104 @@</span></span><br><span class="line"> #include &quot;tcg/perf.h&quot;</span><br><span class="line"> #include &quot;tcg/insn-start-words.h&quot;</span><br><span class="line"> </span><br><span class="line"><span class="addition">+#include &quot;qemuafl/common.h&quot;</span></span><br><span class="line"><span class="addition">+#include &quot;tcg/tcg-op.h&quot;</span></span><br><span class="line"><span class="addition">+#include &quot;qemuafl/imported/afl_hash.h&quot;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+#include &lt;math.h&gt;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+__thread int cur_block_is_good;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+static int afl_track_unstable_log_fd(void) &#123;</span></span><br><span class="line"><span class="addition">+    static bool initialized = false;</span></span><br><span class="line"><span class="addition">+    static int track_fd = -1;</span></span><br><span class="line"><span class="addition">+    if (unlikely(!initialized)) &#123;</span></span><br><span class="line"><span class="addition">+        char * fname = getenv(&quot;AFL_QEMU_TRACK_UNSTABLE&quot;);</span></span><br><span class="line"><span class="addition">+        if (fname != NULL) &#123;</span></span><br><span class="line"><span class="addition">+            track_fd = open(fname, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR);</span></span><br><span class="line"><span class="addition">+        &#125;</span></span><br><span class="line"><span class="addition">+        initialized = true;</span></span><br><span class="line"><span class="addition">+        if (track_fd &gt; 0) dprintf(track_fd, &quot;QEMU UNSTABLE TRACKING ENABLED\n&quot;);</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+    return track_fd;</span></span><br><span class="line"><span class="addition">+&#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+void HELPER(afl_maybe_log)(target_ulong cur_loc) &#123;</span></span><br><span class="line"><span class="addition">+  register uintptr_t afl_idx = cur_loc ^ afl_prev_loc;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  INC_AFL_AREA(afl_idx);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  // afl_prev_loc = ((cur_loc &amp; (MAP_SIZE - 1) &gt;&gt; 1)) |</span></span><br><span class="line"><span class="addition">+  //                ((cur_loc &amp; 1) &lt;&lt; ((int)ceil(log2(MAP_SIZE)) -1));</span></span><br><span class="line"><span class="addition">+  afl_prev_loc = cur_loc &gt;&gt; 1;</span></span><br><span class="line"><span class="addition">+&#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+void HELPER(afl_maybe_log2)(target_ulong cur_loc) &#123;</span></span><br><span class="line"><span class="addition">+  register uintptr_t afl_idx = cur_loc;</span></span><br><span class="line"><span class="addition">+  INC_AFL_AREA(afl_idx);</span></span><br><span class="line"><span class="addition">+&#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+void HELPER(afl_maybe_log_trace)(target_ulong cur_loc) &#123;</span></span><br><span class="line"><span class="addition">+  register uintptr_t afl_idx = cur_loc;</span></span><br><span class="line"><span class="addition">+  INC_AFL_AREA(afl_idx);</span></span><br><span class="line"><span class="addition">+&#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+static target_ulong pc_hash(target_ulong x) &#123;</span></span><br><span class="line"><span class="addition">+    x = ((x &gt;&gt; 16) ^ x) * 0x45d9f3b;</span></span><br><span class="line"><span class="addition">+    x = ((x &gt;&gt; 16) ^ x) * 0x45d9f3b;</span></span><br><span class="line"><span class="addition">+    x = (x &gt;&gt; 16) ^ x;</span></span><br><span class="line"><span class="addition">+    return x;</span></span><br><span class="line"><span class="addition">+&#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+/* Generates TCG code for AFL&#x27;s tracing instrumentation. */</span></span><br><span class="line"><span class="addition">+static void afl_gen_trace(target_ulong cur_loc) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  /* Optimize for cur_loc &gt; afl_end_code, which is the most likely case on</span></span><br><span class="line"><span class="addition">+     Linux systems. */</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  cur_block_is_good = afl_must_instrument(cur_loc);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  if (!cur_block_is_good)</span></span><br><span class="line"><span class="addition">+    return;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  /* Looks like QEMU always maps to fixed locations, so ASLR is not a</span></span><br><span class="line"><span class="addition">+     concern. Phew. But instruction addresses may be aligned. Let&#x27;s mangle</span></span><br><span class="line"><span class="addition">+     the value to get something quasi-uniform. */</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  if (block_cov) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    cur_loc = block_id;</span></span><br><span class="line"><span class="addition">+    ++block_id;</span></span><br><span class="line"><span class="addition">+    if (block_id &gt;= MAP_SIZE) block_id = 5;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    TCGv cur_loc_v = tcg_const_tl(cur_loc);</span></span><br><span class="line"><span class="addition">+    gen_helper_afl_maybe_log2(cur_loc_v);</span></span><br><span class="line"><span class="addition">+    tcg_temp_free(cur_loc_v);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  &#125; else &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    // cur_loc = (cur_loc &gt;&gt; 4) ^ (cur_loc &lt;&lt; 8);</span></span><br><span class="line"><span class="addition">+    // cur_loc &amp;= MAP_SIZE - 1;</span></span><br><span class="line"><span class="addition">+    cur_loc = (uintptr_t)(afl_hash_ip((uint64_t)cur_loc));</span></span><br><span class="line"><span class="addition">+    cur_loc &amp;= (MAP_SIZE - 1);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    /* Implement probabilistic instrumentation by looking at scrambled block</span></span><br><span class="line"><span class="addition">+       address. This keeps the instrumented locations stable across runs. */</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    if (cur_loc &gt;= afl_inst_rms) return;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    TCGv cur_loc_v = tcg_const_tl(cur_loc);</span></span><br><span class="line"><span class="addition">+    if (unlikely(afl_track_unstable_log_fd() &gt;= 0)) &#123;</span></span><br><span class="line"><span class="addition">+      gen_helper_afl_maybe_log_trace(cur_loc_v);</span></span><br><span class="line"><span class="addition">+    &#125; else &#123;</span></span><br><span class="line"><span class="addition">+      gen_helper_afl_maybe_log(cur_loc_v);</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+    tcg_temp_free(cur_loc_v);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+&#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"> TBContext tb_ctx;</span><br><span class="line"> </span><br><span class="line"> /*</span><br><span class="line"><span class="meta">@@ -276,6 +374,7 @@</span> static int setjmp_gen_code(CPUArchState *env, TranslationBlock *tb,</span><br><span class="line">     tcg_func_start(tcg_ctx);</span><br><span class="line"> </span><br><span class="line">     CPUState *cs = env_cpu(env);</span><br><span class="line"><span class="addition">+    afl_gen_trace(pc);</span></span><br><span class="line">     tcg_ctx-&gt;cpu = cs;</span><br><span class="line">     cs-&gt;cc-&gt;tcg_ops-&gt;translate_code(cs, tb, max_insns, pc, host_pc);</span><br><span class="line"> </span><br><span class="line"><span class="meta">@@ -283,9 +382,122 @@</span> static int setjmp_gen_code(CPUArchState *env, TranslationBlock *tb,</span><br><span class="line">     tcg_ctx-&gt;cpu = NULL;</span><br><span class="line">     *max_insns = tb-&gt;icount;</span><br><span class="line"> </span><br><span class="line"><span class="addition">+    /* If we are tracking block instability, then since afl-fuzz will log the ids</span></span><br><span class="line"><span class="addition">+       of the unstable blocks, in fuzzer_stats, we must log these alongside the</span></span><br><span class="line"><span class="addition">+       instruction pointer so that the user can associate these back with the</span></span><br><span class="line"><span class="addition">+       actual binary */</span></span><br><span class="line"><span class="addition">+    int track_fd = afl_track_unstable_log_fd();</span></span><br><span class="line"><span class="addition">+    if (unlikely(track_fd &gt;= 0)) &#123;</span></span><br><span class="line"><span class="addition">+      uint64_t  ip = (uint64_t)pc;</span></span><br><span class="line"><span class="addition">+      uintptr_t block_id = (uintptr_t)(afl_hash_ip(ip));</span></span><br><span class="line"><span class="addition">+      block_id &amp;= (MAP_SIZE - 1);</span></span><br><span class="line"><span class="addition">+      dprintf(track_fd, &quot;BLOCK ID: 0x%016&quot; PRIx64 &quot;, PC: 0x%016zx-0x%016zx\n&quot;,</span></span><br><span class="line"><span class="addition">+              block_id, ip, ip + tb-&gt;size);</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line">     return tcg_gen_code(tcg_ctx, tb, pc);</span><br><span class="line"> &#125;</span><br><span class="line"> </span><br><span class="line"><span class="addition">+/* Called with mmap_lock held for user mode emulation.  */</span></span><br><span class="line"><span class="addition">+TranslationBlock *afl_gen_edge(CPUState *cpu, unsigned long afl_id)</span></span><br><span class="line"><span class="addition">+&#123;</span></span><br><span class="line"><span class="addition">+    CPUArchState *env = cpu-&gt;env_ptr;</span></span><br><span class="line"><span class="addition">+    TranslationBlock *tb;</span></span><br><span class="line"><span class="addition">+    tcg_insn_unit *gen_code_buf;</span></span><br><span class="line"><span class="addition">+    int gen_code_size, search_size;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    assert_memory_lock();</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+ buffer_overflow1:</span></span><br><span class="line"><span class="addition">+    tb = tcg_tb_alloc(tcg_ctx);</span></span><br><span class="line"><span class="addition">+    if (unlikely(!tb)) &#123;</span></span><br><span class="line"><span class="addition">+        /* flush must be done */</span></span><br><span class="line"><span class="addition">+        tb_flush(cpu);</span></span><br><span class="line"><span class="addition">+        mmap_unlock();</span></span><br><span class="line"><span class="addition">+        /* Make the execution loop process the flush as soon as possible.  */</span></span><br><span class="line"><span class="addition">+        cpu-&gt;exception_index = EXCP_INTERRUPT;</span></span><br><span class="line"><span class="addition">+        cpu_loop_exit(cpu);</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    gen_code_buf = tcg_ctx-&gt;code_gen_ptr;</span></span><br><span class="line"><span class="addition">+    tb-&gt;tc.ptr = gen_code_buf;</span></span><br><span class="line"><span class="addition">+    tb-&gt;pc = 0;</span></span><br><span class="line"><span class="addition">+    tb-&gt;cs_base = 0;</span></span><br><span class="line"><span class="addition">+    tb-&gt;flags = 0;</span></span><br><span class="line"><span class="addition">+    tb-&gt;cflags = 0;</span></span><br><span class="line"><span class="addition">+    tb-&gt;trace_vcpu_dstate = *cpu-&gt;trace_dstate;</span></span><br><span class="line"><span class="addition">+    tcg_ctx-&gt;tb_cflags = 0;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    tcg_func_start(tcg_ctx);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    tcg_ctx-&gt;cpu = env_cpu(env);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    target_ulong afl_loc = afl_id &amp; (MAP_SIZE -1);</span></span><br><span class="line"><span class="addition">+    //*afl_dynamic_size = MAX(*afl_dynamic_size, afl_loc);</span></span><br><span class="line"><span class="addition">+    TCGv tmp0 = tcg_const_tl(afl_loc);</span></span><br><span class="line"><span class="addition">+    if (block_cov) </span></span><br><span class="line"><span class="addition">+      gen_helper_afl_maybe_log2(tmp0);</span></span><br><span class="line"><span class="addition">+    else</span></span><br><span class="line"><span class="addition">+      gen_helper_afl_maybe_log(tmp0);</span></span><br><span class="line"><span class="addition">+    tcg_temp_free(tmp0);</span></span><br><span class="line"><span class="addition">+    tcg_gen_goto_tb(0);</span></span><br><span class="line"><span class="addition">+    tcg_gen_exit_tb(tb, 0);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    tcg_ctx-&gt;cpu = NULL;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    trace_translate_block(tb, tb-&gt;pc, tb-&gt;tc.ptr);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    /* generate machine code */</span></span><br><span class="line"><span class="addition">+    tb-&gt;jmp_reset_offset[0] = TB_JMP_RESET_OFFSET_INVALID;</span></span><br><span class="line"><span class="addition">+    tb-&gt;jmp_reset_offset[1] = TB_JMP_RESET_OFFSET_INVALID;</span></span><br><span class="line"><span class="addition">+    tcg_ctx-&gt;tb_jmp_reset_offset = tb-&gt;jmp_reset_offset;</span></span><br><span class="line"><span class="addition">+    if (TCG_TARGET_HAS_direct_jump) &#123;</span></span><br><span class="line"><span class="addition">+        tcg_ctx-&gt;tb_jmp_insn_offset = tb-&gt;jmp_target_arg;</span></span><br><span class="line"><span class="addition">+        tcg_ctx-&gt;tb_jmp_target_addr = NULL;</span></span><br><span class="line"><span class="addition">+    &#125; else &#123;</span></span><br><span class="line"><span class="addition">+        tcg_ctx-&gt;tb_jmp_insn_offset = NULL;</span></span><br><span class="line"><span class="addition">+        tcg_ctx-&gt;tb_jmp_target_addr = tb-&gt;jmp_target_arg;</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    /* ??? Overflow could be handled better here.  In particular, we</span></span><br><span class="line"><span class="addition">+       don&#x27;t need to re-do gen_intermediate_code, nor should we re-do</span></span><br><span class="line"><span class="addition">+       the tcg optimization currently hidden inside tcg_gen_code.  All</span></span><br><span class="line"><span class="addition">+       that should be required is to flush the TBs, allocate a new TB,</span></span><br><span class="line"><span class="addition">+       re-initialize it per above, and re-do the actual code generation.  */</span></span><br><span class="line"><span class="addition">+    gen_code_size = tcg_gen_code(tcg_ctx, tb);</span></span><br><span class="line"><span class="addition">+    if (unlikely(gen_code_size &lt; 0)) &#123;</span></span><br><span class="line"><span class="addition">+        goto buffer_overflow1;</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+    search_size = encode_search(tb, (void *)gen_code_buf + gen_code_size);</span></span><br><span class="line"><span class="addition">+    if (unlikely(search_size &lt; 0)) &#123;</span></span><br><span class="line"><span class="addition">+        goto buffer_overflow1;</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+    tb-&gt;tc.size = gen_code_size;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    qatomic_set(&amp;tcg_ctx-&gt;code_gen_ptr, (void *)</span></span><br><span class="line"><span class="addition">+        ROUND_UP((uintptr_t)gen_code_buf + gen_code_size + search_size,</span></span><br><span class="line"><span class="addition">+                 CODE_GEN_ALIGN));</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    /* init jump list */</span></span><br><span class="line"><span class="addition">+    qemu_spin_init(&amp;tb-&gt;jmp_lock);</span></span><br><span class="line"><span class="addition">+    tb-&gt;jmp_list_head = (uintptr_t)NULL;</span></span><br><span class="line"><span class="addition">+    tb-&gt;jmp_list_next[0] = (uintptr_t)NULL;</span></span><br><span class="line"><span class="addition">+    tb-&gt;jmp_list_next[1] = (uintptr_t)NULL;</span></span><br><span class="line"><span class="addition">+    tb-&gt;jmp_dest[0] = (uintptr_t)NULL;</span></span><br><span class="line"><span class="addition">+    tb-&gt;jmp_dest[1] = (uintptr_t)NULL;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    /* init original jump addresses which have been set during tcg_gen_code() */</span></span><br><span class="line"><span class="addition">+    if (tb-&gt;jmp_reset_offset[0] != TB_JMP_RESET_OFFSET_INVALID) &#123;</span></span><br><span class="line"><span class="addition">+        tb_reset_jump(tb, 0);</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+    if (tb-&gt;jmp_reset_offset[1] != TB_JMP_RESET_OFFSET_INVALID) &#123;</span></span><br><span class="line"><span class="addition">+        tb_reset_jump(tb, 1);</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    return tb;</span></span><br><span class="line"><span class="addition">+&#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"> /* Called with mmap_lock held for user mode emulation.  */</span><br><span class="line"> TranslationBlock *tb_gen_code(CPUState *cpu,</span><br></pre></td></tr></table></figure><p><code>translate-all.c</code> 文件主要用于将 <code>TCG IR</code> 翻译成 <code>Host 机器码</code>。</p><p>该 patch 将 AFL 的 qemu-mode 插桩深度整合进 TCG 代码，使 QEMU 在翻译TB(TCG Block，存储着 TCG IR)时自动生成各种覆盖记录，并添加了 edge TB、生存期概率插桩、不稳定 block 追踪等 AFL 功能。</p><ol start="5"><li><code>accel/tcg/cpu-exec.c</code>文件patch 内容如下所示：</li></ol><figure class="highlight patch"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br><span class="line">350</span><br><span class="line">351</span><br><span class="line">352</span><br><span class="line">353</span><br><span class="line">354</span><br><span class="line">355</span><br><span class="line">356</span><br><span class="line">357</span><br><span class="line">358</span><br><span class="line">359</span><br><span class="line">360</span><br><span class="line">361</span><br><span class="line">362</span><br><span class="line">363</span><br><span class="line">364</span><br><span class="line">365</span><br><span class="line">366</span><br><span class="line">367</span><br><span class="line">368</span><br><span class="line">369</span><br><span class="line">370</span><br><span class="line">371</span><br><span class="line">372</span><br><span class="line">373</span><br><span class="line">374</span><br><span class="line">375</span><br><span class="line">376</span><br><span class="line">377</span><br><span class="line">378</span><br><span class="line">379</span><br><span class="line">380</span><br><span class="line">381</span><br><span class="line">382</span><br><span class="line">383</span><br><span class="line">384</span><br><span class="line">385</span><br><span class="line">386</span><br><span class="line">387</span><br><span class="line">388</span><br><span class="line">389</span><br><span class="line">390</span><br><span class="line">391</span><br><span class="line">392</span><br><span class="line">393</span><br><span class="line">394</span><br><span class="line">395</span><br><span class="line">396</span><br><span class="line">397</span><br><span class="line">398</span><br><span class="line">399</span><br><span class="line">400</span><br><span class="line">401</span><br><span class="line">402</span><br><span class="line">403</span><br><span class="line">404</span><br><span class="line">405</span><br><span class="line">406</span><br><span class="line">407</span><br><span class="line">408</span><br><span class="line">409</span><br><span class="line">410</span><br><span class="line">411</span><br><span class="line">412</span><br><span class="line">413</span><br><span class="line">414</span><br><span class="line">415</span><br><span class="line">416</span><br><span class="line">417</span><br><span class="line">418</span><br><span class="line">419</span><br><span class="line">420</span><br><span class="line">421</span><br><span class="line">422</span><br><span class="line">423</span><br><span class="line">424</span><br><span class="line">425</span><br><span class="line">426</span><br><span class="line">427</span><br><span class="line">428</span><br><span class="line">429</span><br><span class="line">430</span><br><span class="line">431</span><br><span class="line">432</span><br><span class="line">433</span><br><span class="line">434</span><br><span class="line">435</span><br><span class="line">436</span><br><span class="line">437</span><br><span class="line">438</span><br><span class="line">439</span><br><span class="line">440</span><br><span class="line">441</span><br><span class="line">442</span><br><span class="line">443</span><br><span class="line">444</span><br><span class="line">445</span><br><span class="line">446</span><br><span class="line">447</span><br><span class="line">448</span><br><span class="line">449</span><br><span class="line">450</span><br><span class="line">451</span><br><span class="line">452</span><br><span class="line">453</span><br><span class="line">454</span><br><span class="line">455</span><br><span class="line">456</span><br><span class="line">457</span><br><span class="line">458</span><br><span class="line">459</span><br><span class="line">460</span><br><span class="line">461</span><br><span class="line">462</span><br><span class="line">463</span><br><span class="line">464</span><br><span class="line">465</span><br><span class="line">466</span><br><span class="line">467</span><br><span class="line">468</span><br><span class="line">469</span><br><span class="line">470</span><br><span class="line">471</span><br><span class="line">472</span><br><span class="line">473</span><br><span class="line">474</span><br><span class="line">475</span><br><span class="line">476</span><br><span class="line">477</span><br><span class="line">478</span><br><span class="line">479</span><br><span class="line">480</span><br><span class="line">481</span><br><span class="line">482</span><br><span class="line">483</span><br><span class="line">484</span><br><span class="line">485</span><br><span class="line">486</span><br><span class="line">487</span><br><span class="line">488</span><br><span class="line">489</span><br><span class="line">490</span><br><span class="line">491</span><br><span class="line">492</span><br><span class="line">493</span><br><span class="line">494</span><br><span class="line">495</span><br><span class="line">496</span><br><span class="line">497</span><br><span class="line">498</span><br><span class="line">499</span><br><span class="line">500</span><br><span class="line">501</span><br><span class="line">502</span><br><span class="line">503</span><br><span class="line">504</span><br><span class="line">505</span><br><span class="line">506</span><br><span class="line">507</span><br><span class="line">508</span><br><span class="line">509</span><br><span class="line">510</span><br><span class="line">511</span><br><span class="line">512</span><br><span class="line">513</span><br><span class="line">514</span><br><span class="line">515</span><br><span class="line">516</span><br><span class="line">517</span><br><span class="line">518</span><br><span class="line">519</span><br><span class="line">520</span><br><span class="line">521</span><br><span class="line">522</span><br><span class="line">523</span><br><span class="line">524</span><br><span class="line">525</span><br><span class="line">526</span><br><span class="line">527</span><br><span class="line">528</span><br><span class="line">529</span><br><span class="line">530</span><br><span class="line">531</span><br><span class="line">532</span><br><span class="line">533</span><br><span class="line">534</span><br><span class="line">535</span><br><span class="line">536</span><br><span class="line">537</span><br><span class="line">538</span><br><span class="line">539</span><br><span class="line">540</span><br><span class="line">541</span><br><span class="line">542</span><br><span class="line">543</span><br><span class="line">544</span><br><span class="line">545</span><br><span class="line">546</span><br><span class="line">547</span><br><span class="line">548</span><br><span class="line">549</span><br><span class="line">550</span><br><span class="line">551</span><br><span class="line">552</span><br><span class="line">553</span><br><span class="line">554</span><br><span class="line">555</span><br><span class="line">556</span><br><span class="line">557</span><br><span class="line">558</span><br><span class="line">559</span><br><span class="line">560</span><br><span class="line">561</span><br><span class="line">562</span><br><span class="line">563</span><br><span class="line">564</span><br><span class="line">565</span><br><span class="line">566</span><br><span class="line">567</span><br><span class="line">568</span><br><span class="line">569</span><br><span class="line">570</span><br><span class="line">571</span><br><span class="line">572</span><br><span class="line">573</span><br><span class="line">574</span><br><span class="line">575</span><br><span class="line">576</span><br><span class="line">577</span><br><span class="line">578</span><br><span class="line">579</span><br><span class="line">580</span><br><span class="line">581</span><br><span class="line">582</span><br><span class="line">583</span><br><span class="line">584</span><br><span class="line">585</span><br><span class="line">586</span><br><span class="line">587</span><br><span class="line">588</span><br><span class="line">589</span><br><span class="line">590</span><br><span class="line">591</span><br><span class="line">592</span><br><span class="line">593</span><br><span class="line">594</span><br><span class="line">595</span><br><span class="line">596</span><br><span class="line">597</span><br><span class="line">598</span><br><span class="line">599</span><br><span class="line">600</span><br><span class="line">601</span><br><span class="line">602</span><br><span class="line">603</span><br><span class="line">604</span><br><span class="line">605</span><br><span class="line">606</span><br><span class="line">607</span><br><span class="line">608</span><br><span class="line">609</span><br><span class="line">610</span><br><span class="line">611</span><br><span class="line">612</span><br><span class="line">613</span><br><span class="line">614</span><br><span class="line">615</span><br><span class="line">616</span><br><span class="line">617</span><br><span class="line">618</span><br><span class="line">619</span><br><span class="line">620</span><br><span class="line">621</span><br><span class="line">622</span><br><span class="line">623</span><br><span class="line">624</span><br><span class="line">625</span><br><span class="line">626</span><br><span class="line">627</span><br><span class="line">628</span><br><span class="line">629</span><br><span class="line">630</span><br><span class="line">631</span><br><span class="line">632</span><br><span class="line">633</span><br><span class="line">634</span><br><span class="line">635</span><br><span class="line">636</span><br><span class="line">637</span><br><span class="line">638</span><br><span class="line">639</span><br><span class="line">640</span><br><span class="line">641</span><br><span class="line">642</span><br><span class="line">643</span><br><span class="line">644</span><br><span class="line">645</span><br><span class="line">646</span><br><span class="line">647</span><br><span class="line">648</span><br><span class="line">649</span><br><span class="line">650</span><br><span class="line">651</span><br><span class="line">652</span><br><span class="line">653</span><br><span class="line">654</span><br><span class="line">655</span><br><span class="line">656</span><br><span class="line">657</span><br><span class="line">658</span><br><span class="line">659</span><br><span class="line">660</span><br><span class="line">661</span><br><span class="line">662</span><br><span class="line">663</span><br><span class="line">664</span><br><span class="line">665</span><br><span class="line">666</span><br><span class="line">667</span><br><span class="line">668</span><br><span class="line">669</span><br><span class="line">670</span><br><span class="line">671</span><br><span class="line">672</span><br><span class="line">673</span><br><span class="line">674</span><br><span class="line">675</span><br><span class="line">676</span><br><span class="line">677</span><br><span class="line">678</span><br><span class="line">679</span><br><span class="line">680</span><br><span class="line">681</span><br><span class="line">682</span><br><span class="line">683</span><br><span class="line">684</span><br><span class="line">685</span><br><span class="line">686</span><br><span class="line">687</span><br><span class="line">688</span><br><span class="line">689</span><br><span class="line">690</span><br><span class="line">691</span><br><span class="line">692</span><br><span class="line">693</span><br><span class="line">694</span><br><span class="line">695</span><br><span class="line">696</span><br><span class="line">697</span><br><span class="line">698</span><br><span class="line">699</span><br><span class="line">700</span><br><span class="line">701</span><br><span class="line">702</span><br><span class="line">703</span><br><span class="line">704</span><br><span class="line">705</span><br><span class="line">706</span><br><span class="line">707</span><br><span class="line">708</span><br><span class="line">709</span><br><span class="line">710</span><br><span class="line">711</span><br><span class="line">712</span><br><span class="line">713</span><br><span class="line">714</span><br><span class="line">715</span><br><span class="line">716</span><br><span class="line">717</span><br><span class="line">718</span><br><span class="line">719</span><br><span class="line">720</span><br><span class="line">721</span><br><span class="line">722</span><br><span class="line">723</span><br><span class="line">724</span><br><span class="line">725</span><br><span class="line">726</span><br><span class="line">727</span><br><span class="line">728</span><br><span class="line">729</span><br><span class="line">730</span><br><span class="line">731</span><br><span class="line">732</span><br><span class="line">733</span><br><span class="line">734</span><br><span class="line">735</span><br><span class="line">736</span><br><span class="line">737</span><br><span class="line">738</span><br><span class="line">739</span><br><span class="line">740</span><br><span class="line">741</span><br><span class="line">742</span><br><span class="line">743</span><br><span class="line">744</span><br><span class="line">745</span><br><span class="line">746</span><br><span class="line">747</span><br><span class="line">748</span><br><span class="line">749</span><br><span class="line">750</span><br><span class="line">751</span><br><span class="line">752</span><br><span class="line">753</span><br><span class="line">754</span><br><span class="line">755</span><br><span class="line">756</span><br><span class="line">757</span><br><span class="line">758</span><br><span class="line">759</span><br><span class="line">760</span><br><span class="line">761</span><br><span class="line">762</span><br><span class="line">763</span><br><span class="line">764</span><br><span class="line">765</span><br><span class="line">766</span><br><span class="line">767</span><br><span class="line">768</span><br><span class="line">769</span><br><span class="line">770</span><br><span class="line">771</span><br><span class="line">772</span><br><span class="line">773</span><br><span class="line">774</span><br><span class="line">775</span><br><span class="line">776</span><br><span class="line">777</span><br><span class="line">778</span><br><span class="line">779</span><br><span class="line">780</span><br><span class="line">781</span><br><span class="line">782</span><br><span class="line">783</span><br><span class="line">784</span><br><span class="line">785</span><br><span class="line">786</span><br><span class="line">787</span><br><span class="line">788</span><br><span class="line">789</span><br><span class="line">790</span><br><span class="line">791</span><br><span class="line">792</span><br><span class="line">793</span><br><span class="line">794</span><br><span class="line">795</span><br><span class="line">796</span><br><span class="line">797</span><br><span class="line">798</span><br><span class="line">799</span><br><span class="line">800</span><br><span class="line">801</span><br><span class="line">802</span><br><span class="line">803</span><br><span class="line">804</span><br><span class="line">805</span><br><span class="line">806</span><br><span class="line">807</span><br><span class="line">808</span><br><span class="line">809</span><br><span class="line">810</span><br><span class="line">811</span><br><span class="line">812</span><br><span class="line">813</span><br><span class="line">814</span><br><span class="line">815</span><br><span class="line">816</span><br><span class="line">817</span><br><span class="line">818</span><br><span class="line">819</span><br><span class="line">820</span><br><span class="line">821</span><br><span class="line">822</span><br><span class="line">823</span><br><span class="line">824</span><br><span class="line">825</span><br><span class="line">826</span><br><span class="line">827</span><br><span class="line">828</span><br><span class="line">829</span><br><span class="line">830</span><br><span class="line">831</span><br><span class="line">832</span><br><span class="line">833</span><br><span class="line">834</span><br><span class="line">835</span><br><span class="line">836</span><br><span class="line">837</span><br><span class="line">838</span><br><span class="line">839</span><br><span class="line">840</span><br><span class="line">841</span><br><span class="line">842</span><br><span class="line">843</span><br><span class="line">844</span><br><span class="line">845</span><br><span class="line">846</span><br><span class="line">847</span><br><span class="line">848</span><br><span class="line">849</span><br><span class="line">850</span><br><span class="line">851</span><br><span class="line">852</span><br><span class="line">853</span><br><span class="line">854</span><br><span class="line">855</span><br><span class="line">856</span><br><span class="line">857</span><br><span class="line">858</span><br><span class="line">859</span><br><span class="line">860</span><br><span class="line">861</span><br><span class="line">862</span><br><span class="line">863</span><br><span class="line">864</span><br><span class="line">865</span><br><span class="line">866</span><br><span class="line">867</span><br><span class="line">868</span><br><span class="line">869</span><br><span class="line">870</span><br><span class="line">871</span><br><span class="line">872</span><br><span class="line">873</span><br><span class="line">874</span><br><span class="line">875</span><br><span class="line">876</span><br><span class="line">877</span><br><span class="line">878</span><br><span class="line">879</span><br><span class="line">880</span><br><span class="line">881</span><br><span class="line">882</span><br><span class="line">883</span><br><span class="line">884</span><br><span class="line">885</span><br><span class="line">886</span><br><span class="line">887</span><br><span class="line">888</span><br><span class="line">889</span><br><span class="line">890</span><br><span class="line">891</span><br><span class="line">892</span><br><span class="line">893</span><br><span class="line">894</span><br><span class="line">895</span><br><span class="line">896</span><br><span class="line">897</span><br><span class="line">898</span><br><span class="line">899</span><br><span class="line">900</span><br><span class="line">901</span><br><span class="line">902</span><br><span class="line">903</span><br><span class="line">904</span><br><span class="line">905</span><br><span class="line">906</span><br><span class="line">907</span><br><span class="line">908</span><br><span class="line">909</span><br><span class="line">910</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c</span></span><br><span class="line"><span class="comment">index ef3d967e3a..50435b8135 100644</span></span><br><span class="line"><span class="comment">--- a/accel/tcg/cpu-exec.c</span></span><br><span class="line"><span class="comment">+++ b/accel/tcg/cpu-exec.c</span></span><br><span class="line"><span class="meta">@@ -45,6 +45,1581 @@</span></span><br><span class="line"> #include &quot;internal-common.h&quot;</span><br><span class="line"> #include &quot;internal-target.h&quot;</span><br><span class="line"> </span><br><span class="line"><span class="addition">+#include &quot;qemuafl/common.h&quot;</span></span><br><span class="line"><span class="addition">+#include &quot;qemuafl/imported/snapshot-inl.h&quot;</span></span><br><span class="line"><span class="addition">+#include &quot;qemuafl/qemu-ijon-support.h&quot;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+#include &lt;string.h&gt;</span></span><br><span class="line"><span class="addition">+#include &lt;sys/shm.h&gt;</span></span><br><span class="line"><span class="addition">+#ifndef AFL_QEMU_STATIC_BUILD</span></span><br><span class="line"><span class="addition">+  #include &lt;dlfcn.h&gt;</span></span><br><span class="line"><span class="addition">+#endif</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+/***************************</span></span><br><span class="line"><span class="addition">+ * VARIOUS AUXILIARY STUFF *</span></span><br><span class="line"><span class="addition">+ ***************************/</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+/* This is equivalent to afl-as.h: */</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+static unsigned char</span></span><br><span class="line"><span class="addition">+               dummy[MAP_SIZE]; /* costs MAP_SIZE but saves a few instructions */</span></span><br><span class="line"><span class="addition">+unsigned char *afl_area_ptr = dummy;          /* Exported for afl_gen_trace */</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+/* Exported variables populated by the code patched into elfload.c: */</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+abi_ulong afl_entry_point,                      /* ELF entry point (_start) */</span></span><br><span class="line"><span class="addition">+    afl_exit_point,                             /* ELF exit point           */</span></span><br><span class="line"><span class="addition">+    afl_start_code,                             /* .text start pointer      */</span></span><br><span class="line"><span class="addition">+    afl_end_code;                               /* .text end pointer        */</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+struct vmrange* afl_instr_code;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+abi_ulong    afl_persistent_addr, afl_persistent_ret_addr;</span></span><br><span class="line"><span class="addition">+unsigned int afl_persistent_cnt;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+unsigned int block_id = 5;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+u8 afl_compcov_level, block_cov;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+__thread abi_ulong afl_prev_loc;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+struct cmp_map *__afl_cmp_map;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+/* Set in the child process in forkserver mode: */</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+static int forkserver_installed = 0;</span></span><br><span class="line"><span class="addition">+static int disable_caching = 0;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+unsigned char afl_fork_child;</span></span><br><span class="line"><span class="addition">+unsigned int  afl_forksrv_pid;</span></span><br><span class="line"><span class="addition">+unsigned char is_persistent;</span></span><br><span class="line"><span class="addition">+target_long   persistent_stack_offset;</span></span><br><span class="line"><span class="addition">+unsigned char persistent_first_pass = 1;</span></span><br><span class="line"><span class="addition">+unsigned char persistent_exits;</span></span><br><span class="line"><span class="addition">+unsigned char persistent_save_gpr;</span></span><br><span class="line"><span class="addition">+unsigned char persistent_memory;</span></span><br><span class="line"><span class="addition">+int           persisent_retaddr_offset;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+struct api_regs saved_regs;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+u8 * shared_buf;</span></span><br><span class="line"><span class="addition">+u32 *shared_buf_len;</span></span><br><span class="line"><span class="addition">+u8   sharedmem_fuzzing;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+afl_persistent_hook_fn afl_persistent_hook_ptr;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+/* Instrumentation ratio: */</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+unsigned int afl_inst_rms = MAP_SIZE;         /* Exported for afl_gen_trace */</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+/* Function declarations. */</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+static void afl_wait_tsl(CPUState *, int);</span></span><br><span class="line"><span class="addition">+static void afl_request_tsl(target_ulong, target_ulong, uint32_t, uint32_t,</span></span><br><span class="line"><span class="addition">+                            TranslationBlock *, int);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+/* Data structures passed around by the translate handlers: */</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+struct afl_tb &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  target_ulong pc;</span></span><br><span class="line"><span class="addition">+  target_ulong cs_base;</span></span><br><span class="line"><span class="addition">+  uint32_t     flags;</span></span><br><span class="line"><span class="addition">+  uint32_t     cf_mask;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+&#125;;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+struct afl_chain &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  struct afl_tb last_tb;</span></span><br><span class="line"><span class="addition">+  uint32_t      cf_mask;</span></span><br><span class="line"><span class="addition">+  int           tb_exit;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+&#125;;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+struct afl_tsl &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  struct afl_tb tb;</span></span><br><span class="line"><span class="addition">+  struct afl_chain chain;</span></span><br><span class="line"><span class="addition">+  char is_chain;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+&#125;;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+/* Some forward decls: */</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+static inline TranslationBlock *tb_find(CPUState *, TranslationBlock *, int,</span></span><br><span class="line"><span class="addition">+                                        uint32_t);</span></span><br><span class="line"><span class="addition">+static inline void              tb_add_jump(TranslationBlock *tb, int n,</span></span><br><span class="line"><span class="addition">+                                            TranslationBlock *tb_next);</span></span><br><span class="line"><span class="addition">+static void                     afl_map_shm_fuzz(void);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+/*************************</span></span><br><span class="line"><span class="addition">+ * ACTUAL IMPLEMENTATION *</span></span><br><span class="line"><span class="addition">+ *************************/</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+/* Snapshot memory */</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+struct saved_region &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  void* addr;</span></span><br><span class="line"><span class="addition">+  size_t size;</span></span><br><span class="line"><span class="addition">+  void* saved;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+&#125;;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+abi_ulong saved_brk;</span></span><br><span class="line"><span class="addition">+int lkm_snapshot;</span></span><br><span class="line"><span class="addition">+struct saved_region* memory_snapshot;</span></span><br><span class="line"><span class="addition">+size_t memory_snapshot_len;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line">...</span><br><span class="line"><span class="addition">+void afl_setup(void) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  char *id_str = getenv(SHM_ENV_VAR), *inst_r = getenv(&quot;AFL_INST_RATIO&quot;);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  int shm_id;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  if (inst_r) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    unsigned int r;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    r = atoi(inst_r);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    if (r &gt; 100) r = 100;</span></span><br><span class="line"><span class="addition">+    if (!r) r = 1;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    afl_inst_rms = MAP_SIZE * r / 100;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  if (id_str) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    shm_id = atoi(id_str);</span></span><br><span class="line"><span class="addition">+    afl_area_ptr = shmat(shm_id, NULL, 0);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    if (afl_area_ptr == (void *)-1) exit(1);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    /* With AFL_INST_RATIO set to a low value, we want to touch the bitmap</span></span><br><span class="line"><span class="addition">+       so that the parent doesn&#x27;t give up on us. */</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    if (inst_r) afl_area_ptr[0] = 1;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  disable_caching = getenv(&quot;AFL_QEMU_DISABLE_CACHE&quot;) != NULL;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  if (getenv(&quot;___AFL_EINS_ZWEI_POLIZEI___&quot;)) &#123;  // CmpLog forkserver</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    id_str = getenv(CMPLOG_SHM_ENV_VAR);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    if (id_str) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+      u32 shm_id = atoi(id_str);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+      __afl_cmp_map = shmat(shm_id, NULL, 0);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+      if (__afl_cmp_map == (void *)-1) exit(1);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  if (getenv(&quot;AFL_INST_LIBS&quot;)) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    afl_start_code = 0;</span></span><br><span class="line"><span class="addition">+    afl_end_code = (abi_ulong)-1;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  if (getenv(&quot;AFL_CODE_START&quot;))</span></span><br><span class="line"><span class="addition">+    afl_start_code = strtoll(getenv(&quot;AFL_CODE_START&quot;), NULL, 16);</span></span><br><span class="line"><span class="addition">+  if (getenv(&quot;AFL_CODE_END&quot;))</span></span><br><span class="line"><span class="addition">+    afl_end_code = strtoll(getenv(&quot;AFL_CODE_END&quot;), NULL, 16);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  int have_names = 0;</span></span><br><span class="line"><span class="addition">+  if (getenv(&quot;AFL_QEMU_INST_RANGES&quot;)) &#123;</span></span><br><span class="line"><span class="addition">+    char *str = getenv(&quot;AFL_QEMU_INST_RANGES&quot;);</span></span><br><span class="line"><span class="addition">+    char *saveptr1, *saveptr2 = NULL, *save_pt1 = NULL;</span></span><br><span class="line"><span class="addition">+    char *pt1, *pt2, *pt3 = NULL;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    while (1) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+      pt1 = strtok_r(str, &quot;,&quot;, &amp;saveptr1);</span></span><br><span class="line"><span class="addition">+      if (pt1 == NULL) break;</span></span><br><span class="line"><span class="addition">+      str = NULL;</span></span><br><span class="line"><span class="addition">+      save_pt1 = strdup(pt1);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+      pt2 = strtok_r(pt1, &quot;-&quot;, &amp;saveptr2);</span></span><br><span class="line"><span class="addition">+      pt3 = strtok_r(NULL, &quot;-&quot;, &amp;saveptr2);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+      struct vmrange* n = calloc(1, sizeof(struct vmrange));</span></span><br><span class="line"><span class="addition">+      n-&gt;next = afl_instr_code;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+      if (pt3 == NULL) &#123; // filename</span></span><br><span class="line"><span class="addition">+        have_names = 1;</span></span><br><span class="line"><span class="addition">+        n-&gt;start = (target_ulong)-1;</span></span><br><span class="line"><span class="addition">+        n-&gt;end = 0;</span></span><br><span class="line"><span class="addition">+        n-&gt;name = save_pt1;</span></span><br><span class="line"><span class="addition">+      &#125; else &#123;</span></span><br><span class="line"><span class="addition">+        n-&gt;start = strtoull(pt2, NULL, 16);</span></span><br><span class="line"><span class="addition">+        n-&gt;end = strtoull(pt3, NULL, 16);</span></span><br><span class="line"><span class="addition">+        if (n-&gt;start &amp;&amp; n-&gt;end) &#123;</span></span><br><span class="line"><span class="addition">+          n-&gt;name = NULL;</span></span><br><span class="line"><span class="addition">+          free(save_pt1);</span></span><br><span class="line"><span class="addition">+        &#125; else &#123;</span></span><br><span class="line"><span class="addition">+          have_names = 1;</span></span><br><span class="line"><span class="addition">+          n-&gt;start = (target_ulong)-1;</span></span><br><span class="line"><span class="addition">+          n-&gt;end = 0;</span></span><br><span class="line"><span class="addition">+          n-&gt;name = save_pt1;</span></span><br><span class="line"><span class="addition">+        &#125;</span></span><br><span class="line"><span class="addition">+      &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+      afl_instr_code = n;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+  &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  if (getenv(&quot;AFL_QEMU_EXCLUDE_RANGES&quot;)) &#123;</span></span><br><span class="line"><span class="addition">+    char *str = getenv(&quot;AFL_QEMU_EXCLUDE_RANGES&quot;);</span></span><br><span class="line"><span class="addition">+    char *saveptr1, *saveptr2 = NULL, *save_pt1;</span></span><br><span class="line"><span class="addition">+    char *pt1, *pt2, *pt3 = NULL;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    while (1) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+      pt1 = strtok_r(str, &quot;,&quot;, &amp;saveptr1);</span></span><br><span class="line"><span class="addition">+      if (pt1 == NULL) break;</span></span><br><span class="line"><span class="addition">+      str = NULL;</span></span><br><span class="line"><span class="addition">+      save_pt1 = strdup(pt1);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+      pt2 = strtok_r(pt1, &quot;-&quot;, &amp;saveptr2);</span></span><br><span class="line"><span class="addition">+      pt3 = strtok_r(NULL, &quot;-&quot;, &amp;saveptr2);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+      struct vmrange* n = calloc(1, sizeof(struct vmrange));</span></span><br><span class="line"><span class="addition">+      n-&gt;exclude = true; // These are &quot;exclusion&quot; regions.</span></span><br><span class="line"><span class="addition">+      n-&gt;next = afl_instr_code;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+      if (pt3 == NULL) &#123; // filename</span></span><br><span class="line"><span class="addition">+        have_names = 1;</span></span><br><span class="line"><span class="addition">+        n-&gt;start = (target_ulong)-1;</span></span><br><span class="line"><span class="addition">+        n-&gt;end = 0;</span></span><br><span class="line"><span class="addition">+        n-&gt;name = save_pt1;</span></span><br><span class="line"><span class="addition">+      &#125; else &#123;</span></span><br><span class="line"><span class="addition">+        n-&gt;start = strtoull(pt2, NULL, 16);</span></span><br><span class="line"><span class="addition">+        n-&gt;end = strtoull(pt3, NULL, 16);</span></span><br><span class="line"><span class="addition">+        if (n-&gt;start &amp;&amp; n-&gt;end) &#123;</span></span><br><span class="line"><span class="addition">+          n-&gt;name = NULL;</span></span><br><span class="line"><span class="addition">+          free(save_pt1);</span></span><br><span class="line"><span class="addition">+        &#125; else &#123;</span></span><br><span class="line"><span class="addition">+          have_names = 1;</span></span><br><span class="line"><span class="addition">+          n-&gt;start = (target_ulong)-1;</span></span><br><span class="line"><span class="addition">+          n-&gt;end = 0;</span></span><br><span class="line"><span class="addition">+          n-&gt;name = save_pt1;</span></span><br><span class="line"><span class="addition">+        &#125;</span></span><br><span class="line"><span class="addition">+      &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+      afl_instr_code = n;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+  &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  if (have_names) &#123;</span></span><br><span class="line"><span class="addition">+    GSList *map_info = read_self_maps();</span></span><br><span class="line"><span class="addition">+    for (GSList *s = map_info; s; s = g_slist_next(s)) &#123;</span></span><br><span class="line"><span class="addition">+      MapInfo *e = (MapInfo *) s-&gt;data;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+      if (h2g_valid(e-&gt;start)) &#123;</span></span><br><span class="line"><span class="addition">+        unsigned long min = e-&gt;start;</span></span><br><span class="line"><span class="addition">+        unsigned long max = e-&gt;end;</span></span><br><span class="line"><span class="addition">+        int flags = page_get_flags(h2g(min));</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+        max = h2g_valid(max - 1) ? max : (uintptr_t) AFL_G2H(GUEST_ADDR_MAX) + 1;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+        if (page_check_range(h2g(min), max - min, flags) == -1) &#123;</span></span><br><span class="line"><span class="addition">+          continue;</span></span><br><span class="line"><span class="addition">+        &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+        // Now that we have a valid guest address region, compare its</span></span><br><span class="line"><span class="addition">+        // name against the names we care about:</span></span><br><span class="line"><span class="addition">+        target_ulong gmin = h2g(min);</span></span><br><span class="line"><span class="addition">+        target_ulong gmax = h2g(max);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+        struct vmrange* n = afl_instr_code;</span></span><br><span class="line"><span class="addition">+        while (n) &#123;</span></span><br><span class="line"><span class="addition">+          if (n-&gt;name &amp;&amp; strstr(e-&gt;path, n-&gt;name)) &#123;</span></span><br><span class="line"><span class="addition">+            if (gmin &lt; n-&gt;start) n-&gt;start = gmin;</span></span><br><span class="line"><span class="addition">+            if (gmax &gt; n-&gt;end) n-&gt;end = gmax;</span></span><br><span class="line"><span class="addition">+            break;</span></span><br><span class="line"><span class="addition">+          &#125;</span></span><br><span class="line"><span class="addition">+          n = n-&gt;next;</span></span><br><span class="line"><span class="addition">+        &#125;</span></span><br><span class="line"><span class="addition">+      &#125;</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+    free_self_maps(map_info);</span></span><br><span class="line"><span class="addition">+  &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  if (getenv(&quot;AFL_DEBUG&quot;) &amp;&amp; afl_instr_code) &#123;</span></span><br><span class="line"><span class="addition">+    struct vmrange* n = afl_instr_code;</span></span><br><span class="line"><span class="addition">+    while (n) &#123;</span></span><br><span class="line"><span class="addition">+      if (n-&gt;exclude) &#123;</span></span><br><span class="line"><span class="addition">+        fprintf(stderr, &quot;Exclude range: 0x%lx-0x%lx (%s)\n&quot;,</span></span><br><span class="line"><span class="addition">+                (unsigned long)n-&gt;start, (unsigned long)n-&gt;end,</span></span><br><span class="line"><span class="addition">+                n-&gt;name ? n-&gt;name : &quot;&lt;noname&gt;&quot;);</span></span><br><span class="line"><span class="addition">+      &#125; else &#123;</span></span><br><span class="line"><span class="addition">+        fprintf(stderr, &quot;Instrument range: 0x%lx-0x%lx (%s)\n&quot;,</span></span><br><span class="line"><span class="addition">+                (unsigned long)n-&gt;start, (unsigned long)n-&gt;end,</span></span><br><span class="line"><span class="addition">+                n-&gt;name ? n-&gt;name : &quot;&lt;noname&gt;&quot;);</span></span><br><span class="line"><span class="addition">+      &#125;</span></span><br><span class="line"><span class="addition">+      n = n-&gt;next;</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+  &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  /* Maintain for compatibility */</span></span><br><span class="line"><span class="addition">+  if (getenv(&quot;AFL_QEMU_COMPCOV&quot;)) &#123; afl_compcov_level = 1; &#125;</span></span><br><span class="line"><span class="addition">+  if (getenv(&quot;AFL_COMPCOV_LEVEL&quot;)) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    afl_compcov_level = atoi(getenv(&quot;AFL_COMPCOV_LEVEL&quot;));</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  /* pthread_atfork() seems somewhat broken in util/rcu.c, and I&#x27;m</span></span><br><span class="line"><span class="addition">+     not entirely sure what is the cause. This disables that</span></span><br><span class="line"><span class="addition">+     behaviour, and seems to work alright? */</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  rcu_disable_atfork();</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  if (getenv(&quot;AFL_QEMU_PERSISTENT_HOOK&quot;)) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+#ifdef AFL_QEMU_STATIC_BUILD</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    fprintf(stderr,</span></span><br><span class="line"><span class="addition">+            &quot;[AFL] ERROR: you cannot use AFL_QEMU_PERSISTENT_HOOK when &quot;</span></span><br><span class="line"><span class="addition">+            &quot;afl-qemu-trace is static\n&quot;);</span></span><br><span class="line"><span class="addition">+    exit(1);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+#else</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    persistent_save_gpr = 1;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    void *plib = dlopen(getenv(&quot;AFL_QEMU_PERSISTENT_HOOK&quot;), RTLD_NOW);</span></span><br><span class="line"><span class="addition">+    if (!plib) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+      fprintf(stderr, &quot;[AFL] ERROR: invalid AFL_QEMU_PERSISTENT_HOOK=%s - %s\n&quot;,</span></span><br><span class="line"><span class="addition">+              getenv(&quot;AFL_QEMU_PERSISTENT_HOOK&quot;),</span></span><br><span class="line"><span class="addition">+              dlerror());</span></span><br><span class="line"><span class="addition">+      exit(1);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    int (*afl_persistent_hook_init_ptr)(void) =</span></span><br><span class="line"><span class="addition">+        dlsym(plib, &quot;afl_persistent_hook_init&quot;);</span></span><br><span class="line"><span class="addition">+    if (afl_persistent_hook_init_ptr)</span></span><br><span class="line"><span class="addition">+      sharedmem_fuzzing = afl_persistent_hook_init_ptr();</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    afl_persistent_hook_ptr = dlsym(plib, &quot;afl_persistent_hook&quot;);</span></span><br><span class="line"><span class="addition">+    if (!afl_persistent_hook_ptr) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+      fprintf(stderr,</span></span><br><span class="line"><span class="addition">+              &quot;[AFL] ERROR: failed to find the function &quot;</span></span><br><span class="line"><span class="addition">+              &quot;\&quot;afl_persistent_hook\&quot; in %s\n&quot;,</span></span><br><span class="line"><span class="addition">+              getenv(&quot;AFL_QEMU_PERSISTENT_HOOK&quot;));</span></span><br><span class="line"><span class="addition">+      exit(1);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+#endif</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  if (__afl_cmp_map) return; // no persistent for cmplog</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  is_persistent = getenv(&quot;AFL_QEMU_PERSISTENT_ADDR&quot;) != NULL;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  if (is_persistent)</span></span><br><span class="line"><span class="addition">+    afl_persistent_addr = strtoll(getenv(&quot;AFL_QEMU_PERSISTENT_ADDR&quot;), NULL, 0);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  if (getenv(&quot;AFL_QEMU_PERSISTENT_RET&quot;))</span></span><br><span class="line"><span class="addition">+    afl_persistent_ret_addr =</span></span><br><span class="line"><span class="addition">+        strtoll(getenv(&quot;AFL_QEMU_PERSISTENT_RET&quot;), NULL, 0);</span></span><br><span class="line"><span class="addition">+  /* If AFL_QEMU_PERSISTENT_RET is not specified patch the return addr */</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  if (getenv(&quot;AFL_QEMU_PERSISTENT_GPR&quot;)) persistent_save_gpr = 1;</span></span><br><span class="line"><span class="addition">+  if (getenv(&quot;AFL_QEMU_PERSISTENT_MEM&quot;))</span></span><br><span class="line"><span class="addition">+    persistent_memory = 1;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  if (getenv(&quot;AFL_QEMU_PERSISTENT_RETADDR_OFFSET&quot;))</span></span><br><span class="line"><span class="addition">+    persisent_retaddr_offset =</span></span><br><span class="line"><span class="addition">+        strtoll(getenv(&quot;AFL_QEMU_PERSISTENT_RETADDR_OFFSET&quot;), NULL, 0);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  if (getenv(&quot;AFL_QEMU_PERSISTENT_CNT&quot;))</span></span><br><span class="line"><span class="addition">+    afl_persistent_cnt = strtoll(getenv(&quot;AFL_QEMU_PERSISTENT_CNT&quot;), NULL, 0);</span></span><br><span class="line"><span class="addition">+  else</span></span><br><span class="line"><span class="addition">+    afl_persistent_cnt = 0;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  if (getenv(&quot;AFL_QEMU_PERSISTENT_EXITS&quot;)) persistent_exits = 1;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  // TODO persistent exits for other archs not x86</span></span><br><span class="line"><span class="addition">+  // TODO persistent mode for other archs not x86</span></span><br><span class="line"><span class="addition">+  // TODO cmplog rtn for arm</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  if (getenv(&quot;AFL_QEMU_SNAPSHOT&quot;)) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    is_persistent = 1;</span></span><br><span class="line"><span class="addition">+    persistent_save_gpr = 1;</span></span><br><span class="line"><span class="addition">+    persistent_memory = 1;</span></span><br><span class="line"><span class="addition">+    persistent_exits = 1;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    if (afl_persistent_addr == 0)</span></span><br><span class="line"><span class="addition">+      afl_persistent_addr = strtoll(getenv(&quot;AFL_QEMU_SNAPSHOT&quot;), NULL, 0);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  if (persistent_memory &amp;&amp; afl_snapshot_init() &gt;= 0)</span></span><br><span class="line"><span class="addition">+    lkm_snapshot = 1;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  if (getenv(&quot;AFL_DEBUG&quot;)) &#123;</span></span><br><span class="line"><span class="addition">+    if (is_persistent)</span></span><br><span class="line"><span class="addition">+      fprintf(stderr, &quot;Persistent: 0x%lx [0x%lx] %s%s%s\n&quot;,</span></span><br><span class="line"><span class="addition">+              (unsigned long)afl_persistent_addr,</span></span><br><span class="line"><span class="addition">+              (unsigned long)afl_persistent_ret_addr,</span></span><br><span class="line"><span class="addition">+              (persistent_save_gpr ? &quot;gpr &quot;: &quot;&quot;),</span></span><br><span class="line"><span class="addition">+              (persistent_memory ? &quot;mem &quot;: &quot;&quot;),</span></span><br><span class="line"><span class="addition">+              (persistent_exits ? &quot;exits &quot;: &quot;&quot;));</span></span><br><span class="line"><span class="addition">+  &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  qemu_ijon_init();</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+&#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+/* Fork server logic, invoked once we hit _start. */</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+void afl_forkserver(CPUState *cpu) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  if (forkserver_installed == 1) return;</span></span><br><span class="line"><span class="addition">+  forkserver_installed = 1;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  if (getenv(&quot;AFL_QEMU_DEBUG_MAPS&quot;)) open_self_maps(cpu-&gt;env_ptr, 1);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  u32 __afl_old_forkserver = 0;</span></span><br><span class="line"><span class="addition">+  pid_t child_pid;</span></span><br><span class="line"><span class="addition">+  int   t_fd[2];</span></span><br><span class="line"><span class="addition">+  u8    child_stopped = 0;</span></span><br><span class="line"><span class="addition">+  u32   was_killed;</span></span><br><span class="line"><span class="addition">+  u32 version = 0x41464c00 + FS_NEW_VERSION_MAX;</span></span><br><span class="line"><span class="addition">+  u32 tmp = version ^ 0xffffffff, status2, status = version;</span></span><br><span class="line"><span class="addition">+  u8 *msg = (u8 *)&amp;status;</span></span><br><span class="line"><span class="addition">+  u8 *reply = (u8 *)&amp;status2;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  if (getenv(&quot;AFL_DEBUG&quot;))</span></span><br><span class="line"><span class="addition">+    fprintf(stderr, &quot;Debug: Sending status 0x%08x\n&quot;, status);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  if (getenv(&quot;AFL_OLD_FORKSERVER&quot;)) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    __afl_old_forkserver = 1;</span></span><br><span class="line"><span class="addition">+    status = 0;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    fprintf(stderr, &quot;The current version of afl++ qemu mode &quot;</span></span><br><span class="line"><span class="addition">+      &quot;supports forkserver v1, but afl-fuzz still retains &quot;</span></span><br><span class="line"><span class="addition">+      &quot;support for the old forkserver (qemu) version\n&quot;);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  /* Tell the parent that we&#x27;re alive. If the parent doesn&#x27;t want</span></span><br><span class="line"><span class="addition">+     to talk, assume that we&#x27;re not running in forkserver mode. */</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  if (write(FORKSRV_FD + 1, msg, 4) != 4) return;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  afl_forksrv_pid = getpid();</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  int first_run = 1;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  if (!__afl_old_forkserver) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    if (read(FORKSRV_FD, reply, 4) != 4) &#123; _exit(1); &#125;</span></span><br><span class="line"><span class="addition">+    if (tmp != status2) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+      fprintf(stderr, &quot;wrong forkserver message from AFL++ tool&quot;);</span></span><br><span class="line"><span class="addition">+      _exit(1);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    // send the set/requested options to forkserver</span></span><br><span class="line"><span class="addition">+    status = FS_NEW_OPT_MAPSIZE;  // we always send the map size</span></span><br><span class="line"><span class="addition">+    if (lkm_snapshot) status |= FS_OPT_SNAPSHOT;</span></span><br><span class="line"><span class="addition">+    if (sharedmem_fuzzing) status |= FS_NEW_OPT_SHDMEM_FUZZ;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    u32 __afl_map_size = MAP_SIZE;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    if (use_ijon) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+      __afl_map_size = (((__afl_map_size + 63) &gt;&gt; 6) &lt;&lt; 6);</span></span><br><span class="line"><span class="addition">+      __afl_map_size += MAP_SIZE_IJON_MAP + MAP_SIZE_IJON_BYTES;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+      ijon_map_ptr = afl_area_ptr + MAP_SIZE;</span></span><br><span class="line"><span class="addition">+      ijon_max_ptr = (uint64_t*)(ijon_map_ptr + MAP_SIZE_IJON_MAP);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+      status |= FS_OPT_IJON;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    if (write(FORKSRV_FD + 1, msg, 4) != 4) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+      errno = 0;</span></span><br><span class="line"><span class="addition">+      _exit(1);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    // Now send the parameters for the set options, increasing by option number</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    // FS_NEW_OPT_MAPSIZE - we always send the map size</span></span><br><span class="line"><span class="addition">+    status = __afl_map_size;</span></span><br><span class="line"><span class="addition">+    if (write(FORKSRV_FD + 1, msg, 4) != 4) &#123; _exit(1); &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    // send welcome message as final message</span></span><br><span class="line"><span class="addition">+    status = version;</span></span><br><span class="line"><span class="addition">+    if (write(FORKSRV_FD + 1, msg, 4) != 4) &#123; _exit(1); &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  // END forkserver handshake</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  if (sharedmem_fuzzing) &#123; afl_map_shm_fuzz(); &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  /* All right, let&#x27;s await orders... */</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  while (1) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    /* Whoops, parent dead? */</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    if (read(FORKSRV_FD, &amp;was_killed, 4) != 4) exit(2);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    /* If we stopped the child in persistent mode, but there was a race</span></span><br><span class="line"><span class="addition">+       condition and afl-fuzz already issued SIGKILL, write off the old</span></span><br><span class="line"><span class="addition">+       process. */</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    if (child_stopped &amp;&amp; was_killed) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+      child_stopped = 0;</span></span><br><span class="line"><span class="addition">+      if (waitpid(child_pid, &amp;status, 0) &lt; 0) exit(8);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    if (!child_stopped) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+      /* Establish a channel with child to grab translation commands. We&#x27;ll</span></span><br><span class="line"><span class="addition">+       read from t_fd[0], child will write to TSL_FD. */</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+      if (pipe(t_fd) || dup2(t_fd[1], TSL_FD) &lt; 0) exit(3);</span></span><br><span class="line"><span class="addition">+      close(t_fd[1]);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+      child_pid = fork();</span></span><br><span class="line"><span class="addition">+      if (child_pid &lt; 0) exit(4);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+      if (!child_pid) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+        /* Child process. Close descriptors and run free. */</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+        afl_fork_child = 1;</span></span><br><span class="line"><span class="addition">+        close(FORKSRV_FD);</span></span><br><span class="line"><span class="addition">+        close(FORKSRV_FD + 1);</span></span><br><span class="line"><span class="addition">+        close(t_fd[0]);</span></span><br><span class="line"><span class="addition">+        return;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+      &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+      /* Parent. */</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+      close(TSL_FD);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    &#125; else &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+      /* Special handling for persistent mode: if the child is alive but</span></span><br><span class="line"><span class="addition">+         currently stopped, simply restart it with SIGCONT. */</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+      kill(child_pid, SIGCONT);</span></span><br><span class="line"><span class="addition">+      child_stopped = 0;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    /* Parent. */</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    if (write(FORKSRV_FD + 1, &amp;child_pid, 4) != 4) exit(5);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    /* Collect translation requests until child dies and closes the pipe. */</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    afl_wait_tsl(cpu, t_fd[0]);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    /* Get and relay exit status to parent. */</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    if (waitpid(child_pid, &amp;status, is_persistent ? WUNTRACED : 0) &lt; 0) exit(6);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    /* In persistent mode, the child stops itself with SIGSTOP to indicate</span></span><br><span class="line"><span class="addition">+       a successful run. In this case, we want to wake it up without forking</span></span><br><span class="line"><span class="addition">+       again. */</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    if (WIFSTOPPED(status))</span></span><br><span class="line"><span class="addition">+      child_stopped = 1;</span></span><br><span class="line"><span class="addition">+    else if (unlikely(first_run &amp;&amp; is_persistent)) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+      fprintf(stderr, &quot;[AFL] ERROR: no persistent iteration executed\n&quot;);</span></span><br><span class="line"><span class="addition">+      exit(12);  // Persistent is wrong</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    first_run = 0;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    if (write(FORKSRV_FD + 1, &amp;status, 4) != 4) exit(7);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+&#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+/* A simplified persistent mode handler, used as explained in</span></span><br><span class="line"><span class="addition">+ * llvm_mode/README.md. */</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+static u32 cycle_cnt;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+void afl_persistent_iter(CPUArchState *env) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  static struct afl_tsl exit_cmd_tsl;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  if (!afl_persistent_cnt || --cycle_cnt) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    if (persistent_memory) restore_memory_snapshot();</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    if (persistent_save_gpr &amp;&amp; !afl_persistent_hook_ptr) &#123;</span></span><br><span class="line"><span class="addition">+      afl_restore_regs(&amp;saved_regs, env);</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    if (!disable_caching) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+      memset(&amp;exit_cmd_tsl, 0, sizeof(struct afl_tsl));</span></span><br><span class="line"><span class="addition">+      exit_cmd_tsl.tb.pc = (target_ulong)(-1);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+      if (write(TSL_FD, &amp;exit_cmd_tsl, sizeof(struct afl_tsl)) !=</span></span><br><span class="line"><span class="addition">+          sizeof(struct afl_tsl)) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+        /* Exit the persistent loop on pipe error */</span></span><br><span class="line"><span class="addition">+        afl_area_ptr = dummy;</span></span><br><span class="line"><span class="addition">+        exit(0);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+      &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    // TODO use only pipe</span></span><br><span class="line"><span class="addition">+    raise(SIGSTOP);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    // now we have shared_buf updated and ready to use</span></span><br><span class="line"><span class="addition">+    if (persistent_save_gpr &amp;&amp; afl_persistent_hook_ptr) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+      struct api_regs hook_regs = saved_regs;</span></span><br><span class="line"><span class="addition">+      afl_persistent_hook_ptr(&amp;hook_regs, guest_base, shared_buf,</span></span><br><span class="line"><span class="addition">+                              *shared_buf_len);</span></span><br><span class="line"><span class="addition">+      afl_restore_regs(&amp;hook_regs, env);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    afl_area_ptr[0] = 1;</span></span><br><span class="line"><span class="addition">+    afl_prev_loc = 0;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  &#125; else &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    afl_area_ptr = dummy;</span></span><br><span class="line"><span class="addition">+    exit(0);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+&#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+void afl_persistent_loop(CPUArchState *env) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  if (!afl_fork_child) return;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  if (persistent_first_pass) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    /* Make sure that every iteration of __AFL_LOOP() starts with a clean slate.</span></span><br><span class="line"><span class="addition">+       On subsequent calls, the parent will take care of that, but on the first</span></span><br><span class="line"><span class="addition">+       iteration, it&#x27;s our job to erase any trace of whatever happened</span></span><br><span class="line"><span class="addition">+       before the loop. */</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    if (is_persistent) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+      memset(afl_area_ptr, 0, MAP_SIZE);</span></span><br><span class="line"><span class="addition">+      afl_area_ptr[0] = 1;</span></span><br><span class="line"><span class="addition">+      afl_prev_loc = 0;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    if (persistent_memory) collect_memory_snapshot();</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    if (persistent_save_gpr) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+      afl_save_regs(&amp;saved_regs, env);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+      if (afl_persistent_hook_ptr) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+        struct api_regs hook_regs = saved_regs;</span></span><br><span class="line"><span class="addition">+        afl_persistent_hook_ptr(&amp;hook_regs, guest_base, shared_buf,</span></span><br><span class="line"><span class="addition">+                                *shared_buf_len);</span></span><br><span class="line"><span class="addition">+        afl_restore_regs(&amp;hook_regs, env);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+      &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    cycle_cnt = afl_persistent_cnt;</span></span><br><span class="line"><span class="addition">+    persistent_first_pass = 0;</span></span><br><span class="line"><span class="addition">+    persistent_stack_offset = TARGET_LONG_BITS / 8;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    return;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  if (is_persistent) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    afl_persistent_iter(env);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+&#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+/* This code is invoked whenever QEMU decides that it doesn&#x27;t have a</span></span><br><span class="line"><span class="addition">+   translation of a particular block and needs to compute it, or when it</span></span><br><span class="line"><span class="addition">+   decides to chain two TBs together. When this happens, we tell the parent to</span></span><br><span class="line"><span class="addition">+   mirror the operation, so that the next fork() has a cached copy. */</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+static void afl_request_tsl(target_ulong pc, target_ulong cb, uint32_t flags,</span></span><br><span class="line"><span class="addition">+                            uint32_t cf_mask, TranslationBlock *last_tb,</span></span><br><span class="line"><span class="addition">+                            int tb_exit) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  if (disable_caching) return;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  struct afl_tsl t;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  if (!afl_fork_child) return;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  t.tb.pc = pc;</span></span><br><span class="line"><span class="addition">+  t.tb.cs_base = cb;</span></span><br><span class="line"><span class="addition">+  t.tb.flags = flags;</span></span><br><span class="line"><span class="addition">+  t.tb.cf_mask = cf_mask;</span></span><br><span class="line"><span class="addition">+  t.is_chain = (last_tb != NULL);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  if (t.is_chain) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    t.chain.last_tb.pc = last_tb-&gt;pc;</span></span><br><span class="line"><span class="addition">+    t.chain.last_tb.cs_base = last_tb-&gt;cs_base;</span></span><br><span class="line"><span class="addition">+    t.chain.last_tb.flags = last_tb-&gt;flags;</span></span><br><span class="line"><span class="addition">+    t.chain.cf_mask = cf_mask;</span></span><br><span class="line"><span class="addition">+    t.chain.tb_exit = tb_exit;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  if (write(TSL_FD, &amp;t, sizeof(struct afl_tsl)) != sizeof(struct afl_tsl))</span></span><br><span class="line"><span class="addition">+    return;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+&#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+static inline TranslationBlock *</span></span><br><span class="line"><span class="addition">+afl_tb_lookup(CPUState *cpu, target_ulong pc, target_ulong cs_base,</span></span><br><span class="line"><span class="addition">+                     uint32_t flags, uint32_t cf_mask)</span></span><br><span class="line"><span class="addition">+&#123;</span></span><br><span class="line"><span class="addition">+    TranslationBlock *tb;</span></span><br><span class="line"><span class="addition">+    uint32_t hash;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    hash = tb_jmp_cache_hash_func(pc);</span></span><br><span class="line"><span class="addition">+    tb = qatomic_rcu_read(&amp;cpu-&gt;tb_jmp_cache[hash]);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    cf_mask &amp;= ~CF_CLUSTER_MASK;</span></span><br><span class="line"><span class="addition">+    cf_mask |= cpu-&gt;cluster_index &lt;&lt; CF_CLUSTER_SHIFT;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    if (likely(tb &amp;&amp;</span></span><br><span class="line"><span class="addition">+               tb-&gt;pc == pc &amp;&amp;</span></span><br><span class="line"><span class="addition">+               tb-&gt;cs_base == cs_base &amp;&amp;</span></span><br><span class="line"><span class="addition">+               tb-&gt;flags == flags &amp;&amp;</span></span><br><span class="line"><span class="addition">+               tb-&gt;trace_vcpu_dstate == *cpu-&gt;trace_dstate &amp;&amp;</span></span><br><span class="line"><span class="addition">+               (tb_cflags(tb) &amp; (CF_HASH_MASK | CF_INVALID)) == cf_mask)) &#123;</span></span><br><span class="line"><span class="addition">+        return tb;</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+    tb = tb_htable_lookup(cpu, pc, cs_base, flags, cf_mask);</span></span><br><span class="line"><span class="addition">+    if (tb == NULL) &#123;</span></span><br><span class="line"><span class="addition">+        return NULL;</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+    qatomic_set(&amp;cpu-&gt;tb_jmp_cache[hash], tb);</span></span><br><span class="line"><span class="addition">+    return tb;</span></span><br><span class="line"><span class="addition">+&#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+/* This is the other side of the same channel. Since timeouts are handled by</span></span><br><span class="line"><span class="addition">+   afl-fuzz simply killing the child, we can just wait until the pipe breaks. */</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+static void afl_wait_tsl(CPUState *cpu, int fd) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  struct afl_tsl t;</span></span><br><span class="line"><span class="addition">+  TranslationBlock *tb, *last_tb;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  if (disable_caching) return;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  while (1) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    u8 invalid_pc = 0;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    /* Broken pipe means it&#x27;s time to return to the fork server routine. */</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    if (read(fd, &amp;t, sizeof(struct afl_tsl)) != sizeof(struct afl_tsl)) break;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    /* Exit command for persistent */</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    if (t.tb.pc == (target_ulong)(-1)) return;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    tb = afl_tb_lookup(cpu, t.tb.pc, t.tb.cs_base, t.tb.flags, t.tb.cf_mask);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    if (!tb) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+      /* The child may request to transate a block of memory that is not</span></span><br><span class="line"><span class="addition">+         mapped in the parent (e.g. jitted code or dlopened code).</span></span><br><span class="line"><span class="addition">+         This causes a SIGSEV in gen_intermediate_code() and associated</span></span><br><span class="line"><span class="addition">+         subroutines. We simply avoid caching of such blocks. */</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+      if (is_valid_addr(t.tb.pc)) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+        mmap_lock();</span></span><br><span class="line"><span class="addition">+        tb = tb_gen_code(cpu, t.tb.pc, t.tb.cs_base, t.tb.flags, t.tb.cf_mask);</span></span><br><span class="line"><span class="addition">+        mmap_unlock();</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+      &#125; else &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+        invalid_pc = 1;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+      &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    if (t.is_chain &amp;&amp; !invalid_pc) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+      last_tb = afl_tb_lookup(cpu, t.chain.last_tb.pc,</span></span><br><span class="line"><span class="addition">+                                 t.chain.last_tb.cs_base,</span></span><br><span class="line"><span class="addition">+                                 t.chain.last_tb.flags,</span></span><br><span class="line"><span class="addition">+                                 t.chain.cf_mask);</span></span><br><span class="line"><span class="addition">+#define TB_JMP_RESET_OFFSET_INVALID 0xffff</span></span><br><span class="line"><span class="addition">+        if (last_tb &amp;&amp; (last_tb-&gt;jmp_reset_offset[t.chain.tb_exit] !=</span></span><br><span class="line"><span class="addition">+                        TB_JMP_RESET_OFFSET_INVALID)) &#123;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+          tb_add_jump(last_tb, t.chain.tb_exit, tb);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+        &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+  close(fd);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+&#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"> /* -icount align implementation. */</span><br><span class="line"> </span><br><span class="line"> typedef struct SyncClocks &#123;</span><br><span class="line"><span class="meta">@@ -946,6 +2521,7 @@</span> static int __attribute__((noinline))</span><br><span class="line"> cpu_exec_loop(CPUState *cpu, SyncClocks *sc)</span><br><span class="line"> &#123;</span><br><span class="line">     int ret;</span><br><span class="line"><span class="addition">+    bool was_translated = false, was_chained = false;</span></span><br><span class="line"> </span><br><span class="line">     /* if an exception is pending, we execute it here */</span><br><span class="line">     while (!cpu_handle_exception(cpu, &amp;ret)) &#123;</span><br><span class="line"><span class="meta">@@ -985,6 +2561,7 @@</span> cpu_exec_loop(CPUState *cpu, SyncClocks *sc)</span><br><span class="line"> </span><br><span class="line">                 mmap_lock();</span><br><span class="line">                 tb = tb_gen_code(cpu, pc, cs_base, flags, cflags);</span><br><span class="line"><span class="addition">+                was_translated = true;</span></span><br><span class="line">                 mmap_unlock();</span><br><span class="line"> </span><br><span class="line">                 /*</span><br><span class="line"><span class="meta">@@ -1011,6 +2588,11 @@</span> cpu_exec_loop(CPUState *cpu, SyncClocks *sc)</span><br><span class="line">             /* See if we can patch the calling TB. */</span><br><span class="line">             if (last_tb) &#123;</span><br><span class="line">                 tb_add_jump(last_tb, tb_exit, tb);</span><br><span class="line"><span class="addition">+                was_chained = true;</span></span><br><span class="line"><span class="addition">+            &#125;</span></span><br><span class="line"><span class="addition">+            if (was_translated || was_chained) &#123;</span></span><br><span class="line"><span class="addition">+                afl_request_tsl(s.pc, s.cs_base, s.flags, s.cf_mask,</span></span><br><span class="line"><span class="addition">+                                was_chained ? last_tb : NULL, tb_exit);</span></span><br><span class="line">             &#125;</span><br><span class="line"> </span><br><span class="line">             cpu_loop_exec_tb(cpu, tb, pc, &amp;last_tb, &amp;tb_exit);</span><br></pre></td></tr></table></figure><p><code>cpu-exec.c</code> 中的 <code>cpu_exec_loop</code> 函数为 QEMU 仿真的核心函数，调用流程大致如下：</p><ul><li>linux-user&#x2F;main.c 的 main 函数初始化结束后，调用cpu_loop，开始执行目标程序代码。</li><li>cpu_loop 函数位于linux-user&#x2F;{arch}&#x2F;cpu_loop.c 文件中。</li><li>cpu_loop调用accel&#x2F;tcg&#x2F;cpu-exec.c 文件中的<code>cpu_exec</code>函数，进行一些初始化后，执行到cpu_exec_setjmp函数。</li><li>cpu_exec_setjmp 函数的作用相当于使用 try … catch … 执行 cpu_exec_loop 函数。</li><li>cpu_exec_loop 函数执行代码块中的 Host 机器码，若不存在则开始翻译。</li><li>在cpu_exec_loop 函数中，调用tb_lookup根据当前 pc 地址去搜索对应的代码块。如果存在，则直接调用<code>cpu_loop_exec_tb</code>去执行 Host 机器码。</li><li>如果不存在对应的代码块，则调用tb_gen_code开始翻译。</li><li>在tb_gen_code中调用到setjmp_gen_code函数。</li><li>在setjmp_gen_code函数中，首先使用<code>translate_code</code>函数将Guest 指令翻译成 TCG IR。</li><li>translate_code函数位于target&#x2F;{arch}&#x2F;tcg&#x2F;cpu.c 文件中。</li><li>在翻译成 IR 指令后，再调用tcg_gen_code函数，把 IR 指令翻译成 Host 机器码。</li></ul><p>AFL 在该文件中的 patch 是将IJON、snapshot、persistent 模式等功能集成进 QEMU 当中，如下所示：</p><blockquote><p>加入覆盖率共享内存（SHM）映射<br>加入 AFL forkserver 支持<br>加入持久化模式（persistent mode）支持<br>加入持久化模式下 snapshot（快照）&#x2F; restore（恢复）功能<br>加入 IJON（高级指导型 fuzzing）支持<br>加入比较覆盖（CmpCov）支持<br>加入 AFL TB 链跟踪结构（afl_tb, afl_chain 等）<br>加入 sharedmem fuzzing 模式支持<br>加入对 shared memory &#x2F; registers 的 IJON hook 支持<br>扫描并保存 &#x2F;proc&#x2F;self&#x2F;maps 的内存区域<br>在翻译完指令后，会将翻译情况传输给父进程forkserver。</p></blockquote><p>接下来是<code>tcg</code>目录下的代码。</p><ol><li><code>tcg/tcg.c</code>文件patch 内容如下所示：</li></ol><figure class="highlight patch"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">diff --git a/tcg/tcg.c b/tcg/tcg.c</span></span><br><span class="line"><span class="comment">index b1a7465df2..964e91ee32 100644</span></span><br><span class="line"><span class="comment">--- a/tcg/tcg.c</span></span><br><span class="line"><span class="comment">+++ b/tcg/tcg.c</span></span><br><span class="line"><span class="meta">@@ -61,6 +61,8 @@</span></span><br><span class="line"> #include &quot;user/guest-base.h&quot;</span><br><span class="line"> #endif</span><br><span class="line"> </span><br><span class="line"><span class="addition">+#include &quot;qemuafl/common.h&quot;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"> /* Forward declarations for functions declared in tcg-target.c.inc and</span><br><span class="line">    used here. */</span><br><span class="line"> static void tcg_target_init(TCGContext *s);</span><br><span class="line"><span class="meta">@@ -2435,6 +2437,17 @@</span> bool tcg_op_deposit_valid(TCGType type, unsigned ofs, unsigned len)</span><br><span class="line">     return TCG_TARGET_deposit_valid(type, ofs, len);</span><br><span class="line"> &#125;</span><br><span class="line"> </span><br><span class="line"><span class="addition">+void afl_gen_tcg_plain_call(void *func)</span></span><br><span class="line"><span class="addition">+&#123;</span></span><br><span class="line"><span class="addition">+    TCGOp *op = tcg_emit_op(INDEX_op_call);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    TCGOP_CALLO(op) = 0;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+    op-&gt;args[0] = (uintptr_t)func;</span></span><br><span class="line"><span class="addition">+    op-&gt;args[1] = 0;</span></span><br><span class="line"><span class="addition">+    TCGOP_CALLI(op) = 0;</span></span><br><span class="line"><span class="addition">+&#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"> static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs);</span><br></pre></td></tr></table></figure><p>该部分 AFL patch 主要实现一个简单接口，允许在 TCG 翻译过程中插入对指定函数的纯粹函数调用。</p><ol start="2"><li><code>tcg/tcg-op.c</code>文件patch 内容如下所示：</li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br></pre></td><td class="code"><pre><span class="line">diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c</span><br><span class="line">index e2e25ebf7d..e42766c20d <span class="number">100644</span></span><br><span class="line">--- a/tcg/tcg-op.c</span><br><span class="line">+++ b/tcg/tcg-op.c</span><br><span class="line">@@ <span class="number">-32</span>,<span class="number">6</span> +<span class="number">32</span>,<span class="number">25</span> @@</span><br><span class="line"> <span class="meta">#<span class="keyword">include</span> <span class="string">&quot;trace/mem.h&quot;</span></span></span><br><span class="line"> <span class="meta">#<span class="keyword">include</span> <span class="string">&quot;exec/plugin-gen.h&quot;</span></span></span><br><span class="line"> </span><br><span class="line">+<span class="meta">#<span class="keyword">include</span> <span class="string">&quot;qemuafl/qasan-qemu.h&quot;</span></span></span><br><span class="line">+</span><br><span class="line">+<span class="meta">#<span class="keyword">define</span> GEN_QASAN_OP(OP) \</span></span><br><span class="line"><span class="meta">+void qasan_gen_##OP(TCGv addr, int off) &#123; \</span></span><br><span class="line"><span class="meta">+  \</span></span><br><span class="line"><span class="meta">+  <span class="keyword">if</span> (use_qasan &amp;&amp; cur_block_is_good) \</span></span><br><span class="line"><span class="meta">+    gen_helper_qasan_##OP(cpu_env, addr); \</span></span><br><span class="line"><span class="meta">+ \</span></span><br><span class="line"><span class="meta">+&#125;</span></span><br><span class="line">+</span><br><span class="line">+GEN_QASAN_OP(load1)</span><br><span class="line">+GEN_QASAN_OP(load2)</span><br><span class="line">+GEN_QASAN_OP(load4)</span><br><span class="line">+GEN_QASAN_OP(load8)</span><br><span class="line">+GEN_QASAN_OP(store1)</span><br><span class="line">+GEN_QASAN_OP(store2)</span><br><span class="line">+GEN_QASAN_OP(store4)</span><br><span class="line">+GEN_QASAN_OP(store8)</span><br><span class="line">+</span><br><span class="line"></span><br><span class="line">@@ <span class="number">-2836</span>,<span class="number">9</span> +<span class="number">2857</span>,<span class="number">18</span> @@ <span class="type">void</span> <span class="title function_">tcg_gen_qemu_ld_i32</span><span class="params">(TCGv_i32 val, TCGv addr, TCGArg idx, MemOp memop)</span></span><br><span class="line">     &#125;</span><br><span class="line"> </span><br><span class="line">     addr = plugin_prep_mem_callbacks(addr);</span><br><span class="line">+</span><br><span class="line">+    <span class="keyword">switch</span> (memop &amp; MO_SIZE) &#123;</span><br><span class="line">+        <span class="keyword">case</span> MO_64: qasan_gen_load8(addr, idx); <span class="keyword">break</span>;</span><br><span class="line">+        <span class="keyword">case</span> MO_32: qasan_gen_load4(addr, idx); <span class="keyword">break</span>;</span><br><span class="line">+        <span class="keyword">case</span> MO_16: qasan_gen_load2(addr, idx); <span class="keyword">break</span>;</span><br><span class="line">+        <span class="keyword">case</span> MO_8:  qasan_gen_load1(addr, idx); <span class="keyword">break</span>;</span><br><span class="line">+        <span class="keyword">default</span>: qasan_gen_load4(addr, idx); <span class="keyword">break</span>;</span><br><span class="line">+    &#125;</span><br><span class="line">+    </span><br><span class="line">     gen_ldst_i32(INDEX_op_qemu_ld_i32, val, addr, memop, idx);</span><br><span class="line">     plugin_gen_mem_callbacks(addr, info);</span><br><span class="line">-</span><br><span class="line">+    </span><br><span class="line">     <span class="keyword">if</span> ((orig_memop ^ memop) &amp; MO_BSWAP) &#123;</span><br><span class="line">         <span class="keyword">switch</span> (orig_memop &amp; MO_SIZE) &#123;</span><br><span class="line">         <span class="keyword">case</span> MO_16:</span><br><span class="line">@@ <span class="number">-2883</span>,<span class="number">7</span> +<span class="number">2913</span>,<span class="number">20</span> @@ <span class="type">void</span> <span class="title function_">tcg_gen_qemu_st_i32</span><span class="params">(TCGv_i32 val, TCGv addr, TCGArg idx, MemOp memop)</span></span><br><span class="line">     &#125;</span><br><span class="line"> </span><br><span class="line">     addr = plugin_prep_mem_callbacks(addr);</span><br><span class="line">-    gen_ldst_i32(INDEX_op_qemu_st_i32, val, addr, memop, idx);</span><br><span class="line">+</span><br><span class="line">+    <span class="keyword">switch</span> (memop &amp; MO_SIZE) &#123;</span><br><span class="line">+        <span class="keyword">case</span> MO_64: qasan_gen_store8(addr, idx); <span class="keyword">break</span>;</span><br><span class="line">+        <span class="keyword">case</span> MO_32: qasan_gen_store4(addr, idx); <span class="keyword">break</span>;</span><br><span class="line">+        <span class="keyword">case</span> MO_16: qasan_gen_store2(addr, idx); <span class="keyword">break</span>;</span><br><span class="line">+        <span class="keyword">case</span> MO_8:  qasan_gen_store1(addr, idx); <span class="keyword">break</span>;</span><br><span class="line">+        <span class="keyword">default</span>: qasan_gen_store4(addr, idx); <span class="keyword">break</span>;</span><br><span class="line">+    &#125;</span><br><span class="line">+</span><br><span class="line">+    <span class="keyword">if</span> (TCG_TARGET_HAS_qemu_st8_i32 &amp;&amp; (memop &amp; MO_SIZE) == MO_8) &#123;</span><br><span class="line">+        gen_ldst_i32(INDEX_op_qemu_st8_i32, val, addr, memop, idx);</span><br><span class="line">+    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">+        gen_ldst_i32(INDEX_op_qemu_st_i32, val, addr, memop, idx);</span><br><span class="line">+    &#125;</span><br><span class="line">     plugin_gen_mem_callbacks(addr, info);</span><br><span class="line"> </span><br><span class="line">     <span class="keyword">if</span> (swap) &#123;</span><br><span class="line">@@ <span class="number">-2921</span>,<span class="number">6</span> +<span class="number">2964</span>,<span class="number">15</span> @@ <span class="type">void</span> <span class="title function_">tcg_gen_qemu_ld_i64</span><span class="params">(TCGv_i64 val, TCGv addr, TCGArg idx, MemOp memop)</span></span><br><span class="line">     &#125;</span><br><span class="line"> </span><br><span class="line">     addr = plugin_prep_mem_callbacks(addr);</span><br><span class="line">+</span><br><span class="line">+    <span class="keyword">switch</span> (memop &amp; MO_SIZE) &#123;</span><br><span class="line">+        <span class="keyword">case</span> MO_64: qasan_gen_load8(addr, idx); <span class="keyword">break</span>;</span><br><span class="line">+        <span class="keyword">case</span> MO_32: qasan_gen_load4(addr, idx); <span class="keyword">break</span>;</span><br><span class="line">+        <span class="keyword">case</span> MO_16: qasan_gen_load2(addr, idx); <span class="keyword">break</span>;</span><br><span class="line">+        <span class="keyword">case</span> MO_8:  qasan_gen_load1(addr, idx); <span class="keyword">break</span>;</span><br><span class="line">+        <span class="keyword">default</span>: qasan_gen_load8(addr, idx); <span class="keyword">break</span>;</span><br><span class="line">+    &#125;</span><br><span class="line">+    </span><br><span class="line">     gen_ldst_i64(INDEX_op_qemu_ld_i64, val, addr, memop, idx);</span><br><span class="line">     plugin_gen_mem_callbacks(addr, info);</span><br><span class="line"> </span><br><span class="line">@@ <span class="number">-2984</span>,<span class="number">6</span> +<span class="number">3036</span>,<span class="number">15</span> @@ <span class="type">void</span> <span class="title function_">tcg_gen_qemu_st_i64</span><span class="params">(TCGv_i64 val, TCGv addr, TCGArg idx, MemOp memop)</span></span><br><span class="line">     &#125;</span><br><span class="line"> </span><br><span class="line">     addr = plugin_prep_mem_callbacks(addr);</span><br><span class="line">+</span><br><span class="line">+    <span class="keyword">switch</span> (memop &amp; MO_SIZE) &#123;</span><br><span class="line">+        <span class="keyword">case</span> MO_64: qasan_gen_store8(addr, idx); <span class="keyword">break</span>;</span><br><span class="line">+        <span class="keyword">case</span> MO_32: qasan_gen_store4(addr, idx); <span class="keyword">break</span>;</span><br><span class="line">+        <span class="keyword">case</span> MO_16: qasan_gen_store2(addr, idx); <span class="keyword">break</span>;</span><br><span class="line">+        <span class="keyword">case</span> MO_8:  qasan_gen_store1(addr, idx); <span class="keyword">break</span>;</span><br><span class="line">+        <span class="keyword">default</span>: qasan_gen_store8(addr, idx); <span class="keyword">break</span>;</span><br><span class="line">+    &#125;</span><br><span class="line">+</span><br><span class="line">     gen_ldst_i64(INDEX_op_qemu_st_i64, val, addr, memop, idx);</span><br><span class="line">     plugin_gen_mem_callbacks(addr, info);</span><br></pre></td></tr></table></figure><p>这段代码是 QASan实现的核心部分。</p><p>简单来说，它的作用是：在 QEMU 将 Guest（客户机）的内存读写指令翻译成中间码（TCG Ops）时，强制插入一段“检查代码”。</p><p>最后就是<code>target/&#123;arch&#125;/tcg</code>目录下的代码。</p><ol><li><code>target/mips/tcg/translate.c</code>文件patch 内容如下所示：</li></ol><figure class="highlight patch"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">diff --git a/target/mips/tcg/translate.c b/target/mips/tcg/translate.c</span></span><br><span class="line"><span class="comment">index 78b848a6d9..c4d42da965 100644</span></span><br><span class="line"><span class="comment">--- a/target/mips/tcg/translate.c</span></span><br><span class="line"><span class="comment">+++ b/target/mips/tcg/translate.c</span></span><br><span class="line"><span class="meta">@@ -49,6 +49,27 @@</span></span><br><span class="line"> STUB_HELPER(cache, TCGv_env env, TCGv val, TCGv_i32 reg)</span><br><span class="line"> #endif</span><br><span class="line"> </span><br><span class="line"><span class="addition">+/* MIPS_PATCH */</span></span><br><span class="line"><span class="addition">+#include &quot;qemuafl/cpu-translate.h&quot;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+/* MIPS_PATCH */</span></span><br><span class="line"><span class="addition">+#define AFL_QEMU_TARGET_MIPS_SNIPPET                                          \</span></span><br><span class="line"><span class="addition">+  if (is_persistent) &#123;                                                        \</span></span><br><span class="line"><span class="addition">+    if (ctx-&gt;base.pc_next == afl_persistent_addr) &#123;                           \</span></span><br><span class="line"><span class="addition">+      gen_helper_afl_persistent_routine(cpu_env);                             \</span></span><br><span class="line"><span class="addition">+                                                                              \</span></span><br><span class="line"><span class="addition">+      if (afl_persistent_ret_addr == 0 &amp;&amp; !persistent_exits) &#123;                \</span></span><br><span class="line"><span class="addition">+        tcg_gen_movi_tl(cpu_gpr[31], afl_persistent_addr);                    \</span></span><br><span class="line"><span class="addition">+      &#125;                                                                       \</span></span><br><span class="line"><span class="addition">+                                                                              \</span></span><br><span class="line"><span class="addition">+      if (!persistent_save_gpr) afl_gen_tcg_plain_call(&amp;afl_persistent_loop); \</span></span><br><span class="line"><span class="addition">+                                                                              \</span></span><br><span class="line"><span class="addition">+    &#125; else if (afl_persistent_ret_addr &amp;&amp;                                     \</span></span><br><span class="line"><span class="addition">+               ctx-&gt;base.pc_next == afl_persistent_ret_addr) &#123;                \</span></span><br><span class="line"><span class="addition">+      gen_goto_tb(ctx, 0, afl_persistent_addr);                               \</span></span><br><span class="line"><span class="addition">+    &#125;                                                                         \</span></span><br><span class="line"><span class="addition">+  &#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"> enum &#123;</span><br><span class="line">     /* indirect opcode tables */</span><br><span class="line">     OPC_SPECIAL  = (0x00 &lt;&lt; 26),</span><br><span class="line"><span class="meta">@@ -1187,6 +1208,128 @@</span> static const char regnames_LO[][4] = &#123;</span><br><span class="line">     &quot;LO0&quot;, &quot;LO1&quot;, &quot;LO2&quot;, &quot;LO3&quot;,</span><br><span class="line"> &#125;;</span><br><span class="line"> </span><br><span class="line"><span class="addition">+/* MIPS_PATCH */</span></span><br><span class="line"><span class="addition">+void afl_save_regs(struct api_regs* r, CPUArchState *env) &#123;</span></span><br><span class="line"><span class="addition">+    int i = 0;</span></span><br><span class="line"><span class="addition">+    int j = 0;</span></span><br><span class="line"><span class="addition">+    /* GP registers saving */</span></span><br><span class="line"><span class="addition">+    r-&gt;r0 = env-&gt;active_tc.gpr[0];</span></span><br><span class="line"><span class="addition">+    r-&gt;at = env-&gt;active_tc.gpr[1];</span></span><br><span class="line"><span class="addition">+    r-&gt;v0 = env-&gt;active_tc.gpr[2];</span></span><br><span class="line"><span class="addition">+    r-&gt;v1 = env-&gt;active_tc.gpr[3];</span></span><br><span class="line"><span class="addition">+    r-&gt;a0 = env-&gt;active_tc.gpr[4];</span></span><br><span class="line"><span class="addition">+    r-&gt;a1 = env-&gt;active_tc.gpr[5];</span></span><br><span class="line"><span class="addition">+    r-&gt;a2 = env-&gt;active_tc.gpr[6];</span></span><br><span class="line"><span class="addition">+    r-&gt;a3 = env-&gt;active_tc.gpr[7];</span></span><br><span class="line"><span class="addition">+    r-&gt;t0 = env-&gt;active_tc.gpr[8];</span></span><br><span class="line"><span class="addition">+    r-&gt;t1 = env-&gt;active_tc.gpr[9];</span></span><br><span class="line"><span class="addition">+    r-&gt;t2 = env-&gt;active_tc.gpr[10];</span></span><br><span class="line"><span class="addition">+    r-&gt;t3 = env-&gt;active_tc.gpr[11];</span></span><br><span class="line"><span class="addition">+    r-&gt;t4 = env-&gt;active_tc.gpr[12];</span></span><br><span class="line"><span class="addition">+    r-&gt;t5 = env-&gt;active_tc.gpr[13];</span></span><br><span class="line"><span class="addition">+    r-&gt;t6 = env-&gt;active_tc.gpr[14];</span></span><br><span class="line"><span class="addition">+    r-&gt;t7 = env-&gt;active_tc.gpr[15];</span></span><br><span class="line"><span class="addition">+    r-&gt;s0 = env-&gt;active_tc.gpr[16];</span></span><br><span class="line"><span class="addition">+    r-&gt;s1 = env-&gt;active_tc.gpr[17];</span></span><br><span class="line"><span class="addition">+    r-&gt;s2 = env-&gt;active_tc.gpr[18];</span></span><br><span class="line"><span class="addition">+    r-&gt;s3 = env-&gt;active_tc.gpr[19];</span></span><br><span class="line"><span class="addition">+    r-&gt;s4 = env-&gt;active_tc.gpr[20];</span></span><br><span class="line"><span class="addition">+    r-&gt;s5 = env-&gt;active_tc.gpr[21];</span></span><br><span class="line"><span class="addition">+    r-&gt;s6 = env-&gt;active_tc.gpr[22];</span></span><br><span class="line"><span class="addition">+    r-&gt;s7 = env-&gt;active_tc.gpr[23];</span></span><br><span class="line"><span class="addition">+    r-&gt;t8 = env-&gt;active_tc.gpr[24];</span></span><br><span class="line"><span class="addition">+    r-&gt;t9 = env-&gt;active_tc.gpr[25];</span></span><br><span class="line"><span class="addition">+    r-&gt;k0 = env-&gt;active_tc.gpr[26];</span></span><br><span class="line"><span class="addition">+    r-&gt;k1 = env-&gt;active_tc.gpr[27];</span></span><br><span class="line"><span class="addition">+    r-&gt;gp = env-&gt;active_tc.gpr[28];</span></span><br><span class="line"><span class="addition">+    r-&gt;sp = env-&gt;active_tc.gpr[29];</span></span><br><span class="line"><span class="addition">+    r-&gt;fp = env-&gt;active_tc.gpr[30];</span></span><br><span class="line"><span class="addition">+    r-&gt;ra = env-&gt;active_tc.gpr[31];</span></span><br><span class="line"><span class="addition">+    r-&gt;PC = env-&gt;active_tc.PC;</span></span><br><span class="line"><span class="addition">+#if defined(TARGET_MIPS64)</span></span><br><span class="line"><span class="addition">+    memcpy(r-&gt;gpr_hi, env-&gt;active_tc.gpr_hi, sizeof(r-&gt;gpr_hi));</span></span><br><span class="line"><span class="addition">+#endif</span></span><br><span class="line"><span class="addition">+    for (i = 0; i &lt; MIPS_DSP_ACC; i++) &#123;</span></span><br><span class="line"><span class="addition">+        r-&gt;HI[i] = env-&gt;active_tc.HI[i];</span></span><br><span class="line"><span class="addition">+        r-&gt;LO[i] = env-&gt;active_tc.LO[i];</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+    /* FP registers saving */</span></span><br><span class="line"><span class="addition">+    for (i = 0; i &lt; 32; i++) &#123;</span></span><br><span class="line"><span class="addition">+        r-&gt;fpr[i].fd = env-&gt;active_fpu.fpr[i].fd;</span></span><br><span class="line"><span class="addition">+        for (j = 0; j &lt; 2; j++) &#123;</span></span><br><span class="line"><span class="addition">+            r-&gt;fpr[i].fs[j] = env-&gt;active_fpu.fpr[i].fs[j];</span></span><br><span class="line"><span class="addition">+        &#125;</span></span><br><span class="line"><span class="addition">+        r-&gt;fpr[i].d = env-&gt;active_fpu.fpr[i].d;</span></span><br><span class="line"><span class="addition">+        for (j = 0; j &lt; 2; j++) &#123;</span></span><br><span class="line"><span class="addition">+            r-&gt;fpr[i].w[j] = env-&gt;active_fpu.fpr[i].w[j];</span></span><br><span class="line"><span class="addition">+        &#125;</span></span><br><span class="line"><span class="addition">+        for (j = 0; j &lt; MSA_WRLEN / 8; j++) &#123;</span></span><br><span class="line"><span class="addition">+            r-&gt;fpr[i].wr.b[j] = env-&gt;active_fpu.fpr[i].wr.b[j];</span></span><br><span class="line"><span class="addition">+        &#125;</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+&#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+/* MIPS_PATCH */</span></span><br><span class="line"><span class="addition">+void afl_restore_regs(struct api_regs* r, CPUArchState *env) &#123;</span></span><br><span class="line"><span class="addition">+    int i = 0;</span></span><br><span class="line"><span class="addition">+    int j = 0;</span></span><br><span class="line"><span class="addition">+    /* GP registers restoring */</span></span><br><span class="line"><span class="addition">+    env-&gt;active_tc.gpr[0] = r-&gt;r0;</span></span><br><span class="line"><span class="addition">+    env-&gt;active_tc.gpr[1] = r-&gt;at;</span></span><br><span class="line"><span class="addition">+    env-&gt;active_tc.gpr[2] = r-&gt;v0;</span></span><br><span class="line"><span class="addition">+    env-&gt;active_tc.gpr[3] = r-&gt;v1;</span></span><br><span class="line"><span class="addition">+    env-&gt;active_tc.gpr[4] = r-&gt;a0;</span></span><br><span class="line"><span class="addition">+    env-&gt;active_tc.gpr[5] = r-&gt;a1;</span></span><br><span class="line"><span class="addition">+    env-&gt;active_tc.gpr[6] = r-&gt;a2;</span></span><br><span class="line"><span class="addition">+    env-&gt;active_tc.gpr[7] = r-&gt;a3;</span></span><br><span class="line"><span class="addition">+    env-&gt;active_tc.gpr[8] = r-&gt;t0;</span></span><br><span class="line"><span class="addition">+    env-&gt;active_tc.gpr[9] = r-&gt;t1;</span></span><br><span class="line"><span class="addition">+    env-&gt;active_tc.gpr[10] = r-&gt;t2;</span></span><br><span class="line"><span class="addition">+    env-&gt;active_tc.gpr[11] = r-&gt;t3;</span></span><br><span class="line"><span class="addition">+    env-&gt;active_tc.gpr[12] = r-&gt;t4;</span></span><br><span class="line"><span class="addition">+    env-&gt;active_tc.gpr[13] = r-&gt;t5;</span></span><br><span class="line"><span class="addition">+    env-&gt;active_tc.gpr[14] = r-&gt;t6;</span></span><br><span class="line"><span class="addition">+    env-&gt;active_tc.gpr[15] = r-&gt;t7;</span></span><br><span class="line"><span class="addition">+    env-&gt;active_tc.gpr[16] = r-&gt;s0;</span></span><br><span class="line"><span class="addition">+    env-&gt;active_tc.gpr[17] = r-&gt;s1;</span></span><br><span class="line"><span class="addition">+    env-&gt;active_tc.gpr[18] = r-&gt;s2;</span></span><br><span class="line"><span class="addition">+    env-&gt;active_tc.gpr[19] = r-&gt;s3;</span></span><br><span class="line"><span class="addition">+    env-&gt;active_tc.gpr[20] = r-&gt;s4;</span></span><br><span class="line"><span class="addition">+    env-&gt;active_tc.gpr[21] = r-&gt;s5;</span></span><br><span class="line"><span class="addition">+    env-&gt;active_tc.gpr[22] = r-&gt;s6;</span></span><br><span class="line"><span class="addition">+    env-&gt;active_tc.gpr[23] = r-&gt;s7;</span></span><br><span class="line"><span class="addition">+    env-&gt;active_tc.gpr[24] = r-&gt;t8;</span></span><br><span class="line"><span class="addition">+    env-&gt;active_tc.gpr[25] = r-&gt;t9;</span></span><br><span class="line"><span class="addition">+    env-&gt;active_tc.gpr[26] = r-&gt;k0;</span></span><br><span class="line"><span class="addition">+    env-&gt;active_tc.gpr[27] = r-&gt;k1;</span></span><br><span class="line"><span class="addition">+    env-&gt;active_tc.gpr[28] = r-&gt;gp;</span></span><br><span class="line"><span class="addition">+    env-&gt;active_tc.gpr[29] = r-&gt;sp;</span></span><br><span class="line"><span class="addition">+    env-&gt;active_tc.gpr[30] = r-&gt;fp;</span></span><br><span class="line"><span class="addition">+    env-&gt;active_tc.gpr[31] = r-&gt;ra;</span></span><br><span class="line"><span class="addition">+    env-&gt;active_tc.PC = r-&gt;PC;</span></span><br><span class="line"><span class="addition">+#if defined(TARGET_MIPS64)</span></span><br><span class="line"><span class="addition">+    memcpy(env-&gt;active_tc.gpr_hi, r-&gt;gpr_hi, sizeof(r-&gt;gpr_hi));</span></span><br><span class="line"><span class="addition">+#endif</span></span><br><span class="line"><span class="addition">+    for (i = 0; i &lt; MIPS_DSP_ACC; i++) &#123;</span></span><br><span class="line"><span class="addition">+        env-&gt;active_tc.HI[i] = r-&gt;HI[i];</span></span><br><span class="line"><span class="addition">+        env-&gt;active_tc.LO[i] = r-&gt;LO[i];</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+    /* FP registers restoring */</span></span><br><span class="line"><span class="addition">+    for (i = 0; i &lt; 32; i++) &#123;</span></span><br><span class="line"><span class="addition">+        env-&gt;active_fpu.fpr[i].fd = r-&gt;fpr[i].fd;</span></span><br><span class="line"><span class="addition">+        for (j = 0; j &lt; 2; j++) &#123;</span></span><br><span class="line"><span class="addition">+            env-&gt;active_fpu.fpr[i].fs[j] = r-&gt;fpr[i].fs[j];</span></span><br><span class="line"><span class="addition">+        &#125;</span></span><br><span class="line"><span class="addition">+        env-&gt;active_fpu.fpr[i].d = r-&gt;fpr[i].d;</span></span><br><span class="line"><span class="addition">+        for (j = 0; j &lt; 2; j++) &#123;</span></span><br><span class="line"><span class="addition">+            env-&gt;active_fpu.fpr[i].w[j] = r-&gt;fpr[i].w[j];</span></span><br><span class="line"><span class="addition">+        &#125;</span></span><br><span class="line"><span class="addition">+        for (j = 0; j &lt; MSA_WRLEN / 8; j++) &#123;</span></span><br><span class="line"><span class="addition">+            env-&gt;active_fpu.fpr[i].wr.b[j] = r-&gt;fpr[i].wr.b[j];</span></span><br><span class="line"><span class="addition">+        &#125;</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+&#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"> /* General purpose registers moves. */</span><br><span class="line"> void gen_load_gpr(TCGv t, int reg)</span><br><span class="line"> &#123;</span><br><span class="line"><span class="meta">@@ -15138,6 +15281,9 @@</span> static void mips_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)</span><br><span class="line">     int insn_bytes;</span><br><span class="line">     int is_slot;</span><br><span class="line"> </span><br><span class="line"><span class="addition">+    /* MIPS_PATCH */</span></span><br><span class="line"><span class="addition">+    AFL_QEMU_TARGET_MIPS_SNIPPET</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line">     is_slot = ctx-&gt;hflags &amp; MIPS_HFLAG_BMASK;</span><br><span class="line">     if (ctx-&gt;insn_flags &amp; ISA_NANOMIPS32) &#123;</span><br><span class="line">         ctx-&gt;opcode = translator_lduw(env, &amp;ctx-&gt;base, ctx-&gt;base.pc_next);</span><br></pre></td></tr></table></figure><p><code>target/&#123;arch&#125;/tcg/translate.c</code> 主要将目标程序的指令翻译成 TCG IR。AFL 对该文件的 patch 主要添加 AFL 持久化模式支持，包括持久化 fuzz 逻辑注入及 MIPS 完整寄存器状态的保存与恢复，使 AFL 能以高效循环方式 fuzz MIPS 程序。</p><p>由于测试案例使用 MIPS 架构，因此上述 patch 内容仅包含 MIPS 架构相关部分，其他架构暂未 patch。此外，由于暂未使用 QASAN 功能，许多 QASAN 相关 patch 亦暂未加入。</p>]]></content:encoded>
      
      
      
      <category domain="https://nobb.site/tags/bin/">bin</category>
      
      <category domain="https://nobb.site/tags/fuzz/">fuzz</category>
      
      
      <comments>https://nobb.site/2025/11/13/fuzz3/#disqus_thread</comments>
      
    </item>
    
  </channel>
</rss>
