From bc6b256c343893b7b579baddeee140f22777537c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20B=C3=BChler?= Date: Sat, 29 Jul 2017 15:21:08 +0200 Subject: [PATCH] [core] use readdir instead of readdir_r readdir_r is deprecated in glibc due to serious memory handling issues in the API: one cannot pass the size of the allocated dirent. glibc authors claims readdir is thread-safe in modern implementations, and expect POSIX to require it in a future version. No way to check whether readdir is thread-safe though :( ("thread-safe" in this context means different directory streams, which is good enough.) Also remove li_dirent_buf_size. Change-Id: Ia5eae3327e97dc4b0751fb2604ea21c0ce09a5f9 --- include/lighttpd/utils.h | 2 -- src/common/utils.c | 30 ------------------------------ src/main/stat_cache.c | 21 ++++++++++----------- 3 files changed, 10 insertions(+), 43 deletions(-) diff --git a/include/lighttpd/utils.h b/include/lighttpd/utils.h index 00df9c4..39f4a91 100644 --- a/include/lighttpd/utils.h +++ b/include/lighttpd/utils.h @@ -81,8 +81,6 @@ LI_API gboolean li_string_suffix(const GString *str, const gchar *s, gsize len); LI_API void li_string_append_int(GString *dest, gint64 val); -LI_API gsize li_dirent_buf_size(DIR * dirp); - LI_API void li_apr_sha1_base64(GString *dest, const GString *passwd); LI_API void li_apr_md5_crypt(GString *dest, const GString *password, const GString *salt); diff --git a/src/common/utils.c b/src/common/utils.c index 06f57d4..70c7904 100644 --- a/src/common/utils.c +++ b/src/common/utils.c @@ -851,36 +851,6 @@ void li_string_append_int(GString *dest, gint64 v) { dest->len = len; } -/* http://womble.decadentplace.org.uk/readdir_r-advisory.html */ -gsize li_dirent_buf_size(DIR * dirp) { - glong name_max; - gsize name_end; - -# if !defined(HAVE_DIRFD) - UNUSED(dirp); -# endif - -# if defined(HAVE_FPATHCONF) && defined(HAVE_DIRFD) && defined(_PC_NAME_MAX) - name_max = fpathconf(dirfd(dirp), _PC_NAME_MAX); - if (name_max == -1) -# if defined(NAME_MAX) - name_max = (NAME_MAX > 255) ? NAME_MAX : 255; -# else - return (gsize)(-1); -# endif -# else -# if defined(NAME_MAX) - name_max = (NAME_MAX > 255) ? NAME_MAX : 255; -# else -# error "buffer size for readdir_r cannot be determined" -# endif -# endif - - name_end = (gsize)offsetof(struct dirent, d_name) + name_max + 1; - - return (name_end > sizeof(struct dirent) ? name_end : sizeof(struct dirent)); -} - const char *li_remove_path(const char *path) { char *p = strrchr(path, G_DIR_SEPARATOR); if (NULL != p && *(p) != '\0') { diff --git a/src/main/stat_cache.c b/src/main/stat_cache.c index 8d5998c..506e712 100644 --- a/src/main/stat_cache.c +++ b/src/main/stat_cache.c @@ -108,10 +108,7 @@ static void stat_cache_run(gpointer data) { if (!sce->data.failed && sce->type == STAT_CACHE_ENTRY_DIR) { /* dirlisting */ DIR *dirp; - gsize size; - struct dirent *entry; struct dirent *result; - gint error; liStatCacheEntryData sced; GString *str; @@ -120,16 +117,19 @@ static void stat_cache_run(gpointer data) { sce->data.failed = TRUE; sce->data.err = errno; } else { - size = li_dirent_buf_size(dirp); - LI_FORCE_ASSERT(size != (gsize)-1); - entry = g_slice_alloc(size); - sce->dirlist = g_array_sized_new(FALSE, FALSE, sizeof(liStatCacheEntryData), 32); str = g_string_sized_new(sce->data.path->len + 64); g_string_append_len(str, GSTR_LEN(sce->data.path)); - while ((error = readdir_r(dirp, entry, &result)) == 0 && result != NULL) { + /* glibc claims modern readdir are thread-safe, and + * readdir_r has issues. no way to check readdir is actually + * safe, hope for the best. + */ + for (;;) { + errno = 0; /* readdir may not reset errno */ + if (NULL == (result = readdir(dirp))) break; + /* hide "." and ".." */ if (result->d_name[0] == '.' && (result->d_name[1] == '\0' || (result->d_name[1] == '.' && result->d_name[2] == '\0'))) { @@ -155,13 +155,12 @@ static void stat_cache_run(gpointer data) { g_array_append_val(sce->dirlist, sced); } - if (error) { + if (errno) { sce->data.failed = TRUE; - sce->data.err = error; + sce->data.err = errno; } g_string_free(str, TRUE); - g_slice_free1(size, entry); closedir(dirp); } }