]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core: convert exec-invoke to use the new static-friendly functions
authorZbigniew Jędrzejewski-Szmek <zbyszek@amutable.com>
Wed, 1 Jul 2026 17:49:16 +0000 (19:49 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@amutable.com>
Thu, 2 Jul 2026 15:19:18 +0000 (17:19 +0200)
The libc API is rather ugly: it requires the caller to pass an
array of the maximum possible size (or to repeatedly query the group
list to discover the actual size). With our "static-friendly" helpers,
we reallocate the array on the fly.

src/core/exec-invoke.c

index 0037890307411d2bf5c4dae5e5a88333eb2bc2d0..7a7f7f2a709c08e318f6e1ccddcbd0f0161d4b93 100644 (file)
@@ -890,7 +890,7 @@ static int get_supplementary_groups(
         assert(ret_gids);
 
         /*
-         * If user is given, then lookup GID and supplementary groups list.
+         * If user is given, then look up GID and supplementary groups list.
          * We avoid NSS lookups for gid=0. Also we have to initialize groups
          * here and as early as possible so we keep the list of supplementary
          * groups of the caller.
@@ -898,15 +898,16 @@ static int get_supplementary_groups(
         bool keep_groups = false;
         if (user && gid_is_valid(gid) && gid != 0) {
                 /* First step, initialize groups from /etc/groups */
-                if (initgroups(user, gid) < 0) {
+                r = initgroups_wrapper(user, gid);
+                if (r < 0) {
                         /* If our primary gid is already the one specified in Group= (i.e. we're running in
                          * user mode), gracefully handle the case where we have no privilege to re-initgroups().
                          *
                          * Note that group memberships of the current user might have been modified, but
                          * the change will only take effect after re-login. It's better to continue on with
                          * existing credentials rather than erroring out. */
-                        if (!ERRNO_IS_PRIVILEGE(errno) || gid != getgid())
-                                return -errno;
+                        if (!ERRNO_IS_PRIVILEGE(r) || gid != getgid())
+                                return r;
                 }
 
                 keep_groups = true;
@@ -917,29 +918,30 @@ static int get_supplementary_groups(
                 return 0;
         }
 
-        int ngroups_max = sysconf_ngroups_max();
-        if (ngroups_max < 0)
-                return ngroups_max;
-
-        _cleanup_free_ gid_t *l_gids = new(gid_t, ngroups_max);
-        if (!l_gids)
-                return -ENOMEM;
+        /* If SupplementaryGroups= was passed then NGROUPS_MAX has to be positive, otherwise fail. */
+        _cleanup_free_ gid_t *l_gids = NULL;
 
         int k = 0;
         if (keep_groups) {
-                /*
-                 * Lookup the list of groups that the user belongs to, we
-                 * avoid NSS lookups here too for gid=0.
-                 */
-                k = ngroups_max;
-                if (getgrouplist(user, gid, l_gids, &k) < 0)
-                        return -EINVAL;
+                /* Look up the list of groups that the user belongs to.
+                 * We avoid NSS lookups here too for gid=0. */
+
+                k = getgrouplist_malloc(user, gid, &l_gids);
+                if (k < 0)
+                        return k;
         }
 
+        int ngroups_max = sysconf_ngroups_max();
+        if (ngroups_max < 0)
+                return ngroups_max;
+
         STRV_FOREACH(i, c->supplementary_groups) {
                 if (k >= ngroups_max)
                         return -E2BIG;
 
+                if (!GREEDY_REALLOC(l_gids, k + 1))
+                        return -ENOMEM;
+
                 r = get_group_creds(*i, /* flags= */ 0, /* ret_name= */ NULL, l_gids + k);
                 if (r < 0)
                         return r;
@@ -952,12 +954,11 @@ static int get_supplementary_groups(
                 return 0;
         }
 
-        /* Otherwise get the final list of supplementary groups */
-        gid_t *groups = newdup(gid_t, l_gids, k);
-        if (!groups)
-                return -ENOMEM;
+        /* We *could* trim the array size with realloc(3), but right now the only caller frees the array
+         * quickly anyway, so this is not worth the trouble. If other users pop up, this should be
+         * reconsidered. */
 
-        *ret_gids = groups;
+        *ret_gids = TAKE_PTR(l_gids);
         return k;
 }