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