Skip to content
Snippets Groups Projects
Commit e8d226b2 authored by Fred Wright's avatar Fred Wright Committed by Christopher Nielsen
Browse files

test_fdopendir: Add fstatat() buffer overrun defense.

At the time of this writing, fstatat() may choose the wrong variant of
stat to return, possibly overflowing the provided buffer.  To defend
against this, we make the buffer the larger of the two possible sizes,
and also move it off the stack for less verbosity when debugging.  See
the comment in the code.

TESTED:
All versions pass, including previously crashing ino32 cases.
parent 3662d5f8
No related tags found
No related merge requests found
/* /*
* Copyright (c) 2019 * Copyright (c) 2019
* Copyright (C) 2023 raf <raf@raf.org> * Copyright (C) 2023 raf <raf@raf.org>
...@@ -28,6 +27,20 @@ ...@@ -28,6 +27,20 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
/*
* Buffer for fstatat() result. Due to possible confusion over which variant
* should apply, we make it large enough for either variant. Since the
* use of fstatat is only incidental to this test, and the data isn't actually
* used, we don't bother checking for this confusion (and the related possible
* buffer overrun). A separate test should handle that.
*/
static union stat_u {
struct stat st;
#ifdef __DARWIN_STRUCT_STAT64
struct stat_64 __DARWIN_STRUCT_STAT64 st64;
#endif
} stbuf;
/* Test expected failure case */ /* Test expected failure case */
int check_failure(int fd, const char *name, const char *exp_sym, int exp_val) int check_failure(int fd, const char *name, const char *exp_sym, int exp_val)
...@@ -51,7 +64,6 @@ int ...@@ -51,7 +64,6 @@ int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
int verbose = 0; int verbose = 0;
struct stat st;
struct dirent *entry; struct dirent *entry;
int dfd = -1; int dfd = -1;
DIR *dir; DIR *dir;
...@@ -84,7 +96,7 @@ main(int argc, char *argv[]) ...@@ -84,7 +96,7 @@ main(int argc, char *argv[])
return 1; return 1;
} }
if (fstatat(dfd, entry->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) { if (fstatat(dfd, entry->d_name, &stbuf.st, AT_SYMLINK_NOFOLLOW) < 0) {
perror("error: fstatat after fdopendir failed"); perror("error: fstatat after fdopendir failed");
fprintf(stderr, "dfd=%i d_name=%s\n", dfd, entry->d_name); fprintf(stderr, "dfd=%i d_name=%s\n", dfd, entry->d_name);
free(first_entry); free(first_entry);
...@@ -193,7 +205,7 @@ main(int argc, char *argv[]) ...@@ -193,7 +205,7 @@ main(int argc, char *argv[])
if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
continue; continue;
if (fstatat(dfd, entry->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) { if (fstatat(dfd, entry->d_name, &stbuf.st, AT_SYMLINK_NOFOLLOW) < 0) {
perror("error: fstatat after opendir failed"); perror("error: fstatat after opendir failed");
fprintf(stderr, "dfd=%i d_name=%s\n", dfd, entry->d_name); fprintf(stderr, "dfd=%i d_name=%s\n", dfd, entry->d_name);
(void)closedir(dir); (void)closedir(dir);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment