diff options
author | Lennart Poettering <lennart@poettering.net> | 2019-10-31 20:27:34 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2019-10-31 20:59:27 +0100 |
commit | 6e0a3888541d08e34f02ccaf2a86940d266c9f01 (patch) | |
tree | f82f2aec356e1439b9a1bc61bfa6d2ca4f25d835 /src | |
parent | 3ec56e53a2f83f07ffdd10343ace6d604717c1f0 (diff) | |
download | systemd-6e0a3888541d08e34f02ccaf2a86940d266c9f01.tar.gz |
user-util: tweak to in_gid()
Let's make this robust towards parallel updates to group lists. This is
not going to happen IRL, but it makes me sleep better at night: let's
iterate a couple of times in case the list is updated while we are at
it.
Follow-up for: f5e0b942af1e86993c21f4e5c84342bb10403dac
Diffstat (limited to 'src')
-rw-r--r-- | src/basic/user-util.c | 50 |
1 files changed, 34 insertions, 16 deletions
diff --git a/src/basic/user-util.c b/src/basic/user-util.c index 7a31a69e36..b5fdfafd61 100644 --- a/src/basic/user-util.c +++ b/src/basic/user-util.c @@ -409,8 +409,10 @@ char* gid_to_name(gid_t gid) { } int in_gid(gid_t gid) { - gid_t *gids; - int ngroups, r, i; + _cleanup_free_ gid_t *allocated = NULL; + gid_t local[16], *p = local; + int ngroups = ELEMENTSOF(local); + unsigned attempt = 0; if (getgid() == gid) return 1; @@ -421,23 +423,39 @@ int in_gid(gid_t gid) { if (!gid_is_valid(gid)) return -EINVAL; - ngroups = getgroups(0, NULL); - if (ngroups < 0) - return -errno; - if (ngroups == 0) - return 0; - - gids = newa(gid_t, ngroups); + for (;;) { + ngroups = getgroups(ngroups, p); + if (ngroups >= 0) + break; + if (errno != EINVAL) + return -errno; + + /* Give up eventually */ + if (attempt++ > 10) + return -EINVAL; + + /* Get actual size needed, and size the array explicitly. Note that this is potentially racy + * to use (in multi-threaded programs), hence let's call this in a loop. */ + ngroups = getgroups(0, NULL); + if (ngroups < 0) + return -errno; + if (ngroups == 0) + return false; + + free(allocated); + + allocated = new(gid_t, ngroups); + if (!allocated) + return -ENOMEM; - r = getgroups(ngroups, gids); - if (r < 0) - return -errno; + p = allocated; + } - for (i = 0; i < r; i++) - if (gids[i] == gid) - return 1; + for (int i = 0; i < ngroups; i++) + if (p[i] == gid) + return true; - return 0; + return false; } int in_group(const char *name) { |