From 52139fd69034446695af60c8064a38e5e795227c Mon Sep 17 00:00:00 2001 From: =?utf8?q?P=C3=A1draig=20Brady?= Date: Sun, 10 Apr 2022 16:59:40 +0100 Subject: [PATCH] cp,mv,install: avoid EACCES with non directory destination * src/system.h (target_directory_operand): Also check with stat() on systems with O_SEARCH, to avoid open("file", O_SEARCH|O_DIRECTORY) returning EACCES rather than ENOTDIR, which was seen on Solaris 11.4 when operating on non dirs without execute bit set. * NEWS: Remove related bug entry, as that issue was only introduced after coreutils v9.0 was released. Reported by Bruno Haible. --- NEWS | 5 ----- src/system.h | 18 +++++++++++------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/NEWS b/NEWS index 69feffcbc1..85fd5be122 100644 --- a/NEWS +++ b/NEWS @@ -21,11 +21,6 @@ GNU coreutils NEWS -*- outline -*- and B is in some other file system. [bug introduced in coreutils-9.0] - cp, mv, and install, on older systems like Solaris 10 without O_DIRECTORY - support, avoid opening non directory destination operands. Opening such - files can have side effects, like hanging with a fifo for example. - [bug introduced in coreutils-9.0] - On macOS, fmt no longer corrupts multi-byte characters by misdetecting their component bytes as spaces. [This bug was present in "the beginning".] diff --git a/src/system.h b/src/system.h index c24cb4dc39..768c3a1f2a 100644 --- a/src/system.h +++ b/src/system.h @@ -137,19 +137,23 @@ target_directory_operand (char const *file) return AT_FDCWD; int fd = -1; - bool is_a_dir = false; + int maybe_dir = -1; struct stat st; - /* On old systems like Solaris 10, check with stat first - lest we try to open a fifo for example and hang. */ - if (!O_DIRECTORY && stat (file, &st) == 0) + /* On old systems without O_DIRECTORY, like Solaris 10, + check with stat first lest we try to open a fifo for example and hang. + Also check on systems with O_PATHSEARCH == O_SEARCH, like Solaris 11, + where open() was seen to return EACCES for non executable non dirs. + */ + if ((!O_DIRECTORY || (O_PATHSEARCH == O_SEARCH)) + && stat (file, &st) == 0) { - is_a_dir = !!S_ISDIR (st.st_mode); - if (! is_a_dir) + maybe_dir = S_ISDIR (st.st_mode); + if (! maybe_dir) errno = ENOTDIR; } - if (O_DIRECTORY || is_a_dir) + if (maybe_dir) fd = open (file, O_PATHSEARCH | O_DIRECTORY); if (!O_DIRECTORY && 0 <= fd) -- 2.47.2