From 62612f527db0a4a8c9568fa39cf5cc1c2ac3417f Mon Sep 17 00:00:00 2001 From: GrieferAtWork Date: Sat, 11 Nov 2023 15:27:36 +0100 Subject: [PATCH] Add missing overflow checks in `fmapfile(3)` --- kos/include/libc/local/sys.mman/fmapfile.h | 108 ++++++++++++++++---- kos/include/sys/mman.h | 6 +- kos/src/libc/auto/sys.mman.c | 110 ++++++++++++++++----- kos/src/libc/auto/sys.mman.h | 6 +- kos/src/libc/magic/sys.mman.c | 108 ++++++++++++++++---- 5 files changed, 268 insertions(+), 70 deletions(-) diff --git a/kos/include/libc/local/sys.mman/fmapfile.h b/kos/include/libc/local/sys.mman/fmapfile.h index 590455b285..33262fe69c 100644 --- a/kos/include/libc/local/sys.mman/fmapfile.h +++ b/kos/include/libc/local/sys.mman/fmapfile.h @@ -1,4 +1,4 @@ -/* HASH CRC-32:0xff40fcbc */ +/* HASH CRC-32:0x2e0406e6 */ /* Copyright (c) 2019-2023 Griefer@Work * * * * This software is provided 'as-is', without any express or implied * @@ -361,6 +361,18 @@ __NOTHROW_NCX(__LIBCCALL __LIBC_LOCAL_NAME(fmapfile))(struct mapfile *__restrict __SIZE_TYPE__ __bufused; __SIZE_TYPE__ __buffree; + /* Helper macro that makes sure `errno(3)' is preserved across `expr' */ +#if defined(__libc_geterrno) && defined(__libc_seterrno) +#define __LOCAL_preserve_errno(__expr) \ + do { \ + __errno_t ___saved_errno = __libc_geterrno(); \ + __expr; \ + __libc_seterrno(___saved_errno); \ + } __WHILE0 +#else /* __libc_geterrno && __libc_seterrno */ +#define __LOCAL_preserve_errno(__expr) (__expr) +#endif /* !__libc_geterrno || !__libc_seterrno */ + /* Validate the given `flags' */ if __unlikely(__flags & ~(__FMAPFILE_READALL | __FMAPFILE_MUSTMMAP | __FMAPFILE_MAPSHARED | __FMAPFILE_ATSTART)) { @@ -371,6 +383,21 @@ __NOTHROW_NCX(__LIBCCALL __LIBC_LOCAL_NAME(fmapfile))(struct mapfile *__restrict #endif /* !__EINVAL */ } + /* Check for special case: map an empty portion of the file. */ + if __unlikely(__max_bytes == 0) { +#ifndef __REALLOC_ZERO_IS_NONNULL + if (__num_trailing_nulbytes == 0) + __num_trailing_nulbytes = 1; +#endif /* !__REALLOC_ZERO_IS_NONNULL */ + __buf = (__BYTE_TYPE__ *)(__NAMESPACE_LOCAL_SYM __localdep_calloc)(1, __num_trailing_nulbytes); + if __unlikely(!__buf) + return -1; + __mapping->mf_addr = __buf; + __mapping->mf_size = 0; + __mapping->__mf_mapsize = 0; + return 0; + } + /* Try to use mmap(2) */ #if defined(__PROT_READ) && defined(__PROT_WRITE) && defined(__MAP_PRIVATE) && defined(__SEEK_SET) && (defined(__CRT_HAVE_mmap64) || defined(__CRT_HAVE_mmap) || defined(__CRT_HAVE___mmap)) && ((defined(__CRT_HAVE_kfstat) && defined(__CRT_KOS_PRIMARY)) || (defined(__CRT_HAVE_kfstat64) && defined(__CRT_KOS_PRIMARY)) || defined(__CRT_HAVE_fstat) || defined(__CRT_HAVE_fstat64) || defined(__CRT_HAVE___fstat64_time64) || defined(__CRT_HAVE__fstat) || defined(__CRT_HAVE__fstat32) || defined(__CRT_HAVE__fstati64) || defined(__CRT_HAVE__fstat32i64) || defined(__CRT_HAVE__fstat64) || defined(__CRT_HAVE__fstat64i32)) && (defined(__CRT_HAVE_lseek64) || defined(__CRT_HAVE__lseeki64) || defined(__CRT_HAVE_llseek) || defined(__CRT_HAVE___llseek) || defined(__CRT_HAVE_lseek) || defined(__CRT_HAVE__lseek) || defined(__CRT_HAVE___lseek) || defined(__CRT_HAVE___libc_lseek)) { @@ -428,9 +455,12 @@ __NOTHROW_NCX(__LIBCCALL __LIBC_LOCAL_NAME(fmapfile))(struct mapfile *__restrict /* Map file into memory. */ __SIZE_TYPE__ __mapsize, __used_nulbytes; __used_nulbytes = __num_trailing_nulbytes; - if (__min_bytes > __map_bytes) - __used_nulbytes += __min_bytes - __map_bytes; - __mapsize = __map_bytes + __used_nulbytes; + if (__min_bytes > __map_bytes) { + if __unlikely(__hybrid_overflow_uadd(__used_nulbytes, __min_bytes - __map_bytes, &__used_nulbytes)) + goto __err_2big; + } + if __unlikely(__hybrid_overflow_uadd(__map_bytes, __used_nulbytes, &__mapsize)) + __mapsize = (__SIZE_TYPE__)-1; /* Force mmap failure */ #ifdef __MAP_SHARED if (__flags & __FMAPFILE_MAPSHARED) { if __unlikely(__num_trailing_nulbytes) { @@ -515,7 +545,12 @@ __NOTHROW_NCX(__LIBCCALL __LIBC_LOCAL_NAME(fmapfile))(struct mapfile *__restrict __bufsize = 0x10000; if (__bufsize < __min_bytes) __bufsize = __min_bytes; - __buf = (__BYTE_TYPE__ *)(__NAMESPACE_LOCAL_SYM __localdep_malloc)(__bufsize + __num_trailing_nulbytes); + { + __SIZE_TYPE__ __alcsize; + if __unlikely(__hybrid_overflow_uadd(__bufsize, __num_trailing_nulbytes, &__alcsize)) + goto __err_2big; + __LOCAL_preserve_errno(__buf = (__BYTE_TYPE__ *)(__NAMESPACE_LOCAL_SYM __localdep_malloc)(__alcsize)); + } if __unlikely(!__buf) { __bufsize = 1; if (__bufsize < __min_bytes) @@ -542,7 +577,7 @@ __NOTHROW_NCX(__LIBCCALL __LIBC_LOCAL_NAME(fmapfile))(struct mapfile *__restrict __used_nulbytes = __num_trailing_nulbytes; if (__min_bytes > __bufused) __used_nulbytes += __min_bytes - __bufused; - __newbuf = (__BYTE_TYPE__ *)(__NAMESPACE_LOCAL_SYM __localdep_realloc)(__buf, __bufused + __used_nulbytes); + __LOCAL_preserve_errno(__newbuf = (__BYTE_TYPE__ *)(__NAMESPACE_LOCAL_SYM __localdep_realloc)(__buf, __bufused + __used_nulbytes)); if __likely(__newbuf) __buf = __newbuf; (__NAMESPACE_LOCAL_SYM __localdep_bzero)(__buf + __bufused, __used_nulbytes); /* Trailing NUL-bytes */ @@ -561,15 +596,25 @@ __NOTHROW_NCX(__LIBCCALL __LIBC_LOCAL_NAME(fmapfile))(struct mapfile *__restrict __buffree -= (__SIZE_TYPE__)__error; if (__buffree < 1024) { __BYTE_TYPE__ *__newbuf; - __SIZE_TYPE__ __newsize = __bufsize * 2; - __newbuf = (__BYTE_TYPE__ *)(__NAMESPACE_LOCAL_SYM __localdep_realloc)(__buf, __newsize + __num_trailing_nulbytes); + __SIZE_TYPE__ __newsize, __alcsize; + if __unlikely(__hybrid_overflow_umul(__bufsize, 2, &__newsize)) + __newsize = (__SIZE_TYPE__)-1; + if __unlikely(__hybrid_overflow_uadd(__newsize, __num_trailing_nulbytes, &__alcsize)) + __alcsize = (__SIZE_TYPE__)-1; + __LOCAL_preserve_errno(__newbuf = (__BYTE_TYPE__ *)(__NAMESPACE_LOCAL_SYM __localdep_realloc)(__buf, __alcsize)); if (!__newbuf) { - __newsize = __bufsize + 1024; - __newbuf = (__BYTE_TYPE__ *)(__NAMESPACE_LOCAL_SYM __localdep_realloc)(__buf, __newsize + __num_trailing_nulbytes); + if __unlikely(__hybrid_overflow_uadd(__bufsize, 1024, &__newsize)) + __newsize = (__SIZE_TYPE__)-1; + if __unlikely(__hybrid_overflow_uadd(__newsize, __num_trailing_nulbytes, &__alcsize)) + __alcsize = (__SIZE_TYPE__)-1; + __LOCAL_preserve_errno(__newbuf = (__BYTE_TYPE__ *)(__NAMESPACE_LOCAL_SYM __localdep_realloc)(__buf, __alcsize)); if (!__newbuf) { if (!__buffree) { - __newsize = __bufsize + 1; - __newbuf = (__BYTE_TYPE__ *)(__NAMESPACE_LOCAL_SYM __localdep_realloc)(__buf, __newsize + __num_trailing_nulbytes); + if __unlikely(__hybrid_overflow_uadd(__bufsize, 1, &__newsize)) + goto __err_buf_2big; + if __unlikely(__hybrid_overflow_uadd(__newsize, __num_trailing_nulbytes, &__alcsize)) + goto __err_buf_2big; + __newbuf = (__BYTE_TYPE__ *)(__NAMESPACE_LOCAL_SYM __localdep_realloc)(__buf, __alcsize); if __unlikely(!__newbuf) goto __err_buf; } else { @@ -622,7 +667,7 @@ __NOTHROW_NCX(__LIBCCALL __LIBC_LOCAL_NAME(fmapfile))(struct mapfile *__restrict __used_nulbytes = __num_trailing_nulbytes; if (__min_bytes > __bufused) __used_nulbytes += __min_bytes - __bufused; - __newbuf = (__BYTE_TYPE__ *)(__NAMESPACE_LOCAL_SYM __localdep_realloc)(__buf, __bufused + __used_nulbytes); + __LOCAL_preserve_errno(__newbuf = (__BYTE_TYPE__ *)(__NAMESPACE_LOCAL_SYM __localdep_realloc)(__buf, __bufused + __used_nulbytes)); if __likely(__newbuf) __buf = __newbuf; (__NAMESPACE_LOCAL_SYM __localdep_bzero)(__buf + __bufused, __used_nulbytes); /* Trailing NUL-bytes */ @@ -638,15 +683,25 @@ __NOTHROW_NCX(__LIBCCALL __LIBC_LOCAL_NAME(fmapfile))(struct mapfile *__restrict __buffree -= (__SIZE_TYPE__)__error; if (__buffree < 1024) { __BYTE_TYPE__ *__newbuf; - __SIZE_TYPE__ __newsize = __bufsize * 2; - __newbuf = (__BYTE_TYPE__ *)(__NAMESPACE_LOCAL_SYM __localdep_realloc)(__buf, __newsize + __num_trailing_nulbytes); + __SIZE_TYPE__ __newsize, __alcsize; + if __unlikely(__hybrid_overflow_umul(__bufsize, 2, &__newsize)) + __newsize = (__SIZE_TYPE__)-1; + if __unlikely(__hybrid_overflow_uadd(__newsize, __num_trailing_nulbytes, &__alcsize)) + __alcsize = (__SIZE_TYPE__)-1; + __LOCAL_preserve_errno(__newbuf = (__BYTE_TYPE__ *)(__NAMESPACE_LOCAL_SYM __localdep_realloc)(__buf, __alcsize)); if (!__newbuf) { - __newsize = __bufsize + 1024; - __newbuf = (__BYTE_TYPE__ *)(__NAMESPACE_LOCAL_SYM __localdep_realloc)(__buf, __newsize + __num_trailing_nulbytes); + if __unlikely(__hybrid_overflow_uadd(__bufsize, 1024, &__newsize)) + __newsize = (__SIZE_TYPE__)-1; + if __unlikely(__hybrid_overflow_uadd(__newsize, __num_trailing_nulbytes, &__alcsize)) + __alcsize = (__SIZE_TYPE__)-1; + __LOCAL_preserve_errno(__newbuf = (__BYTE_TYPE__ *)(__NAMESPACE_LOCAL_SYM __localdep_realloc)(__buf, __alcsize)); if (!__newbuf) { if (!__buffree) { - __newsize = __bufsize + 1; - __newbuf = (__BYTE_TYPE__ *)(__NAMESPACE_LOCAL_SYM __localdep_realloc)(__buf, __newsize + __num_trailing_nulbytes); + if __unlikely(__hybrid_overflow_uadd(__bufsize, 1, &__newsize)) + goto __err_buf_2big; + if __unlikely(__hybrid_overflow_uadd(__newsize, __num_trailing_nulbytes, &__alcsize)) + goto __err_buf_2big; + __newbuf = (__BYTE_TYPE__ *)(__NAMESPACE_LOCAL_SYM __localdep_realloc)(__buf, __alcsize); if __unlikely(!__newbuf) goto __err_buf; } else { @@ -675,7 +730,7 @@ __NOTHROW_NCX(__LIBCCALL __LIBC_LOCAL_NAME(fmapfile))(struct mapfile *__restrict * lead to memory becoming very badly fragmented. */ __empty_file: __used_nulbytes = __min_bytes + __num_trailing_nulbytes; - __newbuf = (__BYTE_TYPE__ *)(__NAMESPACE_LOCAL_SYM __localdep_calloc)(1, __used_nulbytes); + __LOCAL_preserve_errno(__newbuf = (__BYTE_TYPE__ *)(__NAMESPACE_LOCAL_SYM __localdep_calloc)(1, __used_nulbytes)); if __likely(__newbuf) { #if defined(__CRT_HAVE_free) || defined(__CRT_HAVE_cfree) || defined(__CRT_HAVE___libc_free) (__NAMESPACE_LOCAL_SYM __localdep_free)(__buf); @@ -685,7 +740,7 @@ __NOTHROW_NCX(__LIBCCALL __LIBC_LOCAL_NAME(fmapfile))(struct mapfile *__restrict if __unlikely(!__used_nulbytes) __used_nulbytes = 1; #endif /* !__REALLOC_ZERO_IS_NONNULL */ - __newbuf = (__BYTE_TYPE__ *)(__NAMESPACE_LOCAL_SYM __localdep_realloc)(__buf, __used_nulbytes); + __LOCAL_preserve_errno(__newbuf = (__BYTE_TYPE__ *)(__NAMESPACE_LOCAL_SYM __localdep_realloc)(__buf, __used_nulbytes)); if (!__newbuf) __newbuf = __buf; (__NAMESPACE_LOCAL_SYM __localdep_bzero)(__newbuf, __used_nulbytes); @@ -694,7 +749,18 @@ __NOTHROW_NCX(__LIBCCALL __LIBC_LOCAL_NAME(fmapfile))(struct mapfile *__restrict __mapping->mf_size = 0; __mapping->__mf_mapsize = 0; } +#undef __LOCAL_preserve_errno return 0; +__err_2big: +#if defined(__CRT_HAVE_free) || defined(__CRT_HAVE_cfree) || defined(__CRT_HAVE___libc_free) + __buf = __NULLPTR; +#endif /* __CRT_HAVE_free || __CRT_HAVE_cfree || __CRT_HAVE___libc_free */ +__err_buf_2big: +#ifdef __ENOMEM + __libc_seterrno(__ENOMEM); +#else /* __ENOMEM */ + __libc_seterrno(1); +#endif /* !__ENOMEM */ __err_buf: #if defined(__CRT_HAVE_free) || defined(__CRT_HAVE_cfree) || defined(__CRT_HAVE___libc_free) (__NAMESPACE_LOCAL_SYM __localdep_free)(__buf); diff --git a/kos/include/sys/mman.h b/kos/include/sys/mman.h index ae75912353..3a9b45d06c 100644 --- a/kos/include/sys/mman.h +++ b/kos/include/sys/mman.h @@ -1,4 +1,4 @@ -/* HASH CRC-32:0x2aabd28b */ +/* HASH CRC-32:0x9418e0f1 */ /* Copyright (c) 2019-2023 Griefer@Work * * * * This software is provided 'as-is', without any express or implied * @@ -894,7 +894,7 @@ __SYSDECL_BEGIN #ifdef __CRT_HAVE_fmapfile /* >> fmapfile(3) * A function that can be used to map a specific sub-range of some file into memory. - * This function tries the following (in order) when trying to create the mapping: + * This function tries the following (in this order) in order to create the mapping: * - mmap(2): If `fd' can be mmap'd, then that is how the mapping is created * - malloc(3) + pread(2): If `fd' supports pread(2), use that to fill a buffer * - malloc(3) + lseek(2) + read(2): For a non-zero offset, try to use lseek(2) to move to `offset' @@ -950,7 +950,7 @@ __CDECLARE(__ATTR_WUNUSED __ATTR_FDARG(2) __ATTR_OUT(1),int,__NOTHROW_NCX,fmapfi #include /* >> fmapfile(3) * A function that can be used to map a specific sub-range of some file into memory. - * This function tries the following (in order) when trying to create the mapping: + * This function tries the following (in this order) in order to create the mapping: * - mmap(2): If `fd' can be mmap'd, then that is how the mapping is created * - malloc(3) + pread(2): If `fd' supports pread(2), use that to fill a buffer * - malloc(3) + lseek(2) + read(2): For a non-zero offset, try to use lseek(2) to move to `offset' diff --git a/kos/src/libc/auto/sys.mman.c b/kos/src/libc/auto/sys.mman.c index 7ecc43c5a0..6e9916cc95 100644 --- a/kos/src/libc/auto/sys.mman.c +++ b/kos/src/libc/auto/sys.mman.c @@ -1,4 +1,4 @@ -/* HASH CRC-32:0x79ab4d5d */ +/* HASH CRC-32:0x1943373c */ /* Copyright (c) 2019-2023 Griefer@Work * * * * This software is provided 'as-is', without any express or implied * @@ -287,7 +287,7 @@ NOTHROW_NCX(LIBCCALL libc_pkey_get)(int pkey) { #include /* >> fmapfile(3) * A function that can be used to map a specific sub-range of some file into memory. - * This function tries the following (in order) when trying to create the mapping: + * This function tries the following (in this order) in order to create the mapping: * - mmap(2): If `fd' can be mmap'd, then that is how the mapping is created * - malloc(3) + pread(2): If `fd' supports pread(2), use that to fill a buffer * - malloc(3) + lseek(2) + read(2): For a non-zero offset, try to use lseek(2) to move to `offset' @@ -351,6 +351,18 @@ NOTHROW_NCX(LIBCCALL libc_fmapfile)(struct mapfile *__restrict mapping, size_t bufused; size_t buffree; + /* Helper macro that makes sure `errno(3)' is preserved across `expr' */ + +#define __LOCAL_preserve_errno(expr) \ + do { \ + errno_t _saved_errno = __libc_geterrno(); \ + expr; \ + __libc_seterrno(_saved_errno); \ + } __WHILE0 + + + + /* Validate the given `flags' */ if unlikely(flags & ~(__FMAPFILE_READALL | __FMAPFILE_MUSTMMAP | __FMAPFILE_MAPSHARED | __FMAPFILE_ATSTART)) { @@ -361,6 +373,21 @@ NOTHROW_NCX(LIBCCALL libc_fmapfile)(struct mapfile *__restrict mapping, } + /* Check for special case: map an empty portion of the file. */ + if unlikely(max_bytes == 0) { +#ifndef __REALLOC_ZERO_IS_NONNULL + if (num_trailing_nulbytes == 0) + num_trailing_nulbytes = 1; +#endif /* !__REALLOC_ZERO_IS_NONNULL */ + buf = (byte_t *)libc_calloc(1, num_trailing_nulbytes); + if unlikely(!buf) + return -1; + mapping->mf_addr = buf; + mapping->mf_size = 0; + mapping->__mf_mapsize = 0; + return 0; + } + /* Try to use mmap(2) */ { @@ -418,9 +445,12 @@ NOTHROW_NCX(LIBCCALL libc_fmapfile)(struct mapfile *__restrict mapping, /* Map file into memory. */ size_t mapsize, used_nulbytes; used_nulbytes = num_trailing_nulbytes; - if (min_bytes > map_bytes) - used_nulbytes += min_bytes - map_bytes; - mapsize = map_bytes + used_nulbytes; + if (min_bytes > map_bytes) { + if unlikely(__hybrid_overflow_uadd(used_nulbytes, min_bytes - map_bytes, &used_nulbytes)) + goto err_2big; + } + if unlikely(__hybrid_overflow_uadd(map_bytes, used_nulbytes, &mapsize)) + mapsize = (size_t)-1; /* Force mmap failure */ if (flags & __FMAPFILE_MAPSHARED) { if unlikely(num_trailing_nulbytes) { @@ -505,7 +535,12 @@ NOTHROW_NCX(LIBCCALL libc_fmapfile)(struct mapfile *__restrict mapping, bufsize = 0x10000; if (bufsize < min_bytes) bufsize = min_bytes; - buf = (byte_t *)libc_malloc(bufsize + num_trailing_nulbytes); + { + size_t alcsize; + if unlikely(__hybrid_overflow_uadd(bufsize, num_trailing_nulbytes, &alcsize)) + goto err_2big; + __LOCAL_preserve_errno(buf = (byte_t *)libc_malloc(alcsize)); + } if unlikely(!buf) { bufsize = 1; if (bufsize < min_bytes) @@ -532,7 +567,7 @@ NOTHROW_NCX(LIBCCALL libc_fmapfile)(struct mapfile *__restrict mapping, used_nulbytes = num_trailing_nulbytes; if (min_bytes > bufused) used_nulbytes += min_bytes - bufused; - newbuf = (byte_t *)libc_realloc(buf, bufused + used_nulbytes); + __LOCAL_preserve_errno(newbuf = (byte_t *)libc_realloc(buf, bufused + used_nulbytes)); if likely(newbuf) buf = newbuf; libc_bzero(buf + bufused, used_nulbytes); /* Trailing NUL-bytes */ @@ -551,15 +586,25 @@ NOTHROW_NCX(LIBCCALL libc_fmapfile)(struct mapfile *__restrict mapping, buffree -= (size_t)error; if (buffree < 1024) { byte_t *newbuf; - size_t newsize = bufsize * 2; - newbuf = (byte_t *)libc_realloc(buf, newsize + num_trailing_nulbytes); + size_t newsize, alcsize; + if unlikely(__hybrid_overflow_umul(bufsize, 2, &newsize)) + newsize = (size_t)-1; + if unlikely(__hybrid_overflow_uadd(newsize, num_trailing_nulbytes, &alcsize)) + alcsize = (size_t)-1; + __LOCAL_preserve_errno(newbuf = (byte_t *)libc_realloc(buf, alcsize)); if (!newbuf) { - newsize = bufsize + 1024; - newbuf = (byte_t *)libc_realloc(buf, newsize + num_trailing_nulbytes); + if unlikely(__hybrid_overflow_uadd(bufsize, 1024, &newsize)) + newsize = (size_t)-1; + if unlikely(__hybrid_overflow_uadd(newsize, num_trailing_nulbytes, &alcsize)) + alcsize = (size_t)-1; + __LOCAL_preserve_errno(newbuf = (byte_t *)libc_realloc(buf, alcsize)); if (!newbuf) { if (!buffree) { - newsize = bufsize + 1; - newbuf = (byte_t *)libc_realloc(buf, newsize + num_trailing_nulbytes); + if unlikely(__hybrid_overflow_uadd(bufsize, 1, &newsize)) + goto err_buf_2big; + if unlikely(__hybrid_overflow_uadd(newsize, num_trailing_nulbytes, &alcsize)) + goto err_buf_2big; + newbuf = (byte_t *)libc_realloc(buf, alcsize); if unlikely(!newbuf) goto err_buf; } else { @@ -612,7 +657,7 @@ NOTHROW_NCX(LIBCCALL libc_fmapfile)(struct mapfile *__restrict mapping, used_nulbytes = num_trailing_nulbytes; if (min_bytes > bufused) used_nulbytes += min_bytes - bufused; - newbuf = (byte_t *)libc_realloc(buf, bufused + used_nulbytes); + __LOCAL_preserve_errno(newbuf = (byte_t *)libc_realloc(buf, bufused + used_nulbytes)); if likely(newbuf) buf = newbuf; libc_bzero(buf + bufused, used_nulbytes); /* Trailing NUL-bytes */ @@ -628,15 +673,25 @@ NOTHROW_NCX(LIBCCALL libc_fmapfile)(struct mapfile *__restrict mapping, buffree -= (size_t)error; if (buffree < 1024) { byte_t *newbuf; - size_t newsize = bufsize * 2; - newbuf = (byte_t *)libc_realloc(buf, newsize + num_trailing_nulbytes); + size_t newsize, alcsize; + if unlikely(__hybrid_overflow_umul(bufsize, 2, &newsize)) + newsize = (size_t)-1; + if unlikely(__hybrid_overflow_uadd(newsize, num_trailing_nulbytes, &alcsize)) + alcsize = (size_t)-1; + __LOCAL_preserve_errno(newbuf = (byte_t *)libc_realloc(buf, alcsize)); if (!newbuf) { - newsize = bufsize + 1024; - newbuf = (byte_t *)libc_realloc(buf, newsize + num_trailing_nulbytes); + if unlikely(__hybrid_overflow_uadd(bufsize, 1024, &newsize)) + newsize = (size_t)-1; + if unlikely(__hybrid_overflow_uadd(newsize, num_trailing_nulbytes, &alcsize)) + alcsize = (size_t)-1; + __LOCAL_preserve_errno(newbuf = (byte_t *)libc_realloc(buf, alcsize)); if (!newbuf) { if (!buffree) { - newsize = bufsize + 1; - newbuf = (byte_t *)libc_realloc(buf, newsize + num_trailing_nulbytes); + if unlikely(__hybrid_overflow_uadd(bufsize, 1, &newsize)) + goto err_buf_2big; + if unlikely(__hybrid_overflow_uadd(newsize, num_trailing_nulbytes, &alcsize)) + goto err_buf_2big; + newbuf = (byte_t *)libc_realloc(buf, alcsize); if unlikely(!newbuf) goto err_buf; } else { @@ -665,7 +720,7 @@ NOTHROW_NCX(LIBCCALL libc_fmapfile)(struct mapfile *__restrict mapping, * lead to memory becoming very badly fragmented. */ empty_file: used_nulbytes = min_bytes + num_trailing_nulbytes; - newbuf = (byte_t *)libc_calloc(1, used_nulbytes); + __LOCAL_preserve_errno(newbuf = (byte_t *)libc_calloc(1, used_nulbytes)); if likely(newbuf) { libc_free(buf); @@ -675,7 +730,7 @@ NOTHROW_NCX(LIBCCALL libc_fmapfile)(struct mapfile *__restrict mapping, if unlikely(!used_nulbytes) used_nulbytes = 1; #endif /* !__REALLOC_ZERO_IS_NONNULL */ - newbuf = (byte_t *)libc_realloc(buf, used_nulbytes); + __LOCAL_preserve_errno(newbuf = (byte_t *)libc_realloc(buf, used_nulbytes)); if (!newbuf) newbuf = buf; libc_bzero(newbuf, used_nulbytes); @@ -684,7 +739,18 @@ NOTHROW_NCX(LIBCCALL libc_fmapfile)(struct mapfile *__restrict mapping, mapping->mf_size = 0; mapping->__mf_mapsize = 0; } +#undef __LOCAL_preserve_errno return 0; +err_2big: + + buf = NULL; + +err_buf_2big: + + __libc_seterrno(ENOMEM); + + + err_buf: libc_free(buf); diff --git a/kos/src/libc/auto/sys.mman.h b/kos/src/libc/auto/sys.mman.h index a88dd9102c..ac88a04b71 100644 --- a/kos/src/libc/auto/sys.mman.h +++ b/kos/src/libc/auto/sys.mman.h @@ -1,4 +1,4 @@ -/* HASH CRC-32:0xbe02e950 */ +/* HASH CRC-32:0x15218253 */ /* Copyright (c) 2019-2023 Griefer@Work * * * * This software is provided 'as-is', without any express or implied * @@ -142,7 +142,7 @@ INTDEF ATTR_ACCESS_NONE(1) int NOTHROW_NCX(LIBDCALL libd_pkey_mprotect)(void *ad #if !defined(__LIBCCALL_IS_LIBDCALL) && !defined(__KERNEL__) /* >> fmapfile(3) * A function that can be used to map a specific sub-range of some file into memory. - * This function tries the following (in order) when trying to create the mapping: + * This function tries the following (in this order) in order to create the mapping: * - mmap(2): If `fd' can be mmap'd, then that is how the mapping is created * - malloc(3) + pread(2): If `fd' supports pread(2), use that to fill a buffer * - malloc(3) + lseek(2) + read(2): For a non-zero offset, try to use lseek(2) to move to `offset' @@ -198,7 +198,7 @@ INTDEF WUNUSED ATTR_FDARG(2) ATTR_OUT(1) int NOTHROW_NCX(LIBDCALL libd_fmapfile) #ifndef __KERNEL__ /* >> fmapfile(3) * A function that can be used to map a specific sub-range of some file into memory. - * This function tries the following (in order) when trying to create the mapping: + * This function tries the following (in this order) in order to create the mapping: * - mmap(2): If `fd' can be mmap'd, then that is how the mapping is created * - malloc(3) + pread(2): If `fd' supports pread(2), use that to fill a buffer * - malloc(3) + lseek(2) + read(2): For a non-zero offset, try to use lseek(2) to move to `offset' diff --git a/kos/src/libc/magic/sys.mman.c b/kos/src/libc/magic/sys.mman.c index b36d1c9af9..0eeedaea37 100644 --- a/kos/src/libc/magic/sys.mman.c +++ b/kos/src/libc/magic/sys.mman.c @@ -1124,7 +1124,7 @@ int pkey_mprotect([[access(none)]] void *addr, size_t len, __STDC_INT_AS_UINT_T @@>> fmapfile(3) @@A function that can be used to map a specific sub-range of some file into memory. -@@This function tries the following (in order) when trying to create the mapping: +@@This function tries the following (in this order) in order to create the mapping: @@ - mmap(2): If `fd' can be mmap'd, then that is how the mapping is created @@ - malloc(3) + pread(2): If `fd' supports pread(2), use that to fill a buffer @@ - malloc(3) + lseek(2) + read(2): For a non-zero offset, try to use lseek(2) to move to `offset' @@ -1189,6 +1189,18 @@ int fmapfile([[out]] struct mapfile *__restrict mapping, [[fdarg]] $fd_t fd, size_t bufused; size_t buffree; + /* Helper macro that makes sure `errno(3)' is preserved across `expr' */ +@@pp_if defined(__libc_geterrno) && defined(__libc_seterrno)@@ +#define __LOCAL_preserve_errno(expr) \ + do { \ + errno_t _saved_errno = __libc_geterrno(); \ + expr; \ + __libc_seterrno(_saved_errno); \ + } __WHILE0 +@@pp_else@@ +#define __LOCAL_preserve_errno(expr) (expr) +@@pp_endif@@ + /* Validate the given `flags' */ if unlikely(flags & ~(__FMAPFILE_READALL | __FMAPFILE_MUSTMMAP | __FMAPFILE_MAPSHARED | __FMAPFILE_ATSTART)) { @@ -1199,6 +1211,21 @@ int fmapfile([[out]] struct mapfile *__restrict mapping, [[fdarg]] $fd_t fd, @@pp_endif@@ } + /* Check for special case: map an empty portion of the file. */ + if unlikely(max_bytes == 0) { +@@pp_ifndef __REALLOC_ZERO_IS_NONNULL@@ + if (num_trailing_nulbytes == 0) + num_trailing_nulbytes = 1; +@@pp_endif@@ + buf = (byte_t *)calloc(1, num_trailing_nulbytes); + if unlikely(!buf) + return -1; + mapping->@mf_addr@ = buf; + mapping->@mf_size@ = 0; + mapping->@__mf_mapsize@ = 0; + return 0; + } + /* Try to use mmap(2) */ @@pp_if defined(__PROT_READ) && defined(__PROT_WRITE) && defined(__MAP_PRIVATE) && defined(__SEEK_SET) && $has_function(mmap64, fstat64, lseek64)@@ { @@ -1256,9 +1283,12 @@ int fmapfile([[out]] struct mapfile *__restrict mapping, [[fdarg]] $fd_t fd, /* Map file into memory. */ size_t mapsize, used_nulbytes; used_nulbytes = num_trailing_nulbytes; - if (min_bytes > map_bytes) - used_nulbytes += min_bytes - map_bytes; - mapsize = map_bytes + used_nulbytes; + if (min_bytes > map_bytes) { + if unlikely(__hybrid_overflow_uadd(used_nulbytes, min_bytes - map_bytes, &used_nulbytes)) + goto err_2big; + } + if unlikely(__hybrid_overflow_uadd(map_bytes, used_nulbytes, &mapsize)) + mapsize = (size_t)-1; /* Force mmap failure */ @@pp_ifdef __MAP_SHARED@@ if (flags & __FMAPFILE_MAPSHARED) { if unlikely(num_trailing_nulbytes) { @@ -1343,7 +1373,12 @@ int fmapfile([[out]] struct mapfile *__restrict mapping, [[fdarg]] $fd_t fd, bufsize = 0x10000; if (bufsize < min_bytes) bufsize = min_bytes; - buf = (byte_t *)malloc(bufsize + num_trailing_nulbytes); + { + size_t alcsize; + if unlikely(__hybrid_overflow_uadd(bufsize, num_trailing_nulbytes, &alcsize)) + goto err_2big; + __LOCAL_preserve_errno(buf = (byte_t *)malloc(alcsize)); + } if unlikely(!buf) { bufsize = 1; if (bufsize < min_bytes) @@ -1370,7 +1405,7 @@ int fmapfile([[out]] struct mapfile *__restrict mapping, [[fdarg]] $fd_t fd, used_nulbytes = num_trailing_nulbytes; if (min_bytes > bufused) used_nulbytes += min_bytes - bufused; - newbuf = (byte_t *)realloc(buf, bufused + used_nulbytes); + __LOCAL_preserve_errno(newbuf = (byte_t *)realloc(buf, bufused + used_nulbytes)); if likely(newbuf) buf = newbuf; bzero(buf + bufused, used_nulbytes); /* Trailing NUL-bytes */ @@ -1389,15 +1424,25 @@ int fmapfile([[out]] struct mapfile *__restrict mapping, [[fdarg]] $fd_t fd, buffree -= (size_t)error; if (buffree < 1024) { byte_t *newbuf; - size_t newsize = bufsize * 2; - newbuf = (byte_t *)realloc(buf, newsize + num_trailing_nulbytes); + size_t newsize, alcsize; + if unlikely(__hybrid_overflow_umul(bufsize, 2, &newsize)) + newsize = (size_t)-1; + if unlikely(__hybrid_overflow_uadd(newsize, num_trailing_nulbytes, &alcsize)) + alcsize = (size_t)-1; + __LOCAL_preserve_errno(newbuf = (byte_t *)realloc(buf, alcsize)); if (!newbuf) { - newsize = bufsize + 1024; - newbuf = (byte_t *)realloc(buf, newsize + num_trailing_nulbytes); + if unlikely(__hybrid_overflow_uadd(bufsize, 1024, &newsize)) + newsize = (size_t)-1; + if unlikely(__hybrid_overflow_uadd(newsize, num_trailing_nulbytes, &alcsize)) + alcsize = (size_t)-1; + __LOCAL_preserve_errno(newbuf = (byte_t *)realloc(buf, alcsize)); if (!newbuf) { if (!buffree) { - newsize = bufsize + 1; - newbuf = (byte_t *)realloc(buf, newsize + num_trailing_nulbytes); + if unlikely(__hybrid_overflow_uadd(bufsize, 1, &newsize)) + goto err_buf_2big; + if unlikely(__hybrid_overflow_uadd(newsize, num_trailing_nulbytes, &alcsize)) + goto err_buf_2big; + newbuf = (byte_t *)realloc(buf, alcsize); if unlikely(!newbuf) goto err_buf; } else { @@ -1450,7 +1495,7 @@ int fmapfile([[out]] struct mapfile *__restrict mapping, [[fdarg]] $fd_t fd, used_nulbytes = num_trailing_nulbytes; if (min_bytes > bufused) used_nulbytes += min_bytes - bufused; - newbuf = (byte_t *)realloc(buf, bufused + used_nulbytes); + __LOCAL_preserve_errno(newbuf = (byte_t *)realloc(buf, bufused + used_nulbytes)); if likely(newbuf) buf = newbuf; bzero(buf + bufused, used_nulbytes); /* Trailing NUL-bytes */ @@ -1466,15 +1511,25 @@ int fmapfile([[out]] struct mapfile *__restrict mapping, [[fdarg]] $fd_t fd, buffree -= (size_t)error; if (buffree < 1024) { byte_t *newbuf; - size_t newsize = bufsize * 2; - newbuf = (byte_t *)realloc(buf, newsize + num_trailing_nulbytes); + size_t newsize, alcsize; + if unlikely(__hybrid_overflow_umul(bufsize, 2, &newsize)) + newsize = (size_t)-1; + if unlikely(__hybrid_overflow_uadd(newsize, num_trailing_nulbytes, &alcsize)) + alcsize = (size_t)-1; + __LOCAL_preserve_errno(newbuf = (byte_t *)realloc(buf, alcsize)); if (!newbuf) { - newsize = bufsize + 1024; - newbuf = (byte_t *)realloc(buf, newsize + num_trailing_nulbytes); + if unlikely(__hybrid_overflow_uadd(bufsize, 1024, &newsize)) + newsize = (size_t)-1; + if unlikely(__hybrid_overflow_uadd(newsize, num_trailing_nulbytes, &alcsize)) + alcsize = (size_t)-1; + __LOCAL_preserve_errno(newbuf = (byte_t *)realloc(buf, alcsize)); if (!newbuf) { if (!buffree) { - newsize = bufsize + 1; - newbuf = (byte_t *)realloc(buf, newsize + num_trailing_nulbytes); + if unlikely(__hybrid_overflow_uadd(bufsize, 1, &newsize)) + goto err_buf_2big; + if unlikely(__hybrid_overflow_uadd(newsize, num_trailing_nulbytes, &alcsize)) + goto err_buf_2big; + newbuf = (byte_t *)realloc(buf, alcsize); if unlikely(!newbuf) goto err_buf; } else { @@ -1503,7 +1558,7 @@ int fmapfile([[out]] struct mapfile *__restrict mapping, [[fdarg]] $fd_t fd, * lead to memory becoming very badly fragmented. */ empty_file: used_nulbytes = min_bytes + num_trailing_nulbytes; - newbuf = (byte_t *)calloc(1, used_nulbytes); + __LOCAL_preserve_errno(newbuf = (byte_t *)calloc(1, used_nulbytes)); if likely(newbuf) { @@pp_if $has_function(free)@@ free(buf); @@ -1513,7 +1568,7 @@ int fmapfile([[out]] struct mapfile *__restrict mapping, [[fdarg]] $fd_t fd, if unlikely(!used_nulbytes) used_nulbytes = 1; @@pp_endif@@ - newbuf = (byte_t *)realloc(buf, used_nulbytes); + __LOCAL_preserve_errno(newbuf = (byte_t *)realloc(buf, used_nulbytes)); if (!newbuf) newbuf = buf; bzero(newbuf, used_nulbytes); @@ -1522,7 +1577,18 @@ int fmapfile([[out]] struct mapfile *__restrict mapping, [[fdarg]] $fd_t fd, mapping->@mf_size@ = 0; mapping->@__mf_mapsize@ = 0; } +#undef __LOCAL_preserve_errno return 0; +err_2big: +@@pp_if $has_function(free)@@ + buf = NULL; +@@pp_endif@@ +err_buf_2big: +@@pp_ifdef ENOMEM@@ + __libc_seterrno(ENOMEM); +@@pp_else@@ + __libc_seterrno(1); +@@pp_endif@@ err_buf: @@pp_if $has_function(free)@@ free(buf);