Skip to content

Commit

Permalink
Add missing overflow checks in fmapfile(3)
Browse files Browse the repository at this point in the history
  • Loading branch information
GrieferAtWork committed Nov 11, 2023
1 parent bdfcccb commit 62612f5
Show file tree
Hide file tree
Showing 5 changed files with 268 additions and 70 deletions.
108 changes: 87 additions & 21 deletions kos/include/libc/local/sys.mman/fmapfile.h
Original file line number Diff line number Diff line change
@@ -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 *
Expand Down Expand Up @@ -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)) {
Expand All @@ -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))
{
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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)
Expand All @@ -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 */
Expand All @@ -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 {
Expand Down Expand Up @@ -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 */
Expand All @@ -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 {
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand All @@ -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);
Expand Down
6 changes: 3 additions & 3 deletions kos/include/sys/mman.h
Original file line number Diff line number Diff line change
@@ -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 *
Expand Down Expand Up @@ -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'
Expand Down Expand Up @@ -950,7 +950,7 @@ __CDECLARE(__ATTR_WUNUSED __ATTR_FDARG(2) __ATTR_OUT(1),int,__NOTHROW_NCX,fmapfi
#include <libc/local/sys.mman/fmapfile.h>
/* >> 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'
Expand Down
Loading

0 comments on commit 62612f5

Please sign in to comment.