From: Anoop C S Date: Thu, 29 Aug 2024 06:23:44 +0000 (+0530) Subject: client: Fix symlink open with O_PATH and O_NOFOLLOW X-Git-Tag: testing/wip-vshankar-testing-20241016.135728-debug~5^2~1 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=8443821073b23946a32009106c45581db0d51e8f;p=ceph-ci.git client: Fix symlink open with O_PATH and O_NOFOLLOW man open(2)[1] says the following for O_PATH: . . . If pathname is a symbolic link and the O_NOFOLLOW flag is also specified, then the call returns a file descriptor referring to the symbolic link. This file descriptor can be used as the dirfd argument in calls to fchownat(2), fstatat(2), linkat(2), and readlinkat(2) with an empty pathname to have the calls operate on the symbolic link. . . . symlink check within may_open() failed to consider the O_PATH flag resulting in a ELOOP error to the client. In order to return a valid file descriptor we introduce a check for the presence of O_PATH in the client provided flags. Fixes: https://tracker.ceph.com/issues/67833 [1] https://www.man7.org/linux/man-pages/man2/open.2.html Signed-off-by: Anoop C S --- diff --git a/src/client/Client.cc b/src/client/Client.cc index 6577dd575f1..9c6785fe65e 100644 --- a/src/client/Client.cc +++ b/src/client/Client.cc @@ -6125,6 +6125,10 @@ int Client::may_open(Inode *in, int flags, const UserPerm& perms) int r = 0; switch (in->mode & S_IFMT) { case S_IFLNK: +#if defined(__linux__) && defined(O_PATH) + if (flags & O_PATH) + break; +#endif r = -CEPHFS_ELOOP; goto out; case S_IFDIR: diff --git a/src/test/libcephfs/test.cc b/src/test/libcephfs/test.cc index f2c87168633..b51689ab263 100644 --- a/src/test/libcephfs/test.cc +++ b/src/test/libcephfs/test.cc @@ -976,6 +976,13 @@ TEST(LibCephFS, Symlinks) { fd = ceph_open(cmount, test_symlink, O_NOFOLLOW, 0); ASSERT_EQ(fd, -CEPHFS_ELOOP); +#if defined(__linux__) && defined(O_PATH) + // test the O_NOFOLLOW with O_PATH case + fd = ceph_open(cmount, test_symlink, O_PATH|O_NOFOLLOW, 0); + ASSERT_GT(fd, 0); + ceph_close(cmount, fd); +#endif /* __linux */ + // stat the original file struct ceph_statx stx_orig; ASSERT_EQ(ceph_statx(cmount, test_file, &stx_orig, CEPH_STATX_ALL_STATS, 0), 0);