Merge commit e8316372b from llvm git (by Louis Dionne):

[libc++] Add `__truncating_cast` for safely casting float types to
  integers

  This is needed anytime we need to clamp an arbitrary floating point
  value to an integer type.

  Thanks to Eric Fiselier for the patch.

  Differential Revision: https://reviews.llvm.org/D66836

  llvm-svn: 370891

Merge commit b92deded8 from llvm git (by Louis Dionne):

  [libc++] Move __clamp_to_integral to <cmath>, and harden against
  min()/max() macros

  llvm-svn: 370900

Merge commit 0ec6a4882 from llvm git (by Louis Dionne):

  [libc++] Fix potential OOB in poisson_distribution

  See details in the original Chromium bug report:
      https://bugs.chromium.org/p/chromium/issues/detail?id=994957

Together, these fix a security issue in libc++'s implementation of
std::poisson_distribution, which can be exploited to read data which is
out of bounds.

Note there are no programs in the FreeBSD base system that use
std::poisson_distribution, so this is only a possible issue for ports
and external programs which have been built against libc++.  Therefore,
I am bumping __FreeBSD_version for the benefit of our port maintainers.

Requested by:	emaste
Security:	potential OOB read
MFC after:	3 days
This commit is contained in:
Dimitry Andric 2019-11-07 18:26:01 +00:00
parent 09a05e60bc
commit 04677a42a3
3 changed files with 61 additions and 22 deletions

View File

@ -303,11 +303,15 @@ long double truncl(long double x);
#include <__config>
#include <math.h>
#include <version>
#include <type_traits>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
#pragma GCC system_header
#endif
_LIBCPP_PUSH_MACROS
#include <__undef_macros>
_LIBCPP_BEGIN_NAMESPACE_STD
using ::signbit;
@ -632,6 +636,38 @@ lerp(long double __a, long double __b, long double __t) _NOEXCEPT { return __ler
#endif // _LIBCPP_STD_VER > 17
template <class _IntT, class _FloatT,
bool _FloatBigger = (numeric_limits<_FloatT>::digits > numeric_limits<_IntT>::digits),
int _Bits = (numeric_limits<_IntT>::digits - numeric_limits<_FloatT>::digits)>
_LIBCPP_INLINE_VISIBILITY
_LIBCPP_CONSTEXPR _IntT __max_representable_int_for_float() _NOEXCEPT {
static_assert(is_floating_point<_FloatT>::value, "must be a floating point type");
static_assert(is_integral<_IntT>::value, "must be an integral type");
static_assert(numeric_limits<_FloatT>::radix == 2, "FloatT has incorrect radix");
static_assert(_IsSame<_FloatT, float>::value || _IsSame<_FloatT, double>::value
|| _IsSame<_FloatT,long double>::value, "unsupported floating point type");
return _FloatBigger ? numeric_limits<_IntT>::max() : (numeric_limits<_IntT>::max() >> _Bits << _Bits);
}
// Convert a floating point number to the specified integral type after
// clamping to the integral types representable range.
//
// The behavior is undefined if `__r` is NaN.
template <class _IntT, class _RealT>
_LIBCPP_INLINE_VISIBILITY
_IntT __clamp_to_integral(_RealT __r) _NOEXCEPT {
using _Lim = std::numeric_limits<_IntT>;
const _IntT _MaxVal = std::__max_representable_int_for_float<_IntT, _RealT>();
if (__r >= ::nextafter(static_cast<_RealT>(_MaxVal), INFINITY)) {
return _Lim::max();
} else if (__r <= _Lim::lowest()) {
return _Lim::min();
}
return static_cast<_IntT>(__r);
}
_LIBCPP_END_NAMESPACE_STD
_LIBCPP_POP_MACROS
#endif // _LIBCPP_CMATH

View File

@ -4592,7 +4592,10 @@ public:
template<class _IntType>
poisson_distribution<_IntType>::param_type::param_type(double __mean)
: __mean_(__mean)
// According to the standard `inf` is a valid input, but it causes the
// distribution to hang, so we replace it with the maximum representable
// mean.
: __mean_(isinf(__mean) ? numeric_limits<double>::max() : __mean)
{
if (__mean_ < 10)
{
@ -4610,7 +4613,7 @@ poisson_distribution<_IntType>::param_type::param_type(double __mean)
{
__s_ = _VSTD::sqrt(__mean_);
__d_ = 6 * __mean_ * __mean_;
__l_ = static_cast<result_type>(__mean_ - 1.1484);
__l_ = std::trunc(__mean_ - 1.1484);
__omega_ = .3989423 / __s_;
double __b1_ = .4166667E-1 / __mean_;
double __b2_ = .3 * __b1_ * __b1_;
@ -4627,12 +4630,12 @@ template<class _URNG>
_IntType
poisson_distribution<_IntType>::operator()(_URNG& __urng, const param_type& __pr)
{
result_type __x;
double __tx;
uniform_real_distribution<double> __urd;
if (__pr.__mean_ < 10)
{
__x = 0;
for (double __p = __urd(__urng); __p > __pr.__l_; ++__x)
__tx = 0;
for (double __p = __urd(__urng); __p > __pr.__l_; ++__tx)
__p *= __urd(__urng);
}
else
@ -4642,19 +4645,19 @@ poisson_distribution<_IntType>::operator()(_URNG& __urng, const param_type& __pr
double __u;
if (__g > 0)
{
__x = static_cast<result_type>(__g);
if (__x >= __pr.__l_)
return __x;
__difmuk = __pr.__mean_ - __x;
__tx = std::trunc(__g);
if (__tx >= __pr.__l_)
return std::__clamp_to_integral<result_type>(__tx);
__difmuk = __pr.__mean_ - __tx;
__u = __urd(__urng);
if (__pr.__d_ * __u >= __difmuk * __difmuk * __difmuk)
return __x;
return std::__clamp_to_integral<result_type>(__tx);
}
exponential_distribution<double> __edist;
for (bool __using_exp_dist = false; true; __using_exp_dist = true)
{
double __e;
if (__using_exp_dist || __g < 0)
if (__using_exp_dist || __g <= 0)
{
double __t;
do
@ -4664,31 +4667,31 @@ poisson_distribution<_IntType>::operator()(_URNG& __urng, const param_type& __pr
__u += __u - 1;
__t = 1.8 + (__u < 0 ? -__e : __e);
} while (__t <= -.6744);
__x = __pr.__mean_ + __pr.__s_ * __t;
__difmuk = __pr.__mean_ - __x;
__tx = std::trunc(__pr.__mean_ + __pr.__s_ * __t);
__difmuk = __pr.__mean_ - __tx;
__using_exp_dist = true;
}
double __px;
double __py;
if (__x < 10)
if (__tx < 10 && __tx >= 0)
{
const double __fac[] = {1, 1, 2, 6, 24, 120, 720, 5040,
40320, 362880};
__px = -__pr.__mean_;
__py = _VSTD::pow(__pr.__mean_, (double)__x) / __fac[__x];
__py = _VSTD::pow(__pr.__mean_, (double)__tx) / __fac[static_cast<int>(__tx)];
}
else
{
double __del = .8333333E-1 / __x;
double __del = .8333333E-1 / __tx;
__del -= 4.8 * __del * __del * __del;
double __v = __difmuk / __x;
double __v = __difmuk / __tx;
if (_VSTD::abs(__v) > 0.25)
__px = __x * _VSTD::log(1 + __v) - __difmuk - __del;
__px = __tx * _VSTD::log(1 + __v) - __difmuk - __del;
else
__px = __x * __v * __v * (((((((.1250060 * __v + -.1384794) *
__px = __tx * __v * __v * (((((((.1250060 * __v + -.1384794) *
__v + .1421878) * __v + -.1661269) * __v + .2000118) *
__v + -.2500068) * __v + .3333333) * __v + -.5) - __del;
__py = .3989423 / _VSTD::sqrt(__x);
__py = .3989423 / _VSTD::sqrt(__tx);
}
double __r = (0.5 - __difmuk) / __pr.__s_;
double __r2 = __r * __r;
@ -4708,7 +4711,7 @@ poisson_distribution<_IntType>::operator()(_URNG& __urng, const param_type& __pr
}
}
}
return __x;
return std::__clamp_to_integral<result_type>(__tx);
}
template <class _CharT, class _Traits, class _IntType>

View File

@ -60,7 +60,7 @@
* in the range 5 to 9.
*/
#undef __FreeBSD_version
#define __FreeBSD_version 1300055 /* Master, propagated to newvers */
#define __FreeBSD_version 1300056 /* Master, propagated to newvers */
/*
* __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,