[patch] Fix BZ 19165 -- overflow in fread / fwrite
Paul Pluzhnikov
ppluzhnikov@google.com
Mon Dec 7 17:22:00 GMT 2015
Ok, let's try one more time.
Previous attempt: https://sourceware.org/ml/libc-alpha/2015-10/msg00894.html
Tested on Linux/x86_64 with 6.0.0 (r222386).
Testing with (gcc-4.8 Ubuntu 4.8.4-2ubuntu1~14.04) 4:4.8.2-1ubuntu6
fails for apparently unrelated reasons:
build/math/test-double-vlen2-wrappers.o: In function `cos_vlen2':
/glibc-git/math/../sysdeps/x86_64/fpu/test-double-vlen2-wrappers.c:24:
undefined reference to `_ZGVbN2v_cos'
/glibc-git/build-system-gcc/math/test-double-vlen2-wrappers.o: In
function `sin_vlen2':
/glibc-git/math/../sysdeps/x86_64/fpu/test-double-vlen2-wrappers.c:25:
undefined reference to `_ZGVbN2v_sin'
... etc.
Thanks,
2015-12-07 Paul Pluzhnikov <ppluzhnikov@google.com>
[BZ #19165]
* misc/sys/cdefs.h (__umul_size_t_overflow): New.
(__umul_size_t_saturated): New.
* libio/iofread.c (_IO_fread): Protect against overflow.
* libio/iofread_u.c (__fread_unlocked): Likewise.
* b/libio/iofwrite.c (_IO_fwrite): Likewise.
* libio/iofwrite_u.c (fwrite_unlocked): Likewise.
--
Paul Pluzhnikov
-------------- next part --------------
diff --git a/libio/iofread.c b/libio/iofread.c
index eb69b05..515f862 100644
--- a/libio/iofread.c
+++ b/libio/iofread.c
@@ -29,7 +29,7 @@
_IO_size_t
_IO_fread (void *buf, _IO_size_t size, _IO_size_t count, _IO_FILE *fp)
{
- _IO_size_t bytes_requested = size * count;
+ _IO_size_t bytes_requested = __umul_size_t_saturated (size, count);
_IO_size_t bytes_read;
CHECK_FILE (fp, 0);
if (bytes_requested == 0)
diff --git a/libio/iofread_u.c b/libio/iofread_u.c
index 997b714..9e2d213 100644
--- a/libio/iofread_u.c
+++ b/libio/iofread_u.c
@@ -32,7 +32,7 @@
_IO_size_t
__fread_unlocked (void *buf, _IO_size_t size, _IO_size_t count, _IO_FILE *fp)
{
- _IO_size_t bytes_requested = size * count;
+ _IO_size_t bytes_requested = __umul_size_t_saturated (size, count);
_IO_size_t bytes_read;
CHECK_FILE (fp, 0);
if (bytes_requested == 0)
diff --git a/libio/iofwrite.c b/libio/iofwrite.c
index 48ad4bc..bb34257 100644
--- a/libio/iofwrite.c
+++ b/libio/iofwrite.c
@@ -29,7 +29,7 @@
_IO_size_t
_IO_fwrite (const void *buf, _IO_size_t size, _IO_size_t count, _IO_FILE *fp)
{
- _IO_size_t request = size * count;
+ _IO_size_t request = __umul_size_t_saturated (size, count);
_IO_size_t written = 0;
CHECK_FILE (fp, 0);
if (request == 0)
diff --git a/libio/iofwrite_u.c b/libio/iofwrite_u.c
index 2b1c47a..6e002bf 100644
--- a/libio/iofwrite_u.c
+++ b/libio/iofwrite_u.c
@@ -33,7 +33,7 @@ _IO_size_t
fwrite_unlocked (const void *buf, _IO_size_t size, _IO_size_t count,
_IO_FILE *fp)
{
- _IO_size_t request = size * count;
+ _IO_size_t request = __umul_size_t_saturated (size, count);
_IO_size_t written = 0;
CHECK_FILE (fp, 0);
if (request == 0)
diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h
index 99e94cc..4474f09 100644
--- a/misc/sys/cdefs.h
+++ b/misc/sys/cdefs.h
@@ -441,4 +441,37 @@
# endif
#endif
+#include <stddef.h> /* for size_t. */
+
+__always_inline
+static int
+__umul_size_t_overflow (size_t a, size_t b)
+{
+#if __GNUC_PREREQ (5, 0)
+ size_t result;
+
+ /* _Static_assert, but without triggering conformance test failures. */
+ __attribute__ ((__unused__))
+ char sizeof_size_t_eq_sizeof_ulong[
+ sizeof (size_t) == sizeof (unsigned long) ? 1 : -1];
+
+ return __builtin_umull_overflow (a, b, &result);
+#else
+ const size_t half_size_t = (size_t) 1 << 4 * sizeof (size_t);
+ const size_t size_max = (size_t) -1;
+
+ return __glibc_unlikely ((a | b) >= half_size_t) && b > 1 && a > size_max / b;
+#endif
+}
+
+__always_inline
+static size_t
+__umul_size_t_saturated (size_t a, size_t b)
+{
+ const size_t size_max = (size_t) -1;
+
+ if (__umul_size_t_overflow (a, b)) return size_max;
+ return a * b;
+}
+
#endif /* sys/cdefs.h */
More information about the Libc-alpha
mailing list