summaryrefslogtreecommitdiffstats
path: root/lib/libc
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 /lib/libc
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
Diffstat (limited to 'lib/libc')
-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)