]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
client: Fix symlink open with O_PATH and O_NOFOLLOW
authorAnoop C S <anoopcs@cryptolab.net>
Thu, 29 Aug 2024 06:23:44 +0000 (11:53 +0530)
committerAnoop C S <anoopcs@cryptolab.net>
Tue, 15 Oct 2024 10:51:15 +0000 (16:21 +0530)
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 <anoopcs@cryptolab.net>
src/client/Client.cc
src/test/libcephfs/test.cc

index 6577dd575f1fde36329c08f89a0c96ad3ce398ea..9c6785fe65e5afc92966d655d455c546e7174c57 100644 (file)
@@ -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:
index f2c87168633bb495dc561bfb8c8f2621a83b05df..b51689ab2637e67edf65617e8ef53774ceb13f5f 100644 (file)
@@ -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);