From 088e49e0e5600f54c0dfd2bc0713910fb8f7e409 Mon Sep 17 00:00:00 2001 From: Christopher Hoffman Date: Mon, 30 Oct 2023 22:31:45 +0000 Subject: [PATCH] Add multi user support on a unlock claim. Signed-off-by: Christopher Hoffman --- src/client/Client.cc | 8 +-- src/client/Client.h | 4 +- src/client/FSCrypt.cc | 110 +++++++++++++++++++++++++++++---- src/client/FSCrypt.h | 11 +++- src/client/fuse_ll.cc | 8 +-- src/include/cephfs/libcephfs.h | 2 +- src/libcephfs.cc | 4 +- 7 files changed, 120 insertions(+), 27 deletions(-) diff --git a/src/client/Client.cc b/src/client/Client.cc index ecc15cd43c4..87aa982158c 100644 --- a/src/client/Client.cc +++ b/src/client/Client.cc @@ -18154,13 +18154,13 @@ void Client::set_uuid(const std::string& uuid) } int Client::add_fscrypt_key(const char *key_data, int key_len, - ceph_fscrypt_key_identifier *kid) + ceph_fscrypt_key_identifier *kid, int user) { auto& key_store = fscrypt->get_key_store(); FSCryptKeyHandlerRef kh; - int r = key_store.create((const char *)key_data, key_len, kh); + int r = key_store.create((const char *)key_data, key_len, kh, user); if (r < 0) { ldout(cct, 0) << __func__ << "(): failed to create a new key: r=" << r << dendl; return r; @@ -18175,11 +18175,11 @@ int Client::add_fscrypt_key(const char *key_data, int key_len, return 0; } -int Client::remove_fscrypt_key(const ceph_fscrypt_key_identifier& kid) +int Client::remove_fscrypt_key(fscrypt_remove_key_arg* kid, int user) { auto& key_store = fscrypt->get_key_store(); - return key_store.invalidate(kid); + return key_store.invalidate(kid, user); } int Client::set_fscrypt_policy_v2(int fd, const struct fscrypt_policy_v2& policy) diff --git a/src/client/Client.h b/src/client/Client.h index b0fcbdfe49a..f97bb4517b1 100644 --- a/src/client/Client.h +++ b/src/client/Client.h @@ -342,8 +342,8 @@ public: } /* fscrypt */ - int add_fscrypt_key(const char *key_data, int key_len, ceph_fscrypt_key_identifier *kid); - int remove_fscrypt_key(const ceph_fscrypt_key_identifier& kid); + int add_fscrypt_key(const char *key_data, int key_len, ceph_fscrypt_key_identifier *kid, int user = 0); + int remove_fscrypt_key(fscrypt_remove_key_arg* kid, int user = 0); int set_fscrypt_policy_v2(int fd, const struct fscrypt_policy_v2& policy); int mds_command( diff --git a/src/client/FSCrypt.cc b/src/client/FSCrypt.cc index c492f60e2ad..2a8825dfb6b 100644 --- a/src/client/FSCrypt.cc +++ b/src/client/FSCrypt.cc @@ -376,7 +376,76 @@ FSCryptKeyRef& FSCryptKeyHandler::get_key() return key; } -int FSCryptKeyStore::create(const char *k, int klen, FSCryptKeyHandlerRef& key_handler) +//taken from fs/crypto/keyring.h +bool FSCryptKeyStore::valid_key_spec(const struct fscrypt_key_specifier& k) +{ + if (k.__reserved) + return false; + return master_key_spec_len(k) != 0; +} + +//taken from fs/crypto/fscrypt_private.h +int FSCryptKeyStore::master_key_spec_len(const struct fscrypt_key_specifier& spec) +{ + switch (spec.type) { + case FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR: + return FSCRYPT_KEY_DESCRIPTOR_SIZE; + case FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER: + return FSCRYPT_KEY_IDENTIFIER_SIZE; + } + return 0; +} + + + +int FSCryptKeyStore::maybe_add_user(std::list* users, int user) +{ + ldout(cct, 10) << __FILE__ << ":" << __LINE__ << " user=" << user << dendl; + + auto it = std::find(users->begin(), users->end(), user); + if (it != users->end()) { + ldout(cct, 10) << "maybe_add_user user already added!" << dendl; + return -EEXIST; + } + + ldout(cct, 10) << "maybe_add_user is not found!, adding" << dendl; + users->push_back(user); + ldout(cct, 10) << "maybe_add_user size is now=" << users->size() << dendl; + return 0; +} + +int FSCryptKeyStore::maybe_remove_user(struct fscrypt_remove_key_arg* arg, std::list* users, int user) +{ + ldout(cct, 10) << __FILE__ << ":" << __LINE__ << " user=" << user << dendl; + uint32_t status_flags = 0; + int err = 0; + bool removed = false; + if (!valid_key_spec(arg->key_spec)) { + return -EINVAL; + } + + auto it = std::find(users->begin(), users->end(), user); + if (it != users->end()) { + ldout(cct, 10) << "maybe_remove_user, user found removing!" << dendl; + removed = true; + users->erase(it); + } else { + return -ENOKEY; + } + ldout(cct, 10) << "maybe_add_user size is now=" << users->size() << dendl; + + if (users->size() != 0 && removed) { + + //set bits for removed for requested user + status_flags |= FSCRYPT_KEY_REMOVAL_STATUS_FLAG_OTHER_USERS; + err = -EBUSY; + } + + arg->removal_status_flags = status_flags; + return err; +} + +int FSCryptKeyStore::create(const char *k, int klen, FSCryptKeyHandlerRef& key_handler, int user) { auto key = std::make_shared(); @@ -384,21 +453,30 @@ int FSCryptKeyStore::create(const char *k, int klen, FSCryptKeyHandlerRef& key_h if (r < 0) { return r; } - std::unique_lock wl{lock}; const auto& id = key->get_identifier(); - auto iter = m.find(id); if (iter != m.end()) { /* found a key handler entry, check that there is a key there */ key_handler = iter->second; - if (key_handler->get_key()) { - return -EEXIST; + + auto& users = key_handler->get_users(); + r = maybe_add_user(&users, user); + + if (r == -EEXIST) { + return 0; //returns 0 regardless } key_handler->reset(++epoch, key); } else { key_handler = std::make_shared(++epoch, key); + + auto& users = key_handler->get_users(); + r = maybe_add_user(&users, user); + if (r == -EEXIST) { + return 0; //returns 0 regardless + } + m[id] = key_handler; } @@ -409,7 +487,7 @@ int FSCryptKeyStore::_find(const struct ceph_fscrypt_key_identifier& id, FSCrypt { auto iter = m.find(id); if (iter == m.end()) { - return -ENOENT; + return -ENOKEY; } kh = iter->second; @@ -424,15 +502,25 @@ int FSCryptKeyStore::find(const struct ceph_fscrypt_key_identifier& id, FSCryptK return _find(id, kh); } -int FSCryptKeyStore::invalidate(const struct ceph_fscrypt_key_identifier& id) +int FSCryptKeyStore::invalidate(struct fscrypt_remove_key_arg* arg, int user) { std::unique_lock rl{lock}; + ceph_fscrypt_key_identifier id; + int r = id.init(arg->key_spec); + if (r < 0) { + return r; + } + FSCryptKeyHandlerRef kh; - int r = _find(id, kh); - if (r == -ENOENT) { - return 0; - } else if (r < 0) { + r = _find(id, kh); + if (r < 0) { + return r; + } + + auto& users = kh->get_users(); + r = maybe_remove_user(arg, &users, user); + if (r < 0) { return r; } diff --git a/src/client/FSCrypt.h b/src/client/FSCrypt.h index 4e43d57e98d..a39ea8ea2fc 100644 --- a/src/client/FSCrypt.h +++ b/src/client/FSCrypt.h @@ -90,7 +90,6 @@ std::ostream& operator<<(std::ostream& out, const ceph_fscrypt_key_identifier& k class FSCryptKey { bufferlist key; ceph_fscrypt_key_identifier identifier; - public: int init(const char *k, int klen); @@ -299,6 +298,7 @@ class FSCryptKeyHandler { ceph::shared_mutex lock = ceph::make_shared_mutex("FSCryptKeyHandler"); int64_t epoch = -1; FSCryptKeyRef key; + std::list users; public: FSCryptKeyHandler() {} FSCryptKeyHandler(int64_t epoch, FSCryptKeyRef k) : epoch(epoch), key(k) {} @@ -306,6 +306,7 @@ public: void reset(int64_t epoch, FSCryptKeyRef k); int64_t get_epoch(); + std::list& get_users() { return users; } FSCryptKeyRef& get_key(); }; @@ -322,9 +323,13 @@ class FSCryptKeyStore { public: FSCryptKeyStore(CephContext *_cct) : cct(_cct) {} - int create(const char *k, int klen, FSCryptKeyHandlerRef& key); + bool valid_key_spec(const struct fscrypt_key_specifier& k); + int master_key_spec_len(const struct fscrypt_key_specifier& spec); + int maybe_add_user(std::list* users, int user); + int maybe_remove_user(struct fscrypt_remove_key_arg* arg, std::list* users, int user); + int create(const char *k, int klen, FSCryptKeyHandlerRef& key, int user); int find(const struct ceph_fscrypt_key_identifier& id, FSCryptKeyHandlerRef& key); - int invalidate(const struct ceph_fscrypt_key_identifier& id); + int invalidate(struct fscrypt_remove_key_arg* id, int user); }; struct FSCryptKeyValidator { diff --git a/src/client/fuse_ll.cc b/src/client/fuse_ll.cc index 020b42ba8f6..1ea0b488fef 100644 --- a/src/client/fuse_ll.cc +++ b/src/client/fuse_ll.cc @@ -1010,7 +1010,7 @@ static void fuse_ll_ioctl(fuse_req_t req, fuse_ino_t ino, break; } - int r = cfuse->client->add_fscrypt_key((const char *)arg->raw, arg->raw_size, nullptr); + int r = cfuse->client->add_fscrypt_key((const char *)arg->raw, arg->raw_size, nullptr, ctx->uid); if (r < 0) { generic_dout(0) << __FILE__ << ":" << __LINE__ << ": failed to create a new key: r=" << r << dendl; fuse_reply_err(req, -r); @@ -1044,13 +1044,12 @@ static void fuse_ll_ioctl(fuse_req_t req, fuse_ino_t ino, } /* FIXME: handle busy cases */ - r = cfuse->client->remove_fscrypt_key(kid); + r = cfuse->client->remove_fscrypt_key(arg, ctx->uid); if (r < 0) { fuse_reply_err(req, -r); break; } - arg->removal_status_flags = 0; /* FIXME */ fuse_reply_ioctl(req, 0, arg, sizeof(*arg)); break; } @@ -1135,7 +1134,8 @@ static void fuse_ll_ioctl(fuse_req_t req, fuse_ino_t ino, /* TODO: return correct info */ arg->status = (found ? FSCRYPT_KEY_STATUS_PRESENT : FSCRYPT_KEY_STATUS_ABSENT); - arg->status_flags = (found ? 0x1 : 0); /* FIXME */ + arg->status_flags = 0;//(found ? 0x1 : 0); /* FIXME */ + //arg->status_flags = (found ? 0x1 : 0); /* FIXME */ arg->user_count = !!found; /* FIXME */ fuse_reply_ioctl(req, 0, arg, sizeof(*arg)); diff --git a/src/include/cephfs/libcephfs.h b/src/include/cephfs/libcephfs.h index b0b90512c3d..c6471c64b86 100644 --- a/src/include/cephfs/libcephfs.h +++ b/src/include/cephfs/libcephfs.h @@ -2020,7 +2020,7 @@ int ceph_add_fscrypt_key(struct ceph_mount_info *cmount, * @returns zero on success, other returns a negative error code. */ int ceph_remove_fscrypt_key(struct ceph_mount_info *cmount, - const struct ceph_fscrypt_key_identifier *kid); + struct fscrypt_remove_key_arg *kid); /** * Set encryption policy on a directory. diff --git a/src/libcephfs.cc b/src/libcephfs.cc index 5e7bf52dbaf..d13dce00e83 100644 --- a/src/libcephfs.cc +++ b/src/libcephfs.cc @@ -2505,12 +2505,12 @@ extern "C" int ceph_add_fscrypt_key(struct ceph_mount_info *cmount, } extern "C" int ceph_remove_fscrypt_key(struct ceph_mount_info *cmount, - const struct ceph_fscrypt_key_identifier *kid) + struct fscrypt_remove_key_arg *kid) { if (!cmount->is_mounted()) return -CEPHFS_ENOTCONN; - return cmount->get_client()->remove_fscrypt_key(*kid); + return cmount->get_client()->remove_fscrypt_key(kid); } extern "C" int ceph_set_fscrypt_policy_v2(struct ceph_mount_info *cmount, -- 2.39.5