From 3fb179ec6164ae583bec775e53bf09b925b949fb Mon Sep 17 00:00:00 2001 From: Xavi Hernandez Date: Thu, 18 Sep 2025 12:39:30 +0200 Subject: [PATCH] libcephfs_proxy: implement support for fscrypt Signed-off-by: Xavi Hernandez --- src/libcephfs_proxy/libcephfs_proxy.c | 90 ++++++++++++ src/libcephfs_proxy/libcephfsd.c | 195 ++++++++++++++++++++++++++ src/libcephfs_proxy/proxy_requests.h | 97 +++++++++++++ 3 files changed, 382 insertions(+) diff --git a/src/libcephfs_proxy/libcephfs_proxy.c b/src/libcephfs_proxy/libcephfs_proxy.c index d4f4caa31108..e6996232436d 100644 --- a/src/libcephfs_proxy/libcephfs_proxy.c +++ b/src/libcephfs_proxy/libcephfs_proxy.c @@ -1,6 +1,8 @@ #include +#include + #include "include/cephfs/libcephfs.h" #include "proxy_log.h" @@ -1087,3 +1089,91 @@ __public int64_t ceph_ll_nonblocking_readv_writev( return ans.res; } + +__public int32_t ceph_add_fscrypt_key(struct ceph_mount_info *cmount, + const char *key_data, int32_t key_len, + char *kid, int32_t user) +{ + CEPH_REQ(ceph_add_fscrypt_key, req, 1, ans, 1); + + req.user = user; + req.kid = FSCRYPT_KEY_IDENTIFIER_SIZE; + + CEPH_BUFF_ADD(req, key_data, key_len); + + CEPH_BUFF_ADD(ans, kid, FSCRYPT_KEY_IDENTIFIER_SIZE); + + return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_ADD_FSCRYPT_KEY, req, ans); +} + +__public int32_t ceph_remove_fscrypt_key(struct ceph_mount_info *cmount, + struct fscrypt_remove_key_arg *arg, + int32_t user) +{ + CEPH_REQ(ceph_remove_fscrypt_key, req, 1, ans, 1); + + req.user = user; + req.arg = sizeof(struct fscrypt_remove_key_arg); + + CEPH_BUFF_ADD(req, arg, sizeof(struct fscrypt_remove_key_arg)); + + CEPH_BUFF_ADD(ans, arg, sizeof(struct fscrypt_remove_key_arg)); + + return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_REMOVE_FSCRYPT_KEY, req, ans); +} + +__public int32_t ceph_get_fscrypt_key_status( + struct ceph_mount_info *cmount, struct fscrypt_get_key_status_arg *arg) +{ + CEPH_REQ(ceph_get_fscrypt_key_status, req, 1, ans, 1); + + req.arg = sizeof(struct fscrypt_get_key_status_arg); + + CEPH_BUFF_ADD(req, arg, sizeof(struct fscrypt_get_key_status_arg)); + + CEPH_BUFF_ADD(ans, arg, sizeof(struct fscrypt_get_key_status_arg)); + + return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_REMOVE_FSCRYPT_KEY, req, ans); +} + +__public int32_t ceph_ll_set_fscrypt_policy_v2( + struct ceph_mount_info *cmount, Inode *in, + const struct fscrypt_policy_v2 *policy) +{ + CEPH_REQ(ceph_ll_set_fscrypt_policy_v2, req, 1, ans, 0); + + req.inode = ptr_value(in); + req.policy = sizeof(struct fscrypt_policy_v2); + + CEPH_BUFF_ADD(req, policy, sizeof(struct fscrypt_policy_v2)); + + return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_SET_FSCRYPT_POLICY_V2, req, + ans); +} + +__public int32_t ceph_ll_get_fscrypt_policy_v2(struct ceph_mount_info *cmount, + Inode *in, + struct fscrypt_policy_v2 *policy) +{ + CEPH_REQ(ceph_ll_get_fscrypt_policy_v2, req, 0, ans, 1); + + req.inode = ptr_value(in); + req.policy = sizeof(struct fscrypt_policy_v2); + + CEPH_BUFF_ADD(ans, policy, sizeof(struct fscrypt_policy_v2)); + + return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_GET_FSCRYPT_POLICY_V2, req, + ans); +} + +__public int32_t ceph_ll_is_encrypted(struct ceph_mount_info *cmount, + Inode *in, char *enctag) +{ + CEPH_REQ(ceph_ll_is_encrypted, req, 1, ans, 0); + + req.inode = ptr_value(in); + + CEPH_STR_ADD(req, tag, enctag); + + return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_IS_ENCRYPTED, req, ans); +} diff --git a/src/libcephfs_proxy/libcephfsd.c b/src/libcephfs_proxy/libcephfsd.c index 64a3f888cd86..b920856cb885 100644 --- a/src/libcephfs_proxy/libcephfsd.c +++ b/src/libcephfs_proxy/libcephfsd.c @@ -8,6 +8,8 @@ #include #include +#include + #include "include/cephfs/libcephfs.h" #include "proxy_manager.h" @@ -1821,6 +1823,190 @@ done: return CEPH_COMPLETE(client, err, ans); } +static int32_t libcephfsd_add_fscrypt_key(proxy_client_t *client, + proxy_req_t *req, const void *data, + int32_t data_size) +{ + CEPH_DATA(ceph_add_fscrypt_key, ans, 1); + char kid[FSCRYPT_KEY_IDENTIFIER_SIZE]; + proxy_mount_t *mount; + uint32_t user; + int32_t err; + + err = ptr_check(&client->random, req->add_fscrypt_key.cmount, + (void **)&mount); + if ((err >= 0) && + (req->add_fscrypt_key.kid != sizeof(kid))) { + err = proxy_log(LOG_ERR, EINVAL, "Invalid size of key id"); + } + if (err >= 0) { + user = req->add_fscrypt_key.user; + + CEPH_BUFF_ADD(ans, kid, sizeof(kid)); + + err = ceph_add_fscrypt_key(proxy_cmount(mount), data, + req->add_fscrypt_key.key, kid, + user); + TRACE("add_fscrypt_key(%p, %u) -> %d", mount, user, err); + } + + return CEPH_COMPLETE(client, err, ans); +} + +static int32_t libcephfsd_remove_fscrypt_key(proxy_client_t *client, + proxy_req_t *req, const void *data, + int32_t data_size) +{ + CEPH_DATA(ceph_remove_fscrypt_key, ans, 1); + proxy_mount_t *mount; + uint32_t user; + int32_t err; + + err = ptr_check(&client->random, req->remove_fscrypt_key.cmount, + (void **)&mount); + if ((err >= 0) && + (req->remove_fscrypt_key.arg != + sizeof(struct fscrypt_remove_key_arg))) { + err = proxy_log(LOG_ERR, EINVAL, + "Invalid size of key remove arg"); + } + if (err >= 0) { + user = req->remove_fscrypt_key.user; + + CEPH_BUFF_ADD(ans, data, sizeof(struct fscrypt_remove_key_arg)); + + err = ceph_remove_fscrypt_key( + proxy_cmount(mount), + (struct fscrypt_remove_key_arg *)data, user); + TRACE("remove_fscrypt_key(%p, %u) -> %d", mount, user, err); + } + + return CEPH_COMPLETE(client, err, ans); +} + +static int32_t libcephfsd_get_fscrypt_key_status(proxy_client_t *client, + proxy_req_t *req, + const void *data, + int32_t data_size) +{ + CEPH_DATA(ceph_get_fscrypt_key_status, ans, 1); + proxy_mount_t *mount; + int32_t err; + + err = ptr_check(&client->random, req->get_fscrypt_key_status.cmount, + (void **)&mount); + if ((err >= 0) && + (req->get_fscrypt_key_status.arg != + sizeof(struct fscrypt_get_key_status_arg))) { + err = proxy_log(LOG_ERR, EINVAL, + "Invalid size of key status arg"); + } + if (err >= 0) { + CEPH_BUFF_ADD(ans, data, + sizeof(struct fscrypt_get_key_status_arg)); + + err = ceph_get_fscrypt_key_status( + proxy_cmount(mount), + (struct fscrypt_get_key_status_arg *)data); + TRACE("get_fscrypt_key_status(%p) -> %d", mount, err); + } + + return CEPH_COMPLETE(client, err, ans); +} + +static int32_t libcephfsd_ll_set_fscrypt_policy_v2(proxy_client_t *client, + proxy_req_t *req, + const void *data, + int32_t data_size) +{ + CEPH_DATA(ceph_ll_set_fscrypt_policy_v2, ans, 0); + proxy_mount_t *mount; + Inode *inode; + int32_t err; + + err = ptr_check(&client->random, req->ll_set_fscrypt_policy_v2.cmount, + (void **)&mount); + if (err >= 0) { + err = ptr_check(&client->random, + req->ll_set_fscrypt_policy_v2.inode, + (void **)&inode); + } + if ((err >= 0) && + (req->ll_set_fscrypt_policy_v2.policy != + sizeof(struct fscrypt_policy_v2))) { + err = proxy_log(LOG_ERR, EINVAL, + "Invalid size of fscrypt_policy_v2"); + } + if (err >= 0) { + err = ceph_ll_set_fscrypt_policy_v2(proxy_cmount(mount), inode, + data); + TRACE("ll_set_fscrypt_policy_v2(%p) -> %d", mount, err); + } + + return CEPH_COMPLETE(client, err, ans); +} + +static int32_t libcephfsd_ll_get_fscrypt_policy_v2(proxy_client_t *client, + proxy_req_t *req, + const void *data, + int32_t data_size) +{ + CEPH_DATA(ceph_ll_get_fscrypt_policy_v2, ans, 1); + struct fscrypt_policy_v2 policy; + proxy_mount_t *mount; + Inode *inode; + int32_t err; + + err = ptr_check(&client->random, req->ll_get_fscrypt_policy_v2.cmount, + (void **)&mount); + if (err >= 0) { + err = ptr_check(&client->random, + req->ll_get_fscrypt_policy_v2.inode, + (void **)&inode); + } + if ((err >= 0) && + (req->ll_get_fscrypt_policy_v2.policy != + sizeof(struct fscrypt_policy_v2))) { + err = proxy_log(LOG_ERR, EINVAL, + "Invalid size of fscrypt_policy_v2"); + } + if (err >= 0) { + CEPH_BUFF_ADD(ans, &policy, sizeof(policy)); + + err = ceph_ll_get_fscrypt_policy_v2(proxy_cmount(mount), inode, + &policy); + TRACE("ll_get_fscrypt_policy_v2(%p) -> %d", mount, err); + } + + return CEPH_COMPLETE(client, err, ans); +} + +static int32_t libcephfsd_ll_is_encrypted(proxy_client_t *client, + proxy_req_t *req, const void *data, + int32_t data_size) +{ + CEPH_DATA(ceph_ll_is_encrypted, ans, 0); + proxy_mount_t *mount; + Inode *inode; + char *tag; + int32_t err; + + err = ptr_check(&client->random, req->ll_is_encrypted.cmount, + (void **)&mount); + if (err >= 0) { + err = ptr_check(&client->random, req->ll_is_encrypted.inode, + (void **)&inode); + } + if (err >= 0) { + tag = (char *)CEPH_STR_GET(req->ll_is_encrypted, tag, data); + + err = ceph_ll_is_encrypted(proxy_cmount(mount), inode, tag); + TRACE("ll_is_encrypted(%p) -> %d", mount, err); + } + + return CEPH_COMPLETE(client, err, ans); +} + static proxy_handler_t libcephfsd_handlers[LIBCEPHFSD_OP_TOTAL_OPS] = { [LIBCEPHFSD_OP_VERSION] = libcephfsd_version, [LIBCEPHFSD_OP_USERPERM_NEW] = libcephfsd_userperm_new, @@ -1870,6 +2056,15 @@ static proxy_handler_t libcephfsd_handlers[LIBCEPHFSD_OP_TOTAL_OPS] = { [LIBCEPHFSD_OP_LL_RELEASEDIR] = libcephfsd_ll_releasedir, [LIBCEPHFSD_OP_MOUNT_PERMS] = libcephfsd_mount_perms, [LIBCEPHFSD_OP_LL_NONBLOCKING_RW] = libcephfsd_ll_nonblocking_rw, + [LIBCEPHFSD_OP_ADD_FSCRYPT_KEY] = libcephfsd_add_fscrypt_key, + [LIBCEPHFSD_OP_REMOVE_FSCRYPT_KEY] = libcephfsd_remove_fscrypt_key, + [LIBCEPHFSD_OP_GET_FSCRYPT_KEY_STATUS] = + libcephfsd_get_fscrypt_key_status, + [LIBCEPHFSD_OP_LL_SET_FSCRYPT_POLICY_V2] = + libcephfsd_ll_set_fscrypt_policy_v2, + [LIBCEPHFSD_OP_LL_GET_FSCRYPT_POLICY_V2] = + libcephfsd_ll_get_fscrypt_policy_v2, + [LIBCEPHFSD_OP_LL_IS_ENCRYPTED] = libcephfsd_ll_is_encrypted, }; static void serve_binary(proxy_client_t *client) diff --git a/src/libcephfs_proxy/proxy_requests.h b/src/libcephfs_proxy/proxy_requests.h index 552e7dd816bf..f86cf9e5e9b1 100644 --- a/src/libcephfs_proxy/proxy_requests.h +++ b/src/libcephfs_proxy/proxy_requests.h @@ -126,6 +126,12 @@ enum { LIBCEPHFSD_OP_LL_RELEASEDIR, LIBCEPHFSD_OP_MOUNT_PERMS, LIBCEPHFSD_OP_LL_NONBLOCKING_RW, + LIBCEPHFSD_OP_ADD_FSCRYPT_KEY, + LIBCEPHFSD_OP_REMOVE_FSCRYPT_KEY, + LIBCEPHFSD_OP_GET_FSCRYPT_KEY_STATUS, + LIBCEPHFSD_OP_LL_SET_FSCRYPT_POLICY_V2, + LIBCEPHFSD_OP_LL_GET_FSCRYPT_POLICY_V2, + LIBCEPHFSD_OP_LL_IS_ENCRYPTED, /* Add more operations above this comment. */ @@ -989,6 +995,91 @@ PROTO_CALL(ceph_ll_nonblocking_readv_writev, ) ); +PROTO_CALL(ceph_add_fscrypt_key, + PROTO_REQ( + PROTO_VER(v0, + uint64_t cmount; + uint32_t user; + uint32_t kid; + uint16_t key; + ) + ), + PROTO_ANS( + PROTO_VER(v0, + ) + ) +); + +PROTO_CALL(ceph_remove_fscrypt_key, + PROTO_REQ( + PROTO_VER(v0, + uint64_t cmount; + uint32_t user; + uint32_t arg; + ) + ), + PROTO_ANS( + PROTO_VER(v0, + ) + ) +); + +PROTO_CALL(ceph_get_fscrypt_key_status, + PROTO_REQ( + PROTO_VER(v0, + uint64_t cmount; + uint32_t arg; + ) + ), + PROTO_ANS( + PROTO_VER(v0, + ) + ) +); + +PROTO_CALL(ceph_ll_set_fscrypt_policy_v2, + PROTO_REQ( + PROTO_VER(v0, + uint64_t cmount; + uint64_t inode; + uint32_t policy; + ) + ), + PROTO_ANS( + PROTO_VER(v0, + ) + ) +); + +PROTO_CALL(ceph_ll_get_fscrypt_policy_v2, + PROTO_REQ( + PROTO_VER(v0, + uint64_t cmount; + uint64_t inode; + uint32_t policy; + ) + ), + PROTO_ANS( + PROTO_VER(v0, + ) + ) +); + +PROTO_CALL(ceph_ll_is_encrypted, + PROTO_REQ( + PROTO_VER(v0, + uint64_t cmount; + uint64_t inode; + uint16_t tag; + ) + ), + PROTO_ANS( + PROTO_VER(v0, + uint32_t policy; + ) + ) +); + typedef union _proxy_req { proxy_link_req_t header; @@ -1040,6 +1131,12 @@ typedef union _proxy_req { proxy_ceph_ll_releasedir_req_t ll_releasedir; proxy_ceph_mount_perms_req_t mount_perms; proxy_ceph_ll_nonblocking_readv_writev_req_t ll_nonblocking_rw; + proxy_ceph_add_fscrypt_key_req_t add_fscrypt_key; + proxy_ceph_remove_fscrypt_key_req_t remove_fscrypt_key; + proxy_ceph_get_fscrypt_key_status_req_t get_fscrypt_key_status; + proxy_ceph_ll_set_fscrypt_policy_v2_req_t ll_set_fscrypt_policy_v2; + proxy_ceph_ll_get_fscrypt_policy_v2_req_t ll_get_fscrypt_policy_v2; + proxy_ceph_ll_is_encrypted_req_t ll_is_encrypted; } proxy_req_t; PROTO_NOTIFY(ceph_ll_nonblocking_readv_writev, -- 2.47.3