Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 10 Nov 2019 18:41:13 +0000 (UTC)
From:      Dimitry Andric <dim@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org
Subject:   svn commit: r354598 - in stable: 11/contrib/libc++/include 11/sys/sys 12/contrib/libc++/include 12/sys/sys
Message-ID:  <201911101841.xAAIfDgG088987@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: dim
Date: Sun Nov 10 18:41:13 2019
New Revision: 354598
URL: https://svnweb.freebsd.org/changeset/base/354598

Log:
  MFC r354460:
  
  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

Modified:
  stable/12/contrib/libc++/include/cmath
  stable/12/contrib/libc++/include/random
  stable/12/sys/sys/param.h
Directory Properties:
  stable/12/   (props changed)

Changes in other areas also in this revision:
Modified:
  stable/11/contrib/libc++/include/cmath
  stable/11/contrib/libc++/include/random
  stable/11/sys/sys/param.h
Directory Properties:
  stable/11/   (props changed)

Modified: stable/12/contrib/libc++/include/cmath
==============================================================================
--- stable/12/contrib/libc++/include/cmath	Sun Nov 10 18:07:02 2019	(r354597)
+++ stable/12/contrib/libc++/include/cmath	Sun Nov 10 18:41:13 2019	(r354598)
@@ -304,11 +304,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;
@@ -607,6 +611,38 @@ __libcpp_isfinite_or_builtin(_A1 __lcpp_x) _NOEXCEPT
     return isfinite(__lcpp_x);
 }
 
+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(is_same<_FloatT, float>::value || is_same<_FloatT, double>::value
+               || is_same<_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

Modified: stable/12/contrib/libc++/include/random
==============================================================================
--- stable/12/contrib/libc++/include/random	Sun Nov 10 18:07:02 2019	(r354597)
+++ stable/12/contrib/libc++/include/random	Sun Nov 10 18:41:13 2019	(r354598)
@@ -4593,7 +4593,10 @@ class _LIBCPP_TEMPLATE_VIS poisson_distribution (publi
 
 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)
     {
@@ -4611,7 +4614,7 @@ poisson_distribution<_IntType>::param_type::param_type
     {
         __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_;
@@ -4628,12 +4631,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
@@ -4643,19 +4646,19 @@ poisson_distribution<_IntType>::operator()(_URNG& __ur
         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
@@ -4665,31 +4668,31 @@ poisson_distribution<_IntType>::operator()(_URNG& __ur
                     __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;
@@ -4709,7 +4712,7 @@ poisson_distribution<_IntType>::operator()(_URNG& __ur
             }
         }
     }
-    return __x;
+    return std::__clamp_to_integral<result_type>(__tx);
 }
 
 template <class _CharT, class _Traits, class _IntType>

Modified: stable/12/sys/sys/param.h
==============================================================================
--- stable/12/sys/sys/param.h	Sun Nov 10 18:07:02 2019	(r354597)
+++ stable/12/sys/sys/param.h	Sun Nov 10 18:41:13 2019	(r354598)
@@ -60,7 +60,7 @@
  *		in the range 5 to 9.
  */
 #undef __FreeBSD_version
-#define __FreeBSD_version 1201500	/* Master, propagated to newvers */
+#define __FreeBSD_version 1201501	/* Master, propagated to newvers */
 
 /*
  * __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201911101841.xAAIfDgG088987>