]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
libcephfs_proxy: implement client side support for embedded perms
authorXavi Hernandez <xhernandez@gmail.com>
Sat, 26 Jul 2025 19:33:55 +0000 (21:33 +0200)
committerAnoop C S <anoopcs@cryptolab.net>
Fri, 15 Aug 2025 09:52:22 +0000 (15:22 +0530)
Implement the code to handle embedded perms or not depending on a
feature flag negotiated during connection.

If embedded permissions are enabled, ceph_userperm_new() will allocate a
local structure with the provided credentials instead of sending it to
the server. ceph_userperm_destroy() will just destroy the allocated
structure. If it's disabled, these function will work as any other
function, sending the request to the server.

Signed-off-by: Xavi Hernandez <xhernandez@gmail.com>
(cherry picked from commit 68505c3e3a3f7c00bcc6a0b2e90932bf52d09575)

src/libcephfs_proxy/libcephfs_proxy.c

index 6b898d06dee6d7b09684248b1e3b777807c67640..2d9fc51dfdc15284099f7fc637404021bec70e74 100644 (file)
@@ -8,6 +8,16 @@
 #include "proxy_requests.h"
 #include "proxy_async.h"
 
+/* We override the definition of UserPerm structure to contain internal user
+ * credentials. This is already a black box for libcephfs users, so this won't
+ * be noticed. */
+struct UserPerm {
+       uid_t uid;
+       gid_t gid;
+       uint32_t count;
+       gid_t groups[];
+};
+
 /* We override the definition of the ceph_mount_info structure to contain
  * internal proxy information. This is already a black box for libcephfs users,
  * so this won't be noticed. */
@@ -121,6 +131,31 @@ static int32_t proxy_check(struct ceph_mount_info *cmount, int32_t err,
                __err;                                              \
        })
 
+#define PROXY_EMBED_PERMS(_client, _req, _perms) \
+       do { \
+               if (proxy_embed_perms(_client, &_req.v0.userperm, _perms)) { \
+                       _req.v1.ngroups = _perms->count; \
+                       CEPH_BUFF_ADD(_req, _perms->groups, \
+                                     sizeof(gid_t) * _perms->count); \
+               } else { \
+                       _req.v1.ngroups = 0; \
+               } \
+       } while (false)
+
+static bool proxy_embed_perms(struct ceph_mount_info *cmount,
+                             embedded_perms_t *embed, const UserPerm *perms)
+{
+       if ((cmount->neg.v1.enabled & PROXY_FEAT_EMBEDDED_PERMS) != 0) {
+               embed->uid = perms->uid;
+               embed->gid = perms->gid;
+               return true;
+       }
+
+       embed->ptr = ptr_value(perms);
+
+       return false;
+}
+
 __public int ceph_chdir(struct ceph_mount_info *cmount, const char *path)
 {
        CEPH_REQ(ceph_chdir, req, 1, ans, 0);
@@ -264,10 +299,11 @@ __public int ceph_ll_create(struct ceph_mount_info *cmount, Inode *parent,
                            unsigned want, unsigned lflags,
                            const UserPerm *perms)
 {
-       CEPH_REQ(ceph_ll_create, req, 1, ans, 1);
+       CEPH_REQ(ceph_ll_create, req, 2, ans, 1);
        int32_t err;
 
-       req.v0.userperm.ptr = ptr_value(perms);
+       PROTO_VERSION(&cmount->neg, req, PROXY_PROTOCOL_V1);
+
        req.v0.parent = ptr_value(parent);
        req.v0.mode = mode;
        req.v0.oflags = oflags;
@@ -275,6 +311,8 @@ __public int ceph_ll_create(struct ceph_mount_info *cmount, Inode *parent,
        req.v0.flags = lflags;
 
        CEPH_STR_ADD(req, v0.name, name);
+       PROXY_EMBED_PERMS(cmount, req, perms);
+
        CEPH_BUFF_ADD(ans, stx, sizeof(*stx));
 
        err = CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_CREATE, req, ans);
@@ -314,13 +352,16 @@ __public int ceph_ll_getattr(struct ceph_mount_info *cmount, struct Inode *in,
                             struct ceph_statx *stx, unsigned int want,
                             unsigned int flags, const UserPerm *perms)
 {
-       CEPH_REQ(ceph_ll_getattr, req, 0, ans, 1);
+       CEPH_REQ(ceph_ll_getattr, req, 1, ans, 1);
+
+       PROTO_VERSION(&cmount->neg, req, PROXY_PROTOCOL_V1);
 
-       req.v0.userperm.ptr = ptr_value(perms);
        req.v0.inode = ptr_value(in);
        req.v0.want = want;
        req.v0.flags = flags;
 
+       PROXY_EMBED_PERMS(cmount, req, perms);
+
        CEPH_BUFF_ADD(ans, stx, sizeof(*stx));
 
        return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_GETATTR, req, ans);
@@ -330,12 +371,15 @@ __public int ceph_ll_getxattr(struct ceph_mount_info *cmount, struct Inode *in,
                              const char *name, void *value, size_t size,
                              const UserPerm *perms)
 {
-       CEPH_REQ(ceph_ll_getxattr, req, 1, ans, 1);
+       CEPH_REQ(ceph_ll_getxattr, req, 2, ans, 1);
+
+       PROTO_VERSION(&cmount->neg, req, PROXY_PROTOCOL_V1);
 
-       req.v0.userperm.ptr = ptr_value(perms);
        req.v0.inode = ptr_value(in);
        req.v0.size = size;
+
        CEPH_STR_ADD(req, v0.name, name);
+       PROXY_EMBED_PERMS(cmount, req, perms);
 
        CEPH_BUFF_ADD(ans, value, size);
 
@@ -346,12 +390,15 @@ __public int ceph_ll_link(struct ceph_mount_info *cmount, struct Inode *in,
                          struct Inode *newparent, const char *name,
                          const UserPerm *perms)
 {
-       CEPH_REQ(ceph_ll_link, req, 1, ans, 0);
+       CEPH_REQ(ceph_ll_link, req, 2, ans, 0);
+
+       PROTO_VERSION(&cmount->neg, req, PROXY_PROTOCOL_V1);
 
-       req.v0.userperm.ptr = ptr_value(perms);
        req.v0.inode = ptr_value(in);
        req.v0.parent = ptr_value(newparent);
+
        CEPH_STR_ADD(req, v0.name, name);
+       PROXY_EMBED_PERMS(cmount, req, perms);
 
        return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_LINK, req, ans);
 }
@@ -360,13 +407,16 @@ __public int ceph_ll_listxattr(struct ceph_mount_info *cmount, struct Inode *in,
                               char *list, size_t buf_size, size_t *list_size,
                               const UserPerm *perms)
 {
-       CEPH_REQ(ceph_ll_listxattr, req, 0, ans, 1);
+       CEPH_REQ(ceph_ll_listxattr, req, 1, ans, 1);
        int32_t err;
 
-       req.v0.userperm.ptr = ptr_value(perms);
+       PROTO_VERSION(&cmount->neg, req, PROXY_PROTOCOL_V1);
+
        req.v0.inode = ptr_value(in);
        req.v0.size = buf_size;
 
+       PROXY_EMBED_PERMS(cmount, req, perms);
+
        CEPH_BUFF_ADD(ans, list, buf_size);
 
        err = CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_LISTXATTR, req, ans);
@@ -382,14 +432,17 @@ __public int ceph_ll_lookup(struct ceph_mount_info *cmount, Inode *parent,
                            struct ceph_statx *stx, unsigned want,
                            unsigned flags, const UserPerm *perms)
 {
-       CEPH_REQ(ceph_ll_lookup, req, 1, ans, 1);
+       CEPH_REQ(ceph_ll_lookup, req, 2, ans, 1);
        int32_t err;
 
-       req.v0.userperm.ptr = ptr_value(perms);
+       PROTO_VERSION(&cmount->neg, req, PROXY_PROTOCOL_V1);
+
        req.v0.parent = ptr_value(parent);
        req.v0.want = want;
        req.v0.flags = flags;
+
        CEPH_STR_ADD(req, v0.name, name);
+       PROXY_EMBED_PERMS(cmount, req, perms);
 
        CEPH_BUFF_ADD(ans, stx, sizeof(*stx));
 
@@ -453,15 +506,18 @@ __public int ceph_ll_mkdir(struct ceph_mount_info *cmount, Inode *parent,
                           struct ceph_statx *stx, unsigned want,
                           unsigned flags, const UserPerm *perms)
 {
-       CEPH_REQ(ceph_ll_mkdir, req, 1, ans, 1);
+       CEPH_REQ(ceph_ll_mkdir, req, 2, ans, 1);
        int32_t err;
 
-       req.v0.userperm.ptr = ptr_value(perms);
+       PROTO_VERSION(&cmount->neg, req, PROXY_PROTOCOL_V1);
+
        req.v0.parent = ptr_value(parent);
        req.v0.mode = mode;
        req.v0.want = want;
        req.v0.flags = flags;
+
        CEPH_STR_ADD(req, v0.name, name);
+       PROXY_EMBED_PERMS(cmount, req, perms);
 
        CEPH_BUFF_ADD(ans, stx, sizeof(*stx));
 
@@ -478,16 +534,19 @@ __public int ceph_ll_mknod(struct ceph_mount_info *cmount, Inode *parent,
                           Inode **out, struct ceph_statx *stx, unsigned want,
                           unsigned flags, const UserPerm *perms)
 {
-       CEPH_REQ(ceph_ll_mknod, req, 1, ans, 1);
+       CEPH_REQ(ceph_ll_mknod, req, 2, ans, 1);
        int32_t err;
 
-       req.v0.userperm.ptr = ptr_value(perms);
+       PROTO_VERSION(&cmount->neg, req, PROXY_PROTOCOL_V1);
+
        req.v0.parent = ptr_value(parent);
        req.v0.mode = mode;
        req.v0.rdev = rdev;
        req.v0.want = want;
        req.v0.flags = flags;
+
        CEPH_STR_ADD(req, v0.name, name);
+       PROXY_EMBED_PERMS(cmount, req, perms);
 
        CEPH_BUFF_ADD(ans, stx, sizeof(*stx));
 
@@ -502,13 +561,16 @@ __public int ceph_ll_mknod(struct ceph_mount_info *cmount, Inode *parent,
 __public int ceph_ll_open(struct ceph_mount_info *cmount, struct Inode *in,
                          int flags, struct Fh **fh, const UserPerm *perms)
 {
-       CEPH_REQ(ceph_ll_open, req, 0, ans, 0);
+       CEPH_REQ(ceph_ll_open, req, 1, ans, 0);
        int32_t err;
 
-       req.v0.userperm.ptr = ptr_value(perms);
+       PROTO_VERSION(&cmount->neg, req, PROXY_PROTOCOL_V1);
+
        req.v0.inode = ptr_value(in);
        req.v0.flags = flags;
 
+       PROXY_EMBED_PERMS(cmount, req, perms);
+
        err = CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_OPEN, req, ans);
        if (err >= 0) {
                *fh = value_ptr(ans.v0.fh);
@@ -521,12 +583,15 @@ __public int ceph_ll_opendir(struct ceph_mount_info *cmount, struct Inode *in,
                             struct ceph_dir_result **dirpp,
                             const UserPerm *perms)
 {
-       CEPH_REQ(ceph_ll_opendir, req, 0, ans, 0);
+       CEPH_REQ(ceph_ll_opendir, req, 1, ans, 0);
        int32_t err;
 
-       req.v0.userperm.ptr = ptr_value(perms);
+       PROTO_VERSION(&cmount->neg, req, PROXY_PROTOCOL_V1);
+
        req.v0.inode = ptr_value(in);
 
+       PROXY_EMBED_PERMS(cmount, req, perms);
+
        err = CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_OPENDIR, req, ans);
        if (err >= 0) {
                *dirpp = value_ptr(ans.v0.dir);
@@ -561,12 +626,15 @@ __public int ceph_ll_read(struct ceph_mount_info *cmount, struct Fh *filehandle,
 __public int ceph_ll_readlink(struct ceph_mount_info *cmount, struct Inode *in,
                              char *buf, size_t bufsize, const UserPerm *perms)
 {
-       CEPH_REQ(ceph_ll_readlink, req, 0, ans, 1);
+       CEPH_REQ(ceph_ll_readlink, req, 1, ans, 1);
+
+       PROTO_VERSION(&cmount->neg, req, PROXY_PROTOCOL_V1);
 
-       req.v0.userperm.ptr = ptr_value(perms);
        req.v0.inode = ptr_value(in);
        req.v0.size = bufsize;
 
+       PROXY_EMBED_PERMS(cmount, req, perms);
+
        CEPH_BUFF_ADD(ans, buf, bufsize);
 
        return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_READLINK, req, ans);
@@ -586,11 +654,14 @@ __public int ceph_ll_removexattr(struct ceph_mount_info *cmount,
                                 struct Inode *in, const char *name,
                                 const UserPerm *perms)
 {
-       CEPH_REQ(ceph_ll_removexattr, req, 1, ans, 0);
+       CEPH_REQ(ceph_ll_removexattr, req, 2, ans, 0);
+
+       PROTO_VERSION(&cmount->neg, req, PROXY_PROTOCOL_V1);
 
-       req.v0.userperm.ptr = ptr_value(perms);
        req.v0.inode = ptr_value(in);
+
        CEPH_STR_ADD(req, v0.name, name);
+       PROXY_EMBED_PERMS(cmount, req, perms);
 
        return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_REMOVEXATTR, req, ans);
 }
@@ -600,13 +671,16 @@ __public int ceph_ll_rename(struct ceph_mount_info *cmount,
                            struct Inode *newparent, const char *newname,
                            const UserPerm *perms)
 {
-       CEPH_REQ(ceph_ll_rename, req, 2, ans, 0);
+       CEPH_REQ(ceph_ll_rename, req, 3, ans, 0);
+
+       PROTO_VERSION(&cmount->neg, req, PROXY_PROTOCOL_V1);
 
-       req.v0.userperm.ptr = ptr_value(perms);
        req.v0.old_parent = ptr_value(parent);
        req.v0.new_parent = ptr_value(newparent);
+
        CEPH_STR_ADD(req, v0.old_name, name);
        CEPH_STR_ADD(req, v0.new_name, newname);
+       PROXY_EMBED_PERMS(cmount, req, perms);
 
        return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_RENAME, req, ans);
 }
@@ -624,11 +698,14 @@ __public void ceph_rewinddir(struct ceph_mount_info *cmount,
 __public int ceph_ll_rmdir(struct ceph_mount_info *cmount, struct Inode *in,
                           const char *name, const UserPerm *perms)
 {
-       CEPH_REQ(ceph_ll_rmdir, req, 1, ans, 0);
+       CEPH_REQ(ceph_ll_rmdir, req, 2, ans, 0);
+
+       PROTO_VERSION(&cmount->neg, req, PROXY_PROTOCOL_V1);
 
-       req.v0.userperm.ptr = ptr_value(perms);
        req.v0.parent = ptr_value(in);
+
        CEPH_STR_ADD(req, v0.name, name);
+       PROXY_EMBED_PERMS(cmount, req, perms);
 
        return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_RMDIR, req, ans);
 }
@@ -637,12 +714,15 @@ __public int ceph_ll_setattr(struct ceph_mount_info *cmount, struct Inode *in,
                             struct ceph_statx *stx, int mask,
                             const UserPerm *perms)
 {
-       CEPH_REQ(ceph_ll_setattr, req, 1, ans, 0);
+       CEPH_REQ(ceph_ll_setattr, req, 2, ans, 0);
+
+       PROTO_VERSION(&cmount->neg, req, PROXY_PROTOCOL_V1);
 
-       req.v0.userperm.ptr = ptr_value(perms);
        req.v0.inode = ptr_value(in);
        req.v0.mask = mask;
+
        CEPH_BUFF_ADD(req, stx, sizeof(*stx));
+       PROXY_EMBED_PERMS(cmount, req, perms);
 
        return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_SETATTR, req, ans);
 }
@@ -651,14 +731,17 @@ __public int ceph_ll_setxattr(struct ceph_mount_info *cmount, struct Inode *in,
                              const char *name, const void *value, size_t size,
                              int flags, const UserPerm *perms)
 {
-       CEPH_REQ(ceph_ll_setxattr, req, 2, ans, 0);
+       CEPH_REQ(ceph_ll_setxattr, req, 3, ans, 0);
+
+       PROTO_VERSION(&cmount->neg, req, PROXY_PROTOCOL_V1);
 
-       req.v0.userperm.ptr = ptr_value(perms);
        req.v0.inode = ptr_value(in);
        req.v0.size = size;
        req.v0.flags = flags;
+
        CEPH_STR_ADD(req, v0.name, name);
        CEPH_BUFF_ADD(req, value, size);
+       PROXY_EMBED_PERMS(cmount, req, perms);
 
        return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_SETXATTR, req, ans);
 }
@@ -680,15 +763,18 @@ __public int ceph_ll_symlink(struct ceph_mount_info *cmount, Inode *in,
                             struct ceph_statx *stx, unsigned want,
                             unsigned flags, const UserPerm *perms)
 {
-       CEPH_REQ(ceph_ll_symlink, req, 2, ans, 1);
+       CEPH_REQ(ceph_ll_symlink, req, 3, ans, 1);
        int32_t err;
 
-       req.v0.userperm.ptr = ptr_value(perms);
+       PROTO_VERSION(&cmount->neg, req, PROXY_PROTOCOL_V1);
+
        req.v0.parent = ptr_value(in);
        req.v0.want = want;
        req.v0.flags = flags;
+
        CEPH_STR_ADD(req, v0.name, name);
        CEPH_STR_ADD(req, v0.target, value);
+       PROXY_EMBED_PERMS(cmount, req, perms);
 
        CEPH_BUFF_ADD(req, stx, sizeof(*stx));
 
@@ -703,11 +789,14 @@ __public int ceph_ll_symlink(struct ceph_mount_info *cmount, Inode *in,
 __public int ceph_ll_unlink(struct ceph_mount_info *cmount, struct Inode *in,
                            const char *name, const UserPerm *perms)
 {
-       CEPH_REQ(ceph_ll_unlink, req, 1, ans, 0);
+       CEPH_REQ(ceph_ll_unlink, req, 2, ans, 0);
+
+       PROTO_VERSION(&cmount->neg, req, PROXY_PROTOCOL_V1);
 
-       req.v0.userperm.ptr = ptr_value(perms);
        req.v0.parent = ptr_value(in);
+
        CEPH_STR_ADD(req, v0.name, name);
+       PROXY_EMBED_PERMS(cmount, req, perms);
 
        return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_UNLINK, req, ans);
 }
@@ -716,13 +805,16 @@ __public int ceph_ll_walk(struct ceph_mount_info *cmount, const char *name,
                          Inode **i, struct ceph_statx *stx, unsigned int want,
                          unsigned int flags, const UserPerm *perms)
 {
-       CEPH_REQ(ceph_ll_walk, req, 1, ans, 1);
+       CEPH_REQ(ceph_ll_walk, req, 2, ans, 1);
        int32_t err;
 
-       req.v0.userperm.ptr = ptr_value(perms);
+       PROTO_VERSION(&cmount->neg, req, PROXY_PROTOCOL_V1);
+
        req.v0.want = want;
        req.v0.flags = flags;
+
        CEPH_STR_ADD(req, v0.path, name);
+       PROXY_EMBED_PERMS(cmount, req, perms);
 
        CEPH_BUFF_ADD(ans, stx, sizeof(*stx));
 
@@ -833,27 +925,56 @@ __public void ceph_userperm_destroy(UserPerm *perms)
 {
        CEPH_REQ(ceph_userperm_destroy, req, 0, ans, 0);
 
-       req.v0.userperm = ptr_value(perms);
+       /* We need to make use of the negotiation of the global mount since we
+        * don't have access to cmount here. Both negotiations should have
+        * the same setting for the embedded perms feature. */
+       if ((global_cmount.neg.v1.enabled & PROXY_FEAT_EMBEDDED_PERMS) != 0) {
+               proxy_free(perms);
+       } else {
+               req.v0.userperm = ptr_value(perms);
 
-       CEPH_RUN(&global_cmount, LIBCEPHFSD_OP_USERPERM_DESTROY, req, ans);
+               CEPH_RUN(&global_cmount, LIBCEPHFSD_OP_USERPERM_DESTROY, req,
+                        ans);
+       }
 }
 
 __public UserPerm *ceph_userperm_new(uid_t uid, gid_t gid, int ngids,
                                     gid_t *gidlist)
 {
        CEPH_REQ(ceph_userperm_new, req, 1, ans, 0);
+       UserPerm *perms;
        int32_t err;
 
+       err = proxy_global_connect();
+       if (err < 0) {
+               errno = -err;
+               return NULL;
+       }
+
+       /* We need to make use of the negotiation of the global mount since we
+        * don't have access to cmount here. Both negotiations should have
+        * the same setting for the embedded perms feature. */
+       if ((global_cmount.neg.v1.enabled & PROXY_FEAT_EMBEDDED_PERMS) != 0) {
+               perms = proxy_malloc(sizeof(UserPerm) + sizeof(gid_t) * ngids);
+               if (perms == NULL) {
+                       errno = -ENOMEM;
+                       return NULL;
+               }
+
+               perms->uid = uid;
+               perms->gid = gid;
+               perms->count = ngids;
+               memcpy(perms->groups, gidlist, sizeof(gid_t) * ngids);
+
+               return perms;
+       }
+
        req.v0.uid = uid;
        req.v0.gid = gid;
        req.v0.groups = ngids;
        CEPH_BUFF_ADD(req, gidlist, sizeof(gid_t) * ngids);
 
-       err = proxy_global_connect();
-       if (err >= 0) {
-               err = CEPH_RUN(&global_cmount, LIBCEPHFSD_OP_USERPERM_NEW, req,
-                              ans);
-       }
+       err = CEPH_RUN(&global_cmount, LIBCEPHFSD_OP_USERPERM_NEW, req, ans);
        if (err >= 0) {
                return value_ptr(ans.v0.userperm);
        }
@@ -905,6 +1026,11 @@ __public UserPerm *ceph_mount_perms(struct ceph_mount_info *cmount)
        CEPH_REQ(ceph_mount_perms, req, 0, ans, 0);
        int32_t err;
 
+       if ((cmount->neg.v1.enabled & PROXY_FEAT_EMBEDDED_PERMS) != 0) {
+               errno = -EOPNOTSUPP;
+               return NULL;
+       }
+
        err = CEPH_PROCESS(cmount, LIBCEPHFSD_OP_MOUNT_PERMS, req, ans);
        if (err < 0) {
                errno = -err;