]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
nss: Add ERANGE testing to tst-nss-test4 (bug 33361)
authorCarlos O'Donell <carlos@redhat.com>
Fri, 7 Nov 2025 14:46:10 +0000 (09:46 -0500)
committerCarlos O'Donell <carlos@redhat.com>
Sat, 8 Nov 2025 14:28:11 +0000 (09:28 -0500)
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 <patsy@redhat.com>
Reviewed-by: DJ Delorie <dj@redhat.com>
nss/tst-nss-test4.c

index 5e9306cc9325aa3bada430b22305c3368d0efe54..3d94c12d089cedae30f86a46a899596c0c47e13f 100644 (file)
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
+#include <assert.h>
 #include <nss.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <array_length.h>
+/* For NSS_BUFLEN_GROUP define.  */
+#include "nss/grp.h"
 
+#include <support/test-driver.h>
 #include <support/support.h>
 
 #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)