]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
client: Gracefully handle empty pathname for chownat()
authorAnoop C S <anoopcs@cryptolab.net>
Fri, 20 Sep 2024 08:49:01 +0000 (14:19 +0530)
committerAnoop C S <anoopcs@cryptolab.net>
Sun, 22 Dec 2024 04:28:17 +0000 (09:58 +0530)
man fchownat(2)[1] says the following:
. . .
AT_EMPTY_PATH (since Linux 2.6.39)
    If pathname is an empty string, operate on the file referred to by
    dirfd (which may have been obtained using the open(2) O_PATH flag).
    In this case, dirfd can refer to any type of file, not just a
    directory. If dirfd is AT_FDCWD, the call operates on the current
    working directory.
. . .

Look out for an empty pathname and use the relative fd's inode in the
presence of AT_EMPTY_PATH flag before calling internal _setattr().

Fixes: https://tracker.ceph.com/issues/68189
Review with: git show -w

[1] https://www.man7.org/linux/man-pages/man2/fchownat.2.html

Signed-off-by: Anoop C S <anoopcs@cryptolab.net>
(cherry picked from commit 829f38899226fcd1f603ba446b018f53c5b0921d)

src/client/Client.cc
src/include/cephfs/libcephfs.h
src/test/libcephfs/test.cc

index a84e69f38f2fdcca7691a0c805b6d27a0398a924..f964a6fadf20932b93ca508dd94b577951e3cccc 100644 (file)
@@ -8834,7 +8834,6 @@ int Client::chownat(int dirfd, const char *relpath, uid_t new_uid, gid_t new_gid
   tout(cct) << new_gid << std::endl;
   tout(cct) << flags << std::endl;
 
-  filepath path(relpath);
   InodeRef in;
   InodeRef dirinode;
 
@@ -8844,10 +8843,24 @@ int Client::chownat(int dirfd, const char *relpath, uid_t new_uid, gid_t new_gid
     return r;
   }
 
-  r = path_walk(path, &in, perms, !(flags & AT_SYMLINK_NOFOLLOW), 0, dirinode);
-  if (r < 0) {
-    return r;
+  if (!strcmp(relpath, "")) {
+#if defined(__linux__) && defined(AT_EMPTY_PATH)
+    if (flags & AT_EMPTY_PATH) {
+      in = dirinode;
+      goto out;
+    }
+#endif
+    return -CEPHFS_ENOENT;
+  } else {
+    filepath path(relpath);
+    r = path_walk(path, &in, perms, !(flags & AT_SYMLINK_NOFOLLOW), 0, dirinode);
+    if (r < 0) {
+      return r;
+    }
   }
+
+out:
+
   struct stat attr;
   attr.st_uid = new_uid;
   attr.st_gid = new_gid;
index dc62698fa482a3f9346c9104012a03137af8925b..96130c3063b12bb574262ced592ee128d0c0f251 100644 (file)
@@ -1091,7 +1091,7 @@ int ceph_lchown(struct ceph_mount_info *cmount, const char *path, int uid, int g
  * @param relpath the relpath of the file/directory to change the ownership of.
  * @param uid the user id to set on the file/directory.
  * @param gid the group id to set on the file/directory.
- * @param flags bitfield that can be used to set AT_* modifier flags (AT_SYMLINK_NOFOLLOW)
+ * @param flags bitfield that can be used to set AT_* modifier flags (AT_SYMLINK_NOFOLLOW and AT_EMPTY_PATH)
  * @returns 0 on success or negative error code on failure.
  */
 int ceph_chownat(struct ceph_mount_info *cmount, int dirfd, const char *relpath,
index 57c5eefa6d3283fea50c51dc18cd23c91b66b298..449774ac708eef35622ec3bb96e7c171e9e86964 100644 (file)
@@ -3246,6 +3246,13 @@ TEST(LibCephFS, Chownat) {
   // change ownership to nobody -- we assume nobody exists and id is always 65534
   ASSERT_EQ(ceph_conf_set(cmount, "client_permissions", "0"), 0);
   ASSERT_EQ(ceph_chownat(cmount, fd, rel_file_path, 65534, 65534, 0), 0);
+  // change relative fd ownership with AT_EMPTY_PATH
+#if defined(__linux__) && defined(AT_EMPTY_PATH)
+  int file_fd = ceph_openat(cmount, fd, rel_file_path, O_RDONLY, 0);
+  ASSERT_LE(0, file_fd);
+  ASSERT_EQ(ceph_chownat(cmount, file_fd, "", 65534, 65534, AT_EMPTY_PATH), 0);
+  ceph_close(cmount, file_fd);
+#endif
   ASSERT_EQ(ceph_conf_set(cmount, "client_permissions", "1"), 0);
   ceph_close(cmount, fd);