There is a small race condition between the previous stat call and openat/fdopendir (which cannot be avoided): if the directory got replaced by another file type, then openat would succeed but the subsequent fdopendir would fail with ENOTDIR. Detect this earlier by passing the O_DIRECTORY flag. Furthermore, the opened file descriptor was leaked in that case (bug introduced in FINDUTILS_4_3_2-1-80-gb46b0d89 in 2007). Later on, after a readdir error, also the directory stream was leaked (bug introduced by myself in commit 7a6e548690b1).
* find/pred.c (pred_empty): Add more flags to the openat call, especially O_DIRECTORY; inspired by gnulib's opendirat module. Close the file descriptor when fdopendir failed. Close the directory stream when readdir failed. --- find/pred.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/find/pred.c b/find/pred.c index e34a41dc..688103d6 100644 --- a/find/pred.c +++ b/find/pred.c @@ -363,9 +363,9 @@ pred_empty (const char *pathname, struct stat *stat_buf, struct predicate *pred_ errno = 0; if ((fd = openat (state.cwd_dir_fd, state.rel_pathname, O_RDONLY #if defined O_LARGEFILE - |O_LARGEFILE + | O_LARGEFILE #endif - )) < 0) + | O_CLOEXEC | O_DIRECTORY | O_NOCTTY | O_NONBLOCK)) < 0) { error (0, errno, "%s", safely_quote_err_filename (0, pathname)); state.exit_status = 1; @@ -376,6 +376,7 @@ pred_empty (const char *pathname, struct stat *stat_buf, struct predicate *pred_ { error (0, errno, "%s", safely_quote_err_filename (0, pathname)); state.exit_status = 1; + close (fd); return false; } /* errno is not touched in the loop body, so initializing it here @@ -396,6 +397,7 @@ pred_empty (const char *pathname, struct stat *stat_buf, struct predicate *pred_ /* Handle errors from readdir(3). */ error (0, errno, "%s", safely_quote_err_filename (0, pathname)); state.exit_status = 1; + CLOSEDIR (d); return false; } if (CLOSEDIR (d)) -- 2.20.1