From ea8e2b96d8f0584ac4cf7df69c92cc9f83a4c7d7 Mon Sep 17 00:00:00 2001 From: Carlos O'Donell Date: Fri, 7 Nov 2025 09:46:10 -0500 Subject: [PATCH] nss: Add ERANGE testing to tst-nss-test4 (bug 33361) This adds testing for the fix added in commit: 0fceed254559836b57ee05188deac649bc505d05 "nss: Group merge does not react to ERANGE during merge (bug 33361)" The in-use group size is increased large enough to trigger ERANGE for initial buffers and cause a retry. The actualy size is approximately twice that required to trigger the defect, though any size larger than NSS_BUFLEN_GROUP triggers the defect. Without the fix the group is not merged and the failure is detected, but with the fix the ERANGE error is handled, buffers are enlarged and subsequently correctly merged. Tested with a/b testing before and after patching. Tested on x86_64 with no regression. Co-authored-by: Patsy Griffin Reviewed-by: DJ Delorie --- nss/tst-nss-test4.c | 115 +++++++++++++++++++++++++++++++++----------- 1 file changed, 86 insertions(+), 29 deletions(-) diff --git a/nss/tst-nss-test4.c b/nss/tst-nss-test4.c index 5e9306cc93..3d94c12d08 100644 --- a/nss/tst-nss-test4.c +++ b/nss/tst-nss-test4.c @@ -16,11 +16,16 @@ License along with the GNU C Library; if not, see . */ +#include #include #include #include #include +#include +/* For NSS_BUFLEN_GROUP define. */ +#include "nss/grp.h" +#include #include #include "nss_test.h" @@ -32,14 +37,10 @@ static const char *group_1[] = { "foo", "bar", NULL }; -static const char *group_2[] = { - "foo", "dick", "harry", NULL -}; +/* Enough entries to exceed NSS_BUFLEN_GROUP and trigger ERANGE. */ +static char *group_2[256]; -/* Note that deduplication is NOT supposed to happen. */ -static const char *merge_1[] = { - "foo", "bar", "foo", "dick", "harry", NULL -}; +static char *merge_1[array_length(group_1) + array_length (group_2) - 1]; static const char *group_4[] = { "fred", "wilma", NULL @@ -59,6 +60,14 @@ static struct group group_table_data2[] = { GRP_LAST () }; +/* In order to trigger ERANGE checking the minimum size of + group_table_data2 should exceed NSS_BUFLEN_GROUP which is used + internally by getgrgid. We use 8 bytes per group_2 string as + a lower bound. */ +_Static_assert (sizeof (group_table_data2) + array_length (group_2) * 8 + >= NSS_BUFLEN_GROUP, + "test group table size should exceed NSS_BUFLEN_GROUP"); + /* This is the data we compare against. */ static struct group group_table[] = { GRP_N(1, "name1", merge_1), @@ -83,42 +92,90 @@ static int do_test (void) { int retval = 0; - int i; + int i, member_cnt; struct group *g = NULL; uintptr_t align_mask; + uintptr_t align_mem_mask; - __nss_configure_lookup ("group", "test1 [SUCCESS=merge] test2"); + /* At least 3 service modules are needed to reproduce BZ#33361. */ + __nss_configure_lookup ("group", "test1 [SUCCESS=merge] test2 files"); - align_mask = __alignof__ (struct group *) - 1; + /* Test increasing sizes of group_2 to see if we fail, starting with + member_cnt == 1 to ensure we always check for no de-duplication + e.g. { "foo", NULL } */ + for (member_cnt = 1; member_cnt < array_length (group_2); member_cnt++) + { + verbose_printf ("Outer loop - member_cnt is %d\n", member_cnt); - setgrent (); + /* Initialize group_2 */ + for (i = 0; i < member_cnt; i++) + { + /* Note that deduplication is NOT supposed to happen. */ + if (i == 0) + group_2[i] = xstrdup ("foo"); + else + group_2[i] = xasprintf ("foobar%d", i); + } + group_2[member_cnt] = NULL; - for (i = 0; group_table[i].gr_gid; ++i) - { - g = getgrgid (group_table[i].gr_gid); - if (g) + /* Create the merged list to verify against */ + + /* Copy group_1 to the merge list (excluding NULL) */ + for (i = 0; i < array_length (group_1) - 1; i++) + { + merge_1[i] = xasprintf ("%s", group_1[i]); + verbose_printf ("MERGED LIST of [%d] is %s\n", i, merge_1[i]); + } + + /* Add group_2 to the merge list */ + int group2_index = 0; + for (i = array_length (group_1) - 1; + i < array_length (group_1) - 1 + member_cnt; i++) { - retval += compare_groups (i, g, & group_table[i]); - if ((uintptr_t)g & align_mask) + merge_1[i] = xasprintf ("%s", group_2[group2_index++]); + verbose_printf ("MERGED LIST of [%d] is %s\n", i, merge_1[i]); + } + merge_1[array_length(group_1) - 1 + member_cnt]= NULL; + + align_mask = __alignof__ (struct group) - 1; + align_mem_mask = __alignof__ (char *) - 1; + + setgrent (); + + for (i = 0; group_table[i].gr_gid; ++i) + { + g = getgrgid (group_table[i].gr_gid); + if (g) { - printf("FAIL: [%d] unaligned group %p\n", i, g); - ++retval; + retval += compare_groups (i, g, & group_table[i]); + if ((uintptr_t)g & align_mask) + { + printf ("FAIL: [%d] unaligned group %p\n", i, g); + ++retval; + } + if ((uintptr_t)(g->gr_mem) & align_mem_mask) + { + printf ("FAIL: [%d] unaligned member list %p\n", + i, g->gr_mem); + ++retval; + } } - if ((uintptr_t)(g->gr_mem) & align_mask) + else { - printf("FAIL: [%d] unaligned member list %p\n", i, g->gr_mem); + printf ("FAIL: [%d] group %u.%s not found\n", i, + group_table[i].gr_gid, group_table[i].gr_name); ++retval; } } - else - { - printf ("FAIL: [%d] group %u.%s not found\n", i, - group_table[i].gr_gid, group_table[i].gr_name); - ++retval; - } - } - endgrent (); + endgrent (); + + /* Free malloc'd array members (including the NULL) */ + for (i = 0; i < member_cnt; i++) + free (group_2[i]); + for (i = 0; i < array_length (group_1) + member_cnt; i++) + free (merge_1[i]); + } #define EXPECTED 0 if (retval == EXPECTED) -- 2.47.3