summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorray <ray@openbsd.org>2007-06-26 05:00:50 +0000
committerray <ray@openbsd.org>2007-06-26 05:00:50 +0000
commit57f92aee30215dd5a0f1b8c6304daafd65a90ac2 (patch)
treef11f3387116bbee98e802ae40eba9ffb22d26c4e
parentadd support for cvs rlog. (diff)
downloadwireguard-openbsd-57f92aee30215dd5a0f1b8c6304daafd65a90ac2.tar.xz
wireguard-openbsd-57f92aee30215dd5a0f1b8c6304daafd65a90ac2.zip
It seems st_size is not always a good estimator for the number of
directory entries. ZFS, for instance, sets st_size to the number of entries. Use the same algorithm for the initial estimate but keep a minimum to prevent a divide by zero. When the buffer is filled, instead of re-using the same flawed algorithm, double the buffer size. Also add check for integer overflow. Bug reported by Ed Ravin, ZFS testing environment provided by Bryan Allen. OK millert
-rw-r--r--lib/libc/gen/scandir.c12
1 files changed, 7 insertions, 5 deletions
diff --git a/lib/libc/gen/scandir.c b/lib/libc/gen/scandir.c
index f3b3fe2b569..089ad19e0da 100644
--- a/lib/libc/gen/scandir.c
+++ b/lib/libc/gen/scandir.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: scandir.c,v 1.10 2005/08/08 08:05:34 espie Exp $ */
+/* $OpenBSD: scandir.c,v 1.11 2007/06/26 05:00:50 ray Exp $ */
/*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
@@ -35,7 +35,7 @@
* struct dirent (through namelist). Returns -1 if there were any errors.
*/
-#include <sys/types.h>
+#include <sys/param.h>
#include <sys/stat.h>
#include <dirent.h>
#include <errno.h>
@@ -73,8 +73,8 @@ scandir(const char *dirname, struct dirent ***namelist,
* estimate the array size by taking the size of the directory file
* and dividing it by a multiple of the minimum size entry.
*/
- arraysz = (stb.st_size / 24);
- if (arraysz > SIZE_T_MAX / sizeof(struct dirent *)) {
+ arraysz = MAX(stb.st_size / 24, 16);
+ if (arraysz > SIZE_MAX / sizeof(struct dirent *)) {
errno = ENOMEM;
goto fail;
}
@@ -96,7 +96,9 @@ scandir(const char *dirname, struct dirent ***namelist,
if (fstat(dirp->dd_fd, &stb) < 0)
goto fail;
- arraysz = stb.st_size / 12;
+ arraysz *= 2;
+ if (SIZE_MAX / sizeof(struct dirent *) < arraysz)
+ goto fail;
nnames = (struct dirent **)realloc((char *)names,
arraysz * sizeof(struct dirent *));
if (nnames == NULL)