a2cf7d
commit 9333498794cde1d5cca518badf79533a24114b6f
a2cf7d
Author: Joseph Myers <joseph@codesourcery.com>
a2cf7d
Date:   Wed Feb 12 23:31:56 2020 +0000
a2cf7d
a2cf7d
    Avoid ldbl-96 stack corruption from range reduction of pseudo-zero (bug 25487).
a2cf7d
a2cf7d
    Bug 25487 reports stack corruption in ldbl-96 sinl on a pseudo-zero
a2cf7d
    argument (an representation where all the significand bits, including
a2cf7d
    the explicit high bit, are zero, but the exponent is not zero, which
a2cf7d
    is not a valid representation for the long double type).
a2cf7d
a2cf7d
    Although this is not a valid long double representation, existing
a2cf7d
    practice in this area (see bug 4586, originally marked invalid but
a2cf7d
    subsequently fixed) is that we still seek to avoid invalid memory
a2cf7d
    accesses as a result, in case of programs that treat arbitrary binary
a2cf7d
    data as long double representations, although the invalid
a2cf7d
    representations of the ldbl-96 format do not need to be consistently
a2cf7d
    handled the same as any particular valid representation.
a2cf7d
a2cf7d
    This patch makes the range reduction detect pseudo-zero and unnormal
a2cf7d
    representations that would otherwise go to __kernel_rem_pio2, and
a2cf7d
    returns a NaN for them instead of continuing with the range reduction
a2cf7d
    process.  (Pseudo-zero and unnormal representations whose unbiased
a2cf7d
    exponent is less than -1 have already been safely returned from the
a2cf7d
    function before this point without going through the rest of range
a2cf7d
    reduction.)  Pseudo-zero representations would previously result in
a2cf7d
    the value passed to __kernel_rem_pio2 being all-zero, which is
a2cf7d
    definitely unsafe; unnormal representations would previously result in
a2cf7d
    a value passed whose high bit is zero, which might well be unsafe
a2cf7d
    since that is not a form of input expected by __kernel_rem_pio2.
a2cf7d
a2cf7d
    Tested for x86_64.
a2cf7d
a2cf7d
Revised for RHEL 8.3.0.
a2cf7d
a2cf7d
diff -Nrup a/sysdeps/ieee754/ldbl-96/e_rem_pio2l.c b/sysdeps/ieee754/ldbl-96/e_rem_pio2l.c
a2cf7d
--- a/sysdeps/ieee754/ldbl-96/e_rem_pio2l.c	2018-08-01 01:10:47.000000000 -0400
a2cf7d
+++ b/sysdeps/ieee754/ldbl-96/e_rem_pio2l.c	2020-04-03 13:05:02.609844427 -0400
a2cf7d
@@ -209,6 +209,18 @@ __ieee754_rem_pio2l (long double x, long
a2cf7d
       y[1] = y[0];
a2cf7d
       return 0;
a2cf7d
     }
a2cf7d
+  
a2cf7d
+  if ((i0 & 0x80000000) == 0)
a2cf7d
+    {
a2cf7d
+      /* Pseudo-zero and unnormal representations are not valid
a2cf7d
+        representations of long double.  We need to avoid stack
a2cf7d
+        corruption in __kernel_rem_pio2, which expects input in a
a2cf7d
+        particular normal form, but those representations do not need
a2cf7d
+        to be consistently handled like any particular floating-point
a2cf7d
+        value.  */
a2cf7d
+      y[1] = y[0] = __builtin_nanl ("");
a2cf7d
+      return 0;
a2cf7d
+    }
a2cf7d
 
a2cf7d
   /* Split the 64 bits of the mantissa into three 24-bit integers
a2cf7d
      stored in a double array.  */
a2cf7d
diff -Nrup a/sysdeps/ieee754/ldbl-96/Makefile b/sysdeps/ieee754/ldbl-96/Makefile
a2cf7d
--- a/sysdeps/ieee754/ldbl-96/Makefile	2018-08-01 01:10:47.000000000 -0400
a2cf7d
+++ b/sysdeps/ieee754/ldbl-96/Makefile	2020-04-03 13:03:20.233546734 -0400
a2cf7d
@@ -17,5 +17,6 @@
a2cf7d
 # <http://www.gnu.org/licenses/>.
a2cf7d
 
a2cf7d
 ifeq ($(subdir),math)
a2cf7d
-tests += test-canonical-ldbl-96 test-totalorderl-ldbl-96
a2cf7d
+tests += test-canonical-ldbl-96 test-totalorderl-ldbl-96 test-sinl-pseudo
a2cf7d
+CFLAGS-test-sinl-pseudo.c += -fstack-protector-all
a2cf7d
 endif
a2cf7d
diff -Nrup a/sysdeps/ieee754/ldbl-96/test-sinl-pseudo.c b/sysdeps/ieee754/ldbl-96/test-sinl-pseudo.c
a2cf7d
--- a/sysdeps/ieee754/ldbl-96/test-sinl-pseudo.c	1969-12-31 19:00:00.000000000 -0500
a2cf7d
+++ b/sysdeps/ieee754/ldbl-96/test-sinl-pseudo.c	2020-04-03 13:05:37.857952212 -0400
a2cf7d
@@ -0,0 +1,41 @@
a2cf7d
+/* Test sinl for pseudo-zeros and unnormals for ldbl-96 (bug 25487).
a2cf7d
+   Copyright (C) 2020 Free Software Foundation, Inc.
a2cf7d
+   This file is part of the GNU C Library.
a2cf7d
+
a2cf7d
+   The GNU C Library is free software; you can redistribute it and/or
a2cf7d
+   modify it under the terms of the GNU Lesser General Public
a2cf7d
+   License as published by the Free Software Foundation; either
a2cf7d
+   version 2.1 of the License, or (at your option) any later version.
a2cf7d
+
a2cf7d
+   The GNU C Library is distributed in the hope that it will be useful,
a2cf7d
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
a2cf7d
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
a2cf7d
+   Lesser General Public License for more details.
a2cf7d
+
a2cf7d
+   You should have received a copy of the GNU Lesser General Public
a2cf7d
+   License along with the GNU C Library; if not, see
a2cf7d
+   <https://www.gnu.org/licenses/>.  */
a2cf7d
+
a2cf7d
+#include <math.h>
a2cf7d
+#include <math_ldbl.h>
a2cf7d
+#include <stdint.h>
a2cf7d
+
a2cf7d
+static int
a2cf7d
+do_test (void)
a2cf7d
+{
a2cf7d
+  for (int i = 0; i < 64; i++)
a2cf7d
+    {
a2cf7d
+      uint64_t sig = i == 63 ? 0 : 1ULL << i;
a2cf7d
+      long double ld;
a2cf7d
+      SET_LDOUBLE_WORDS (ld, 0x4141,
a2cf7d
+                        sig >> 32, sig & 0xffffffffULL);
a2cf7d
+      /* The requirement is that no stack overflow occurs when the
a2cf7d
+        pseudo-zero or unnormal goes through range reduction.  */
a2cf7d
+      volatile long double ldr;
a2cf7d
+      ldr = sinl (ld);
a2cf7d
+      (void) ldr;
a2cf7d
+    }
a2cf7d
+  return 0;
a2cf7d
+}
a2cf7d
+
a2cf7d
+#include <support/test-driver.c>