From: Christopher Hoffman Date: Fri, 1 Dec 2023 17:18:03 +0000 (+0000) Subject: client: On fscrypt enabled directories, only allow read/write to files X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=3630ed6449204aa98ac23f08dcc0063c02af22ec;p=ceph.git client: On fscrypt enabled directories, only allow read/write to files in dir when unlocked. Client should not be able to read/write the encrypted payload. Signed-off-by: Christopher Hoffman --- diff --git a/src/client/Client.cc b/src/client/Client.cc index 93416459737..4bffb1d74b5 100644 --- a/src/client/Client.cc +++ b/src/client/Client.cc @@ -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; diff --git a/src/client/Client.h b/src/client/Client.h index 438521645eb..7f7a05277bb 100644 --- a/src/client/Client.h +++ b/src/client/Client.h @@ -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 &metadata={}, diff --git a/src/client/Inode.h b/src/client/Inode.h index 7970e84f61e..b2f77bce385 100644 --- a/src/client/Inode.h +++ b/src/client/Inode.h @@ -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();