ubusd: load extra group IDs for a client process
authorFelix Fietkau <[email protected]>
Tue, 14 Oct 2025 09:49:16 +0000 (09:49 +0000)
committerFelix Fietkau <[email protected]>
Tue, 14 Oct 2025 10:16:49 +0000 (10:16 +0000)
Use them for ACL checks

Signed-off-by: Felix Fietkau <[email protected]>
ubusd.h
ubusd_acl.c

diff --git a/ubusd.h b/ubusd.h
index 05af4341eacd6cb053afcbd99d7abc03120829ea..a8348a35f8d04ad160a121018d2763532d8a0098 100644 (file)
--- a/ubusd.h
+++ b/ubusd.h
@@ -25,6 +25,7 @@
 
 #define UBUS_OBJ_HASH_BITS     4
 #define UBUS_CLIENT_MAX_TXQ_LEN        UBUS_MAX_MSGLEN
+#define UBUS_CLIENT_MAX_EXTRA_GID      64
 
 extern struct blob_buf b;
 
@@ -54,6 +55,8 @@ struct ubus_client {
 
        int uid;
        int gid;
+       int *extra_gid;
+       size_t n_extra_gid;
        char *user;
        char *group;
 
index b9755808863114ade01503bf16d6610b70745d1a..0979b5efc11fa032b10f079e0ac4b087bb14eeca 100644 (file)
@@ -81,11 +81,19 @@ static struct ubus_object *acl_obj;
 static int
 ubusd_acl_match_cred(struct ubus_client *cl, struct ubusd_acl_obj *obj)
 {
+       size_t i;
+
        if (obj->uid != -1 && cl->uid == obj->uid)
                return 0;
 
-       if (obj->gid != -1 && cl->gid == obj->gid)
-               return 0;
+       if (obj->gid != -1) {
+               if (cl->gid == obj->gid)
+                       return 0;
+
+               for (i = 0; i < cl->n_extra_gid; i++)
+                       if (cl->extra_gid[i] == obj->gid)
+                               return 0;
+       }
 
        return -1;
 }
@@ -170,6 +178,51 @@ ubusd_acl_check(struct ubus_client *cl, const char *obj,
        return -1;
 }
 
+static int
+ubusd_acl_load_extra_gids(struct ubus_client *cl, pid_t pid)
+{
+#ifdef __linux__
+       char path[64];
+       FILE *f;
+       char line[512];
+       gid_t gids[UBUS_CLIENT_MAX_EXTRA_GID];
+       size_t n_gids = 0;
+
+       snprintf(path, sizeof(path), "/proc/%d/status", (int)pid);
+       f = fopen(path, "r");
+       if (!f)
+               return -1;
+
+       while (fgets(line, sizeof(line), f)) {
+               if (strncmp(line, "Groups:", 7) != 0)
+                       continue;
+
+               char *p = line + 7;
+               while (*p && n_gids < UBUS_CLIENT_MAX_EXTRA_GID) {
+                       char *end;
+                       unsigned long gid = strtoul(p, &end, 10);
+                       if (p == end)
+                               break;
+                       gids[n_gids++] = gid;
+                       p = end;
+               }
+               break;
+       }
+
+       fclose(f);
+
+       if (n_gids > 0) {
+               cl->extra_gid = malloc(n_gids * sizeof(gid_t));
+               if (!cl->extra_gid)
+                       return -1;
+               memcpy(cl->extra_gid, gids, n_gids * sizeof(gid_t));
+               cl->n_extra_gid = n_gids;
+       }
+#endif
+
+       return 0;
+}
+
 int
 ubusd_acl_init_client(struct ubus_client *cl, int fd)
 {
@@ -206,12 +259,15 @@ ubusd_acl_init_client(struct ubus_client *cl, int fd)
        cl->group = strdup(group->gr_name);
        cl->user = strdup(pwd->pw_name);
 
+       ubusd_acl_load_extra_gids(cl, cred.pid);
+
        return 0;
 }
 
 void
 ubusd_acl_free_client(struct ubus_client *cl)
 {
+       free(cl->extra_gid);
        free(cl->group);
        free(cl->user);
 }