Boost C++ Libraries: Ticket #12915: Buffer overflow in boost::container::vector (affects flat_set) https://svn.boost.org/trac10/ticket/12915 <p> boost::container::flat_set's ranged insert with ordered_unique_range_t uses vector::priv_merge to perform the insertion. The implementation of vector::priv_merge contains a buffer overflow bug for some combinations of inputs. </p> <p> (Note: trac won't let me submit this with links to the source on github, so for future reference the line numbers are referring to commit 1261ac33089cbc08108b4beaed97f307270892a8 of boost/container/vector.hpp) </p> <p> Line 2260 in vector.hpp calculates whether there is enough spare space in the vector's storage buffer to hold index values used during the merge operation: </p> <div class="wiki-code"><div class="code"><pre><span class="n">std</span><span class="o">::</span><span class="kt">size_t</span> <span class="n">index_capacity</span> <span class="o">=</span> <span class="p">(</span><span class="n">aligned_addr</span> <span class="o">&gt;=</span> <span class="n">capaddr</span><span class="p">)</span> <span class="o">?</span> <span class="mi">0u</span> <span class="o">:</span> <span class="p">(</span><span class="n">capaddr</span> <span class="o">-</span> <span class="n">addr</span><span class="p">)</span><span class="o">/</span><span class="k">sizeof</span><span class="p">(</span><span class="n">size_type</span><span class="p">);</span> </pre></div></div><ul><li>addr = start address of buffer + num of currently stored values (s) + num of new values to add (n) </li><li>aligned_addr = addr rounded up to the memory alignment boundary for size_type (typically 8) </li><li>capaddr = end address of buffer (start address + capacity) </li></ul><p> When the byte size of the elements being stored is not a multiple of sizeof(size_type), the calculation of index_capacity can overestimate the available spare space. The attached test case uses a flat_set containing 4-byte integers and has the following layout for the ordered_unique_range insertion (numbers are element counts, not bytes): </p> <pre class="wiki"> &lt;- capacity=623 -&gt; +-------------+----------------+ | s=311 | free=312 | +-------------+----------------+ +---------+ : : | n=118 | : : +---------+ : ^ capaddr : : addr ^ ^ aligned_addr (= addr + 4 bytes) </pre><p> The 8-byte index values are stored using an 8-byte aligned pointer (size_type *position in priv_insert_ordered_range). This is correctly initialised to aligned_addr but the index_capacity is incorrectly calculated using addr; it should use aligned_addr: </p> <pre class="wiki">capaddr - addr = 776 bytes / 8 = 97.0 capaddr - aligned_addr = 772 bytes / 8 = 96.5 </pre><p> The actual spare capacity is 96 index values of 8 bytes each, with a slack of 4 bytes. The code attempts to write 97 elements and overflows at line 2307. To detect the overflow, pass capaddr to priv_insert_ordered_range and add an assert before that line: </p> <div class="wiki-code"><div class="code"><pre><span class="n">assert</span><span class="p">(</span><span class="n">boost</span><span class="o">::</span><span class="kt">uintptr_t</span><span class="p">(</span><span class="n">position</span><span class="p">)</span> <span class="o">+</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">size_type</span><span class="p">)</span> <span class="o">&lt;</span> <span class="n">capaddr</span><span class="p">);</span> <span class="o">*</span><span class="n">position</span> <span class="o">=</span> <span class="k">static_cast</span><span class="o">&lt;</span><span class="n">size_type</span><span class="o">&gt;</span><span class="p">(</span><span class="n">pcur</span> <span class="o">-</span> <span class="n">pbeg</span><span class="p">);</span> </pre></div></div><p> The fix for this is to replace addr with aligned_addr in line 2260: </p> <div class="wiki-code"><div class="code"><pre><span class="n">std</span><span class="o">::</span><span class="kt">size_t</span> <span class="n">index_capacity</span> <span class="o">=</span> <span class="p">(</span><span class="n">aligned_addr</span> <span class="o">&gt;=</span> <span class="n">capaddr</span><span class="p">)</span> <span class="o">?</span> <span class="mi">0u</span> <span class="o">:</span> <span class="p">(</span><span class="n">capaddr</span> <span class="o">-</span> <span class="n">aligned_addr</span><span class="p">)</span><span class="o">/</span><span class="k">sizeof</span><span class="p">(</span><span class="n">size_type</span><span class="p">);</span> </pre></div></div> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/12915 Trac 1.4.3 mykmartin@… Mon, 20 Mar 2017 04:48:01 GMT attachment set https://svn.boost.org/trac10/ticket/12915 https://svn.boost.org/trac10/ticket/12915 <ul> <li><strong>attachment</strong> → <span class="trac-field-new">overflow.cc</span> </li> </ul> Ticket mykmartin@… Sun, 26 Mar 2017 22:57:46 GMT <link>https://svn.boost.org/trac10/ticket/12915#comment:1 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12915#comment:1</guid> <description> <p> Minor correction: the assert to show the problem should use &lt;=: </p> <p> assert(boost::uintptr_t(position) + sizeof(size_type) &lt;= capaddr); </p> </description> <category>Ticket</category> </item> <item> <author>fdegros@…</author> <pubDate>Tue, 25 Jul 2017 01:10:22 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12915#comment:2 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12915#comment:2</guid> <description> <p> Ping? Any progress on this ticket? The diagnosis and fix have been provided by the original reporter. Is the fix making its way into new releases of Boost Containers? </p> </description> <category>Ticket</category> </item> <item> <author>François Degros <fdegros@…></author> <pubDate>Wed, 26 Jul 2017 01:14:21 GMT</pubDate> <title>cc set https://svn.boost.org/trac10/ticket/12915#comment:3 https://svn.boost.org/trac10/ticket/12915#comment:3 <ul> <li><strong>cc</strong> <span class="trac-author">fdegros@…</span> added </li> </ul> Ticket karl.tarbe@… Wed, 20 Jun 2018 09:09:44 GMT <link>https://svn.boost.org/trac10/ticket/12915#comment:4 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12915#comment:4</guid> <description> <p> I might have also run into this. Why is this bug still <em>new</em>? </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Ion Gaztañaga</dc:creator> <pubDate>Tue, 26 Jun 2018 21:26:42 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12915#comment:5 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12915#comment:5</guid> <description> <p> vector's merge implementation was rewritten some releases ago. Provided overflow.cc correctly works under current develop branch with gcc with ASAN+UBSAN. </p> </description> <category>Ticket</category> </item> <item> <author>karl.tarbe@…</author> <pubDate>Tue, 26 Jun 2018 22:58:06 GMT</pubDate> <title>attachment set https://svn.boost.org/trac10/ticket/12915 https://svn.boost.org/trac10/ticket/12915 <ul> <li><strong>attachment</strong> → <span class="trac-field-new">test.cpp</span> </li> </ul> <p> When run with valgrind: invalid write of size 8 </p> Ticket karl.tarbe@… Tue, 26 Jun 2018 23:07:05 GMT attachment set https://svn.boost.org/trac10/ticket/12915 https://svn.boost.org/trac10/ticket/12915 <ul> <li><strong>attachment</strong> → <span class="trac-field-new">log</span> </li> </ul> <p> Log of valgrind output </p> Ticket karl.tarbe@… Tue, 26 Jun 2018 23:10:15 GMT <link>https://svn.boost.org/trac10/ticket/12915#comment:6 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12915#comment:6</guid> <description> <p> I have attached test.cpp and log of valgrind output on it. </p> <p> I am using Arch linux with boost 1.67.0-4 and gcc 8.1.1+20180531-1 </p> <p> This might be a separate bug, but I am not sure. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Ion Gaztañaga</dc:creator> <pubDate>Wed, 27 Jun 2018 12:22:11 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12915#comment:7 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12915#comment:7</guid> <description> <p> Thanks for the new test case, it's a separate bug, working on it. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Ion Gaztañaga</dc:creator> <pubDate>Wed, 27 Jun 2018 21:28:10 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12915#comment:8 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12915#comment:8</guid> <description> <p> Looks like the following commit: </p> <p> <a class="ext-link" href="https://github.com/boostorg/move/commit/ddeb2341271583d25a0a9974d339b519b8e18dc9"><span class="icon">​</span>https://github.com/boostorg/move/commit/ddeb2341271583d25a0a9974d339b519b8e18dc9</a> </p> <p> fixes the issue. Will be released in 1.68. </p> </description> <category>Ticket</category> </item> <item> <author>karl.tarbe@…</author> <pubDate>Thu, 28 Jun 2018 07:47:35 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12915#comment:9 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12915#comment:9</guid> <description> <p> Thank you for quickly addressing the issue. </p> </description> <category>Ticket</category> </item> <item> <author>karl.tarbe@…</author> <pubDate>Thu, 28 Jun 2018 09:49:40 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12915#comment:10 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12915#comment:10</guid> <description> <p> I have one follow-up question. Which Boost versions are affected by this (the one I provided the test case for) bug. </p> <p> So I can use BOOST_VERSION to switch between workaround (insert one-by-one) and the faster method. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Ion Gaztañaga</dc:creator> <pubDate>Thu, 28 Jun 2018 21:03:14 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12915#comment:11 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12915#comment:11</guid> <description> <p> There were other bugs related to this in Boost 1.67, so I would say soon to be released version 1.68 will be safe. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Ion Gaztañaga</dc:creator> <pubDate>Mon, 31 Dec 2018 17:26:22 GMT</pubDate> <title>status changed; resolution set https://svn.boost.org/trac10/ticket/12915#comment:12 https://svn.boost.org/trac10/ticket/12915#comment:12 <ul> <li><strong>status</strong> <span class="trac-field-old">new</span> → <span class="trac-field-new">closed</span> </li> <li><strong>resolution</strong> → <span class="trac-field-new">fixed</span> </li> </ul> <p> Closing the bug. </p> Ticket