1feee8
commit e3255e7d2188d1731aad83ad0dc147513560aa1e
1feee8
Author: Noah Goldstein <goldstein.w.n@gmail.com>
1feee8
Date:   Tue Sep 20 17:58:04 2022 -0700
1feee8
1feee8
    x86: Fix wcsnlen-avx2 page cross length comparison [BZ #29591]
1feee8
    
1feee8
    Previous implementation was adjusting length (rsi) to match
1feee8
    bytes (eax), but since there is no bound to length this can cause
1feee8
    overflow.
1feee8
    
1feee8
    Fix is to just convert the byte-count (eax) to length by dividing by
1feee8
    sizeof (wchar_t) before the comparison.
1feee8
    
1feee8
    Full check passes on x86-64 and build succeeds w/ and w/o multiarch.
1feee8
    
1feee8
    (cherry picked from commit b0969fa53a28b4ab2159806bf6c99a98999502ee)
1feee8
1feee8
diff --git a/string/test-strnlen.c b/string/test-strnlen.c
1feee8
index bb5d9b5f04fa6586..eac84cd17526d5d9 100644
1feee8
--- a/string/test-strnlen.c
1feee8
+++ b/string/test-strnlen.c
1feee8
@@ -75,7 +75,7 @@ do_test (size_t align, size_t len, size_t maxlen, int max_char)
1feee8
 {
1feee8
   size_t i;
1feee8
 
1feee8
-  align &= 63;
1feee8
+  align &= (getpagesize () / sizeof (CHAR) - 1);
1feee8
   if ((align + len) * sizeof (CHAR) >= page_size)
1feee8
     return;
1feee8
 
1feee8
@@ -92,36 +92,50 @@ do_test (size_t align, size_t len, size_t maxlen, int max_char)
1feee8
 static void
1feee8
 do_overflow_tests (void)
1feee8
 {
1feee8
-  size_t i, j, len;
1feee8
+  size_t i, j, al_idx, repeats, len;
1feee8
   const size_t one = 1;
1feee8
   uintptr_t buf_addr = (uintptr_t) buf1;
1feee8
+  const size_t alignments[] = { 0, 1, 7, 9, 31, 33, 63, 65, 95, 97, 127, 129 };
1feee8
 
1feee8
-  for (i = 0; i < 750; ++i)
1feee8
+  for (al_idx = 0; al_idx < sizeof (alignments) / sizeof (alignments[0]);
1feee8
+       al_idx++)
1feee8
     {
1feee8
-      do_test (0, i, SIZE_MAX - i, BIG_CHAR);
1feee8
-      do_test (0, i, i - buf_addr, BIG_CHAR);
1feee8
-      do_test (0, i, -buf_addr - i, BIG_CHAR);
1feee8
-      do_test (0, i, SIZE_MAX - buf_addr - i, BIG_CHAR);
1feee8
-      do_test (0, i, SIZE_MAX - buf_addr + i, BIG_CHAR);
1feee8
-
1feee8
-      len = 0;
1feee8
-      for (j = 8 * sizeof(size_t) - 1; j ; --j)
1feee8
-        {
1feee8
-          len |= one << j;
1feee8
-          do_test (0, i, len - i, BIG_CHAR);
1feee8
-          do_test (0, i, len + i, BIG_CHAR);
1feee8
-          do_test (0, i, len - buf_addr - i, BIG_CHAR);
1feee8
-          do_test (0, i, len - buf_addr + i, BIG_CHAR);
1feee8
-
1feee8
-          do_test (0, i, ~len - i, BIG_CHAR);
1feee8
-          do_test (0, i, ~len + i, BIG_CHAR);
1feee8
-          do_test (0, i, ~len - buf_addr - i, BIG_CHAR);
1feee8
-          do_test (0, i, ~len - buf_addr + i, BIG_CHAR);
1feee8
-
1feee8
-          do_test (0, i, -buf_addr, BIG_CHAR);
1feee8
-          do_test (0, i, j - buf_addr, BIG_CHAR);
1feee8
-          do_test (0, i, -buf_addr - j, BIG_CHAR);
1feee8
-        }
1feee8
+      for (repeats = 0; repeats < 2; ++repeats)
1feee8
+	{
1feee8
+	  size_t align = repeats ? (getpagesize () - alignments[al_idx])
1feee8
+				 : alignments[al_idx];
1feee8
+	  align /= sizeof (CHAR);
1feee8
+	  for (i = 0; i < 750; ++i)
1feee8
+	    {
1feee8
+	      do_test (align, i, SIZE_MAX, BIG_CHAR);
1feee8
+
1feee8
+	      do_test (align, i, SIZE_MAX - i, BIG_CHAR);
1feee8
+	      do_test (align, i, i - buf_addr, BIG_CHAR);
1feee8
+	      do_test (align, i, -buf_addr - i, BIG_CHAR);
1feee8
+	      do_test (align, i, SIZE_MAX - buf_addr - i, BIG_CHAR);
1feee8
+	      do_test (align, i, SIZE_MAX - buf_addr + i, BIG_CHAR);
1feee8
+
1feee8
+	      len = 0;
1feee8
+	      for (j = 8 * sizeof (size_t) - 1; j; --j)
1feee8
+		{
1feee8
+		  len |= one << j;
1feee8
+		  do_test (align, i, len, BIG_CHAR);
1feee8
+		  do_test (align, i, len - i, BIG_CHAR);
1feee8
+		  do_test (align, i, len + i, BIG_CHAR);
1feee8
+		  do_test (align, i, len - buf_addr - i, BIG_CHAR);
1feee8
+		  do_test (align, i, len - buf_addr + i, BIG_CHAR);
1feee8
+
1feee8
+		  do_test (align, i, ~len - i, BIG_CHAR);
1feee8
+		  do_test (align, i, ~len + i, BIG_CHAR);
1feee8
+		  do_test (align, i, ~len - buf_addr - i, BIG_CHAR);
1feee8
+		  do_test (align, i, ~len - buf_addr + i, BIG_CHAR);
1feee8
+
1feee8
+		  do_test (align, i, -buf_addr, BIG_CHAR);
1feee8
+		  do_test (align, i, j - buf_addr, BIG_CHAR);
1feee8
+		  do_test (align, i, -buf_addr - j, BIG_CHAR);
1feee8
+		}
1feee8
+	    }
1feee8
+	}
1feee8
     }
1feee8
 }
1feee8
 
1feee8
diff --git a/sysdeps/x86_64/multiarch/strlen-avx2.S b/sysdeps/x86_64/multiarch/strlen-avx2.S
1feee8
index b282a75613bf52ab..4d7d68396bcd4049 100644
1feee8
--- a/sysdeps/x86_64/multiarch/strlen-avx2.S
1feee8
+++ b/sysdeps/x86_64/multiarch/strlen-avx2.S
1feee8
@@ -542,14 +542,11 @@ L(return_vzeroupper):
1feee8
 L(cross_page_less_vec):
1feee8
 	tzcntl	%eax, %eax
1feee8
 #  ifdef USE_AS_WCSLEN
1feee8
-	/* NB: Multiply length by 4 to get byte count.  */
1feee8
-	sall	$2, %esi
1feee8
+	/* NB: Divide by 4 to convert from byte-count to length.  */
1feee8
+	shrl	$2, %eax
1feee8
 #  endif
1feee8
 	cmpq	%rax, %rsi
1feee8
 	cmovb	%esi, %eax
1feee8
-#  ifdef USE_AS_WCSLEN
1feee8
-	shrl	$2, %eax
1feee8
-#  endif
1feee8
 	VZEROUPPER_RETURN
1feee8
 # endif
1feee8