Subject: [Boost-bugs] [Boost C++ Libraries] #12915: Buffer overflow in boost::container::vector (affects flat_set)
From: Boost C++ Libraries (noreply_at_[hidden])
Date: 2017-03-20 04:46:09
#12915: Buffer overflow in boost::container::vector (affects flat_set)
-------------------------------------+------------------------
Reporter: mykmartin@⦠| Owner: igaztanaga
Type: Bugs | Status: new
Milestone: To Be Determined | Component: container
Version: Boost Development Trunk | Severity: Problem
Keywords: |
-------------------------------------+------------------------
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.
(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)
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:
{{{#!c++
std::size_t index_capacity = (aligned_addr >= capaddr) ? 0u : (capaddr -
addr)/sizeof(size_type);
}}}
- addr = start address of buffer + num of currently stored values (s) +
num of new values to add (n)
- aligned_addr = addr rounded up to the memory alignment boundary for
size_type (typically 8)
- capaddr = end address of buffer (start address + capacity)
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):
{{{
<- capacity=623 ->
+-------------+----------------+
| s=311 | free=312 |
+-------------+----------------+
+---------+ : :
| n=118 | : :
+---------+ : ^ capaddr
: :
addr ^ ^ aligned_addr (= addr + 4 bytes)
}}}
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:
{{{
capaddr - addr = 776 bytes / 8 = 97.0
capaddr - aligned_addr = 772 bytes / 8 = 96.5
}}}
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:
{{{#!c++
assert(boost::uintptr_t(position) + sizeof(size_type) < capaddr);
*position = static_cast<size_type>(pcur - pbeg);
}}}
The fix for this is to replace addr with aligned_addr in line 2260:
{{{#!c++
std::size_t index_capacity = (aligned_addr >= capaddr) ? 0u : (capaddr -
aligned_addr)/sizeof(size_type);
}}}
-- Ticket URL: <https://svn.boost.org/trac/boost/ticket/12915> Boost C++ Libraries <http://www.boost.org/> Boost provides free peer-reviewed portable C++ source libraries.
This archive was generated by hypermail 2.1.7 : 2017-03-20 04:49:20 UTC