public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
* Re: [PATCH v2] string: Fix OOB read on generic strncmp
@ 2023-02-24 12:24 Wilco Dijkstra
  2023-02-24 12:34 ` Adhemerval Zanella Netto
  2023-02-24 12:43 ` Szabolcs Nagy
  0 siblings, 2 replies; 10+ messages in thread
From: Wilco Dijkstra @ 2023-02-24 12:24 UTC (permalink / raw)
  To: Florian Weimer, Adhemerval Zanella, Szabolcs Nagy; +Cc: 'GNU C Library'

Hi,

> It's common to use strncmp as a starts-with predicate, like this:
>
>  strncmp (s, "prefix", 5)
>
> This requires that reading stops at the first null byte.  C11 wording
> makes this kind of usage inadvisable because it treats the inputs as
> arrays, and this means that mean that implementations could read past
> the null byte.  But that doesn't match current programming practice.

C11 says you can't read past the end of the array, but it doesn't say that
you *must* read past a NUL-byte. My interpretation is that this is a valid
strncmp implementation:

int
simple_strncmp (const char *s1, const char *s2, size_t size)
{
   size_t len1 = strnlen (s1, size);
   size_t len2 = strnlen (s2, size);
   if (len1 < len2)
     len1++;
   else if (len1 > len2)
     len1 = len2 + 1;
   return memcmp (s1, s2, len1);
}

Ie. both strings must be valid up until the given size or NUL-terminated if
smaller. This works on the example above even if the first string is only 1 byte.

> The strnlen function has the same problem if you want to use it to limit
> readhead, e.g. in sscanf to fix bug 17577.  (POSIX also speaks of an
> array argument.)  In stdio-common/Xprintf_buffer_puts_1.c, we already
> use it to avoid a similar performance glitch.  It's not the first such
> uses, there is already a similar call (with similar rationale) in
> string/strcasestr.c, and for wcsnlen in
> stdio-common/vfprintf-process-arg.c.
>
> I think we should support all these as extensions.  The alternative
> would be to add new functions that stop reading after the first null
> byte (particularly for the strnlen optimization).

Existing functions already do stop after the first NUL byte. Even if the C
standard doesn't explicitly disallow it, it doesn't seem valid to read beyond
it (a lot of code could fail if we did).

Cheers,
Wilco

^ permalink raw reply	[flat|nested] 10+ messages in thread
* Re: [PATCH v2] string: Fix OOB read on generic strncmp
@ 2023-02-23 19:10 Wilco Dijkstra
  0 siblings, 0 replies; 10+ messages in thread
From: Wilco Dijkstra @ 2023-02-23 19:10 UTC (permalink / raw)
  To: Adhemerval Zanella; +Cc: 'GNU C Library'

Hi Adhemerval,

What kind of readahead are you trying to test/fix here? It's not clear from the
patch... So with strcmp you can safely call strlen on either input, and similarly I
believe you can call strnlen on both inputs of strncmp without getting a crash.
That means it is possible to read ahead as long as you never read past a zero
byte or past the given size.

If you couldn't read even a single byte past the first mismatch it would be hard
to create efficient implementations, especially with wide vectors...

Cheers,
Wilco

^ permalink raw reply	[flat|nested] 10+ messages in thread
* [PATCH v2] string: Fix OOB read on generic strncmp
@ 2023-02-22 16:31 Adhemerval Zanella
  2023-02-22 17:21 ` Szabolcs Nagy
  0 siblings, 1 reply; 10+ messages in thread
From: Adhemerval Zanella @ 2023-02-22 16:31 UTC (permalink / raw)
  To: libc-alpha, Szabolcs Nagy

For unaligned case, reading ahead can only be done if parting reads
matches the aligned input.

Also extend the stratcliff tests to check such cases.

Checked on x86_64-linux-gnu, i686-linux-gnu, powerpc64-linux-gnu,
and powerpc-linux-gnu by removing the arch-specific assembly
implementation and disabling multi-arch (it covers both LE and BE
for 64 and 32 bits).
---
 string/stratcliff.c | 17 ++++++++++++++++-
 string/strncmp.c    | 13 ++++++++++++-
 2 files changed, 28 insertions(+), 2 deletions(-)

diff --git a/string/stratcliff.c b/string/stratcliff.c
index 74d64cc03d..88ac787088 100644
--- a/string/stratcliff.c
+++ b/string/stratcliff.c
@@ -401,12 +401,27 @@ do_test (void)
 		result = 1;
 	      }
 
-	    if (STRNCMP (dest + nchars - outer, adr + middle, outer) <= 0)
+	    /* Also check for size larger than the string.  */
+	    if (STRNCMP (adr + middle, dest + nchars - outer, outer + 99) >= 0)
 	      {
 		printf ("%s 2 flunked for outer = %zu, middle = %zu, full\n",
+			STRINGIFY (STRNCMP), outer + 99, middle);
+		result = 1;
+	      }
+
+	    if (STRNCMP (dest + nchars - outer, adr + middle, outer) <= 0)
+	      {
+		printf ("%s 3 flunked for outer = %zu, middle = %zu, full\n",
 			STRINGIFY (STRNCMP), outer, middle);
 		result = 1;
 	      }
+
+	    if (STRNCMP (dest + nchars - outer, adr + middle, outer + 99) <= 0)
+	      {
+		printf ("%s 4 flunked for outer = %zu, middle = %zu, full\n",
+			STRINGIFY (STRNCMP), outer + 99, middle);
+		result = 1;
+	      }
 	  }
 
       /* strncpy/wcsncpy tests */
diff --git a/string/strncmp.c b/string/strncmp.c
index 4c8bf36bb9..751bf53d55 100644
--- a/string/strncmp.c
+++ b/string/strncmp.c
@@ -73,7 +73,11 @@ strncmp_unaligned_loop (const op_t *x1, const op_t *x2, op_t w1, uintptr_t ofs,
   uintptr_t sh_2 = sizeof(op_t) * CHAR_BIT - sh_1;
 
   op_t w2 = MERGE (w2a, sh_1, (op_t)-1, sh_2);
-  if (!has_zero (w2) && n > (sizeof (op_t) - ofs))
+
+  /* Reading ahead is wrong if w1 and w2 already differs.  */
+  op_t w1a = MERGE (w1, 0, (op_t)-1, sh_2);
+
+  if (!has_zero (w2) && w2 == w1a && n >= (sizeof (op_t) - ofs))
     {
       op_t w2b;
 
@@ -90,6 +94,13 @@ strncmp_unaligned_loop (const op_t *x1, const op_t *x2, op_t w1, uintptr_t ofs,
 	  if (has_zero (w2b) || n <= (sizeof (op_t) - ofs))
 	    break;
 	  w1 = *x1++;
+
+	  /* Reading ahead is wrong if w1 and w2 already differs.  */
+	  w2 = MERGE (w2b, sh_1, (op_t)-1, sh_2);
+	  w1a = MERGE (w1, 0, (op_t)-1, sh_2);
+	  if (w2 != w1a)
+	    return final_cmp (w1a, w2, n);
+
 	  w2a = w2b;
 	}
 
-- 
2.34.1


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2023-02-24 12:57 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-02-24 12:24 [PATCH v2] string: Fix OOB read on generic strncmp Wilco Dijkstra
2023-02-24 12:34 ` Adhemerval Zanella Netto
2023-02-24 12:43 ` Szabolcs Nagy
2023-02-24 12:57   ` Adhemerval Zanella Netto
  -- strict thread matches above, loose matches on Subject: below --
2023-02-23 19:10 Wilco Dijkstra
2023-02-22 16:31 Adhemerval Zanella
2023-02-22 17:21 ` Szabolcs Nagy
2023-02-23 18:15   ` Adhemerval Zanella Netto
2023-02-24 10:19     ` Szabolcs Nagy
2023-02-24 10:58       ` Florian Weimer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).