]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
client: On fscrypt enabled directories, only allow read/write to files
authorChristopher Hoffman <choffman@redhat.com>
Fri, 1 Dec 2023 17:18:03 +0000 (17:18 +0000)
committerChristopher Hoffman <choffman@redhat.com>
Wed, 5 Nov 2025 13:59:33 +0000 (13:59 +0000)
in dir when unlocked. Client should not be able to read/write the encrypted payload.

Signed-off-by: Christopher Hoffman <choffman@redhat.com>
src/client/Client.cc
src/client/Client.h
src/client/Inode.h

index 934164597376a5d2894f7800ec2eca7a0513a5ac..4bffb1d74b5611a1c143521b1c8575f3cc8f402d 100644 (file)
@@ -6362,6 +6362,9 @@ int Client::may_open(const InodeRef& in, int flags, const UserPerm& perms)
   ldout(cct, 20) << __func__ << " " << *in << "; " << perms << dendl;
   unsigned want = 0;
 
+  if (!in->is_dir() && is_inode_locked(in))
+    return -ENOKEY;
+
   if ((flags & O_ACCMODE) == O_WRONLY)
     want = CLIENT_MAY_WRITE;
   else if ((flags & O_ACCMODE) == O_RDWR)
@@ -6401,6 +6404,7 @@ out:
 int Client::may_lookup(const InodeRef& dir, const UserPerm& perms)
 {
   ldout(cct, 20) << __func__ << " " << *dir << "; " << perms << dendl;
+
   int r = _getattr_for_perm(dir, perms);
   if (r < 0)
     goto out;
@@ -6414,6 +6418,9 @@ out:
 int Client::may_create(const InodeRef& dir, const UserPerm& perms)
 {
   ldout(cct, 20) << __func__ << " " << *dir << "; " << perms << dendl;
+  if (dir->is_dir() && is_inode_locked(dir))
+    return -ENOKEY;
+
   int r = _getattr_for_perm(dir, perms);
   if (r < 0)
     goto out;
@@ -16304,6 +16311,18 @@ int Client::ll_rmdir(Inode *in, const char *name, const UserPerm& perms)
   return _rmdir(in, name, perms);
 }
 
+bool Client::is_inode_locked(Inode *to_check)
+{
+  if (to_check && to_check->fscrypt_ctx) {
+    FSCryptKeyHandlerRef kh;
+    int r = fscrypt->get_key_store().find(to_check->fscrypt_ctx->master_key_identifier, kh);
+    if (r < 0) {
+      return true;
+    }
+  }
+  return false;
+}
+
 int Client::_rename(Inode *fromdir, const char *fromname, Inode *todir, const char *toname, const UserPerm& perm, std::string alternate_name)
 {
   ldout(cct, 8) << "_rename(" << fromdir->ino << " " << fromname << " to "
@@ -16340,6 +16359,11 @@ int Client::_rename(Inode *fromdir, const char *fromname, Inode *todir, const ch
     return -EINVAL;
   }
 
+  bool source_locked = is_inode_locked(fromdir);
+  bool dest_locked = is_inode_locked(todir);
+  if (source_locked || dest_locked)
+    return -ENOKEY;
+
   if (wdr_from.diri->snapid != wdr_to.diri->snapid)
     return -EXDEV;
 
index 438521645ebb08f36e84dc5f41b12d9f5665e8b1..7f7a05277bb7706c2b0a5285eb7fc2afada2d088 100644 (file)
@@ -2044,6 +2044,7 @@ private:
 
   int _link(Inode *diri_from, const char* path_from, Inode* diri_to, const char* path_to, const UserPerm& perm, std::string alternate_name);
   int _unlink(Inode *dir, const char *name, const UserPerm& perm);
+  bool is_inode_locked(Inode *to_check);
   int _rename(Inode *olddir, const char *oname, Inode *ndir, const char *nname, const UserPerm& perm, std::string alternate_name);
   int _mkdir(const walk_dentry_result& wdr, mode_t mode, const UserPerm& perm,
             InodeRef *inp = 0, const std::map<std::string, std::string> &metadata={},
index 7970e84f61e129603fa33183c16019100b29e078..b2f77bce38570256ef338f538f92ca7e5cb8d7f9 100644 (file)
@@ -140,6 +140,7 @@ struct Inode : RefCountedObject {
   uint32_t   mode = 0;
   uid_t      uid = 0;
   gid_t      gid = 0;
+  uint32_t i_flags;
 
   // nlink
   int32_t    nlink = 0;
@@ -195,7 +196,9 @@ struct Inode : RefCountedObject {
   bool is_symlink() const { return (mode & S_IFMT) == S_IFLNK; }
   bool is_dir()     const { return (mode & S_IFMT) == S_IFDIR; }
   bool is_file()    const { return (mode & S_IFMT) == S_IFREG; }
-  bool is_encrypted() const { return (mode & S_ENCRYPTED) == S_ENCRYPTED; }
+
+  // use i_flags as 1 << 14 will overlap with other mode bits.
+  bool is_encrypted() const { return (i_flags & S_ENCRYPTED) == S_ENCRYPTED; }
 
   bool has_dir_layout() const {
     return layout != file_layout_t();