From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2155) id 74072385840E; Tue, 18 Apr 2023 11:54:34 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 74072385840E DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1681818874; bh=Itv3k+bhjNKFVHLaPMH3lsOpckxNvsz1Lou3+1BMaII=; h=From:To:Subject:Date:From; b=enrI9cJnYOiJb25+ebxtRBofVeOJ3R24lzxxV3x+UcIvlUtYQeJ1ML3Zy5Z2IvrnU 4oc5E44tnTnByF0FkWtT99Arf7Hak7tWiwMcBUdwKaFMateqgYrhnHiJjU+z8YptDY Fp056E6y1QWrvS/UIvaHDppjY6fL1Ty/z6kgCOUk= Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable From: Corinna Vinschen To: cygwin-cvs@sourceware.org Subject: [newlib-cygwin/cygwin-3_4-branch] Cygwin: fix errno values set by readlinkat X-Act-Checkin: newlib-cygwin X-Git-Author: Corinna Vinschen X-Git-Refname: refs/heads/cygwin-3_4-branch X-Git-Oldrev: f87469dd5bcae461bd9fe4da4ee4958ecf353749 X-Git-Newrev: 4b8222983f914a7950987802e73fc069dffc3058 Message-Id: <20230418115434.74072385840E@sourceware.org> Date: Tue, 18 Apr 2023 11:54:34 +0000 (GMT) List-Id: https://sourceware.org/git/gitweb.cgi?p=3Dnewlib-cygwin.git;h=3D4b8222983f9= 14a7950987802e73fc069dffc3058 commit 4b8222983f914a7950987802e73fc069dffc3058 Author: Corinna Vinschen AuthorDate: Tue Apr 18 13:52:50 2023 +0200 Commit: Corinna Vinschen CommitDate: Tue Apr 18 13:53:09 2023 +0200 Cygwin: fix errno values set by readlinkat =20 readlinkat(fd, "", ...) is supposed to return ENOENT per POSIX, but Cygwin returns EBADF. =20 At the same time, we have to maintain the special feature of glibc that readlinkat(fd, "", ...) operates on fd, if fd is pointing at a symlink opened with O_PATH|O_NOFOLLOW. =20 And, while fixing that, readlinkat(fd, path, ...) *still* has to set er= rno to EBADF, if fd is an invalid descriptor *and* path is a relative path. =20 This required to change the evaluation order in the helper function gen_full_path_at. =20 Last but not least, in case of the aforementioned glibc-like special handling for symlink descriptors, we have to make sure that errors from gen_full_path_at are not spilled into that special handling. =20 Fixes: 6cc05784e16a ("Cygwin: readlinkat: allow pathname to be empty") Reported-by: Bruno Haible Signed-off-by: Corinna Vinschen Diff: --- winsup/cygwin/release/3.4.7 | 3 +++ winsup/cygwin/syscalls.cc | 42 ++++++++++++++++++++++-------------------- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/winsup/cygwin/release/3.4.7 b/winsup/cygwin/release/3.4.7 index 8ecfbc30a24b..7bc7d4a1ccdb 100644 --- a/winsup/cygwin/release/3.4.7 +++ b/winsup/cygwin/release/3.4.7 @@ -18,3 +18,6 @@ Bug Fixes =20 - Fix return value of ilogbl(NaN). Addresses: https://cygwin.com/pipermail/cygwin/2023-April/253511.html + +- Fix error handling in readlinkat. + Addresses: https://cygwin.com/pipermail/cygwin/2023-April/253510.html diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc index fff8af009fd1..a4e4af626db1 100644 --- a/winsup/cygwin/syscalls.cc +++ b/winsup/cygwin/syscalls.cc @@ -4415,19 +4415,6 @@ gen_full_path_at (char *path_ret, int dirfd, const c= har *pathname, set_errno (EFAULT); return -1; } - if (pathname) - { - if (!*pathname) - { - set_errno (ENOENT); - return -1; - } - if (strlen (pathname) >=3D PATH_MAX) - { - set_errno (ENAMETOOLONG); - return -1; - } - } if (pathname && isabspath_strict (pathname)) stpcpy (path_ret, pathname); else @@ -4459,6 +4446,16 @@ gen_full_path_at (char *path_ret, int dirfd, const c= har *pathname, } if (pathname) { + if (!*pathname) + { + set_errno (ENOENT); + return -1; + } + if (strlen (pathname) >=3D PATH_MAX) + { + set_errno (ENAMETOOLONG); + return -1; + } if (p[-1] !=3D '/') *p++ =3D '/'; stpcpy (p, pathname); @@ -4803,21 +4800,26 @@ readlinkat (int dirfd, const char *__restrict pathn= ame, char *__restrict buf, __try { char *path =3D tp.c_get (); + int save_errno =3D errno; int res =3D gen_full_path_at (path, dirfd, pathname); if (res) { - if (errno !=3D ENOENT) + if (errno !=3D ENOENT && errno !=3D ENOTDIR) __leave; /* pathname is an empty string. This is OK if dirfd refers to a symlink that was opened with O_PATH | O_NOFOLLOW. - In this case, readlinkat operates on the symlink. */ + In this case, readlinkat operates on the symlink. + Don't propagate errors from gen_full_path_at after this point. */ + errno =3D save_errno; cygheap_fdget cfd (dirfd); - if (cfd < 0) - __leave; - if (!(cfd->issymlink () + if (cfd < 0 + || (!(cfd->issymlink () && cfd->get_flags () & O_PATH - && cfd->get_flags () & O_NOFOLLOW)) - __leave; + && cfd->get_flags () & O_NOFOLLOW))) + { + set_errno (ENOENT); + __leave; + } strcpy (path, cfd->get_name ()); } return readlink (path, buf, bufsize);