nss-systemd: set sg_adm/sg_mem in intrinsic groups

The sg_adm and sg_mem fields are supposed to point to a NULL terminated
string array. If these are NULL, some foreign tools like shadow's sg
trigger NULL pointer dereferences (or fortunately their asset() calls).
This commit is contained in:
Tobias Stoeckmann
2026-01-04 18:01:13 +01:00
parent e67ad3e586
commit 239903d44c
+16 -3
View File
@@ -75,6 +75,8 @@ static const struct group root_group = {
static const struct sgrp root_sgrp = {
.sg_namp = (char*) "root",
.sg_passwd = (char*) PASSWORD_LOCKED_AND_INVALID,
.sg_adm = (char*[]) { NULL },
.sg_mem = (char*[]) { NULL },
};
static const struct group nobody_group = {
@@ -87,6 +89,8 @@ static const struct group nobody_group = {
static const struct sgrp nobody_sgrp = {
.sg_namp = (char*) NOBODY_GROUP_NAME,
.sg_passwd = (char*) PASSWORD_LOCKED_AND_INVALID,
.sg_adm = (char*[]) { NULL },
.sg_mem = (char*[]) { NULL },
};
typedef struct GetentData {
@@ -257,12 +261,18 @@ static enum nss_status copy_synthesized_sgrp(
assert(src);
assert(src->sg_namp);
assert(src->sg_passwd);
assert(src->sg_adm);
assert(!*src->sg_adm); /* Our synthesized records' sg_adm is always just NULL... */
assert(src->sg_mem);
assert(!*src->sg_mem); /* Our synthesized records' sg_mem is always just NULL... */
size_t required =
strlen(src->sg_namp) + 1 +
strlen(src->sg_passwd) + 1;
strlen(src->sg_passwd) + 1 +
sizeof(char*) + /* NULL terminator storage for src->sg_adm */
sizeof(char*); /* NULL terminator storage for src->sg_mem */
if (buflen < required) {
if (buflen < ALIGN(required)) {
*errnop = ERANGE;
return NSS_STATUS_TRYAGAIN;
}
@@ -274,7 +284,10 @@ static enum nss_status copy_synthesized_sgrp(
/* String fields point into the user-provided buffer */
dest->sg_namp = buffer;
dest->sg_passwd = stpcpy(dest->sg_namp, src->sg_namp) + 1;
strcpy(dest->sg_passwd, src->sg_passwd);
dest->sg_adm = ALIGN_PTR(stpcpy(dest->sg_passwd, src->sg_passwd) + 1);
*dest->sg_adm = NULL;
dest->sg_mem = dest->sg_adm + 1;
*dest->sg_mem = NULL;
return NSS_STATUS_SUCCESS;
}