<div dir="ltr">Hi all,<div><p>I have identified a high-severity heap buffer overflow vulnerability in <code>src/cache.c</code>. This issue arises from a synchronization failure in the TCP/DNS pipe communication between the parent and child processes when a memory allocation fails.</p><h3>Summary</h3><p>In <code>cache_recv_insert()</code>, when <code>blockdata_read()</code> fails to allocate memory (returning <code>NULL</code>), the code uses a <code>continue</code> statement to skip the current iteration. However, because <code>blockdata_read()</code> returns before consuming the expected number of bytes from the file descriptor (<code>fd</code>), the unread Resource Record (RR) data remains in the pipe.</p><p>In the next iteration of the loop, this leftover data is incorrectly interpreted as the length of the next domain name (<code>m</code>), leading to a heap buffer overflow when reading into <code>daemon->namebuff</code>.</p><h3>Technical Details</h3><p><b>File:</b> <code>src/cache.c</code>
<b>Function:</b> <code>cache_recv_insert()</code>
<b>Impacted Lines:</b> 1018, 1025, 1032 (in master/2.93test7)</p><p><b>Vulnerable Logic:</b></p><span class="gmail-"><span class="gmail-ng-tns-c2858875814-267 gmail-ng-star-inserted"><div class="gmail-code-block gmail-ng-tns-c2858875814-267 gmail-ng-animate-disabled gmail-ng-trigger gmail-ng-trigger-codeBlockRevealAnimation"><div class="gmail-formatted-code-block-internal-container gmail-ng-tns-c2858875814-267"><div class="gmail-animated-opacity gmail-ng-tns-c2858875814-267"><pre class="gmail-ng-tns-c2858875814-267"><code role="text" class="gmail-code-container gmail-formatted gmail-ng-tns-c2858875814-267"><span class="gmail-hljs-comment">// src/cache.c:1018</span>
<span class="gmail-hljs-keyword">if</span> ((flags & F_RR) && !(flags & F_NEG) && (flags & F_KEYTAG) 
    && !(block = addr.rrblock.rrdata = blockdata_read(fd, addr.rrblock.datalen)))
  <span class="gmail-hljs-keyword">continue</span>; <span class="gmail-hljs-comment">// <span class="gmail-hljs-doctag">BUG:</span> Should be 'return 0' to abort the transaction</span>
</code></pre></div></div></div></span></span><p>When <code>blockdata_read()</code> fails at <code>src/blockdata.c:92</code> (due to <code>new_block()</code> returning <code>NULL</code>), it returns <code>NULL</code> without reading any data from the pipe. The <code>continue</code> statement then forces the loop to start over:</p><ol start="1"><li><p>The loop tries to read <code>m</code> (the next name length).</p></li><li><p>It instead reads the <b>first 8 bytes of the unconsumed RR data</b> as <code>m</code>.</p></li><li><p>If the attacker-controlled RR data results in an <code>m > MAXDNAME</code> (1024), the subsequent <code>read_write(fd, daemon->namebuff, m, ..)</code> call overflows the <code>daemon->namebuff</code> heap buffer.</p></li></ol><h3>Impact</h3><p>An attacker can trigger this by:</p><ol start="1"><li><p>Sending a DNS query that generates a large RR response (setting <code>F_RR</code>).</p></li><li><p>Inducing memory pressure (or exploiting a specific allocation limit).</p></li><li><p>Once <code>blockdata_read</code> fails, the pipe desyncs, allowing the attacker to control the <code>m</code> value and execute a heap overflow.</p></li></ol><p>This can lead to a <b>Denial of Service (DoS)</b> or potentially <b>Remote Code Execution (RCE)</b> under specific memory layouts.</p></div></div>