]> git.apps.os.sepia.ceph.com Git - ceph-ci.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>
Thu, 14 Aug 2025 20:08:08 +0000 (20:08 +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 6bf8013449ac6e2e49269037e61b1e91d245844e..f1091be20ff1e438e2495c5ed1e7b964cb5acf70 100644 (file)
@@ -6325,6 +6325,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)
@@ -6364,6 +6367,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;
@@ -6377,6 +6381,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;
@@ -16187,6 +16194,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 "
@@ -16223,6 +16242,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 f97bb4517b1530b0826bb497491e5a95452e1c27..c31b107c223e1c230313e21e66ff2ba036953c9c 100644 (file)
@@ -1997,6 +1997,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 a99f37322577bbb4af9709f39372ae2eac1d12bc..7bd223e01715021dd4490d54ae5f7a061df3cdba 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();