diff --git a/lib/libc/stdio/fread.c b/lib/libc/stdio/fread.c index 6253856b9e33..ad3ea29de3e0 100644 --- a/lib/libc/stdio/fread.c +++ b/lib/libc/stdio/fread.c @@ -37,6 +37,8 @@ static char sccsid[] = "@(#)fread.c 8.2 (Berkeley) 12/11/93"; __FBSDID("$FreeBSD$"); #include "namespace.h" +#include <errno.h> +#include <stdint.h> #include <stdio.h> #include <string.h> #include "un-namespace.h" @@ -69,8 +71,27 @@ __fread(void * __restrict buf, size_t size, size_t count, FILE * __restrict fp) /* * ANSI and SUSv2 require a return value of 0 if size or count are 0. */ - if ((resid = count * size) == 0) + if ((count == 0) || (size == 0)) return (0); + + /* + * Check for integer overflow. As an optimization, first check that + * at least one of {count, size} is at least 2^16, since if both + * values are less than that, their product can't possible overflow + * (size_t is always at least 32 bits on FreeBSD). + */ + if (((count | size) > 0xFFFF) && + (count > SIZE_MAX / size)) { + errno = EINVAL; + fp->_flags |= __SERR; + return (0); + } + + /* + * Compute the (now required to not overflow) number of bytes to + * read and actually do the work. + */ + resid = count * size; ORIENT(fp, -1); if (fp->_r < 0) fp->_r = 0; diff --git a/lib/libc/stdio/fwrite.c b/lib/libc/stdio/fwrite.c index cf52e42f615f..acac94398ea4 100644 --- a/lib/libc/stdio/fwrite.c +++ b/lib/libc/stdio/fwrite.c @@ -37,6 +37,8 @@ static char sccsid[] = "@(#)fwrite.c 8.1 (Berkeley) 6/4/93"; __FBSDID("$FreeBSD$"); #include "namespace.h" +#include <errno.h> +#include <stdint.h> #include <stdio.h> #include "un-namespace.h" #include "local.h" @@ -60,10 +62,24 @@ fwrite(buf, size, count, fp) /* * ANSI and SUSv2 require a return value of 0 if size or count are 0. */ - n = count * size; - if (n == 0) + if ((count == 0) || (size == 0)) return (0); + /* + * Check for integer overflow. As an optimization, first check that + * at least one of {count, size} is at least 2^16, since if both + * values are less than that, their product can't possible overflow + * (size_t is always at least 32 bits on FreeBSD). + */ + if (((count | size) > 0xFFFF) && + (count > SIZE_MAX / size)) { + errno = EINVAL; + fp->_flags |= __SERR; + return (0); + } + + n = count * size; + iov.iov_base = (void *)buf; uio.uio_resid = iov.iov_len = n; uio.uio_iov = &iov;