[PATCH v12 08/31] string: Improve generic strncmp

Szabolcs Nagy szabolcs.nagy@arm.com
Tue Feb 21 09:28:00 GMT 2023


The 02/02/2023 15:11, Adhemerval Zanella via Libc-alpha wrote:
> It follows the strategy:
> 
>    - Align the first input to word boundary using byte operations.
> 
>    - If second input is also word aligned, read a word per time, check
>      for  null (using has_zero), and check final words using byte
>      operation.
> 
>    - If second input is not word aligned, loop by aligning the source,
>      and merge the result of two reads.  Similar to aligned case, check
>      for null with has_zero, and check final words using byte operation.
> 
> 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).

on arm i see

FAIL: crypt/badsalttest

Program received signal SIGSEGV, Segmentation fault.
strncmp_unaligned_loop (n=3, ofs=<optimized out>, w1=2371876, x2=0xf7feb000, x1=0xf7f6563c) at strncmp.c:85
85                w2b = *x2++;

this strncmp does out of bounds read:

Breakpoint 2, __GI_strncmp (p1=0xf7f65638 <md5_salt_prefix> "$1$", p2=p2@entry=0xf7feafff "*", n=n@entry=3) at strncmp.c:115

0xf7feb000 is mapped PROT_NONE.

> +strncmp_unaligned_loop (const op_t *x1, const op_t *x2, op_t w1, uintptr_t ofs,
> +			size_t n)
> +{
> +  op_t w2a = *x2++;
> +  uintptr_t sh_1 = ofs * CHAR_BIT;
> +  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))
>      {
> -      c1 = (unsigned char) *s1++;
> -      c2 = (unsigned char) *s2++;
> -      if (c1 == '\0' || c1 != c2)
> -	return c1 - c2;
> -      n--;
> +      op_t w2b;
> +
> +      /* Unaligned loop.  The invariant is that W2B, which is "ahead" of W1,
> +	 does not contain end-of-string.  Therefore it is safe (and necessary)
> +	 to read another word from each while we do not have a difference.  */
> +      while (1)
> +	{
> +	  w2b = *x2++;
^^^^^^^^^^^^^^^^^^^^^^

reading ahead is wrong if w1 and w2 already mismatches.

> +	  w2 = MERGE (w2a, sh_1, w2b, sh_2);
> +	  if (n <= sizeof (op_t) || w1 != w2)
> +	    return final_cmp (w1, w2, n);
> +	  n -= sizeof(op_t);
> +	  if (has_zero (w2b) || n <= (sizeof (op_t) - ofs))
> +	    break;
> +	  w1 = *x1++;
> +	  w2a = w2b;
> +	}
> +
> +      /* Zero found in the second partial of P2.  If we had EOS in the aligned
> +	 word, we have equality.  */
> +      if (has_zero (w1))
> +	return 0;
> +
> +      /* Load the final word of P1 and align the final partial of P2.  */
> +      w1 = *x1++;
> +      w2 = MERGE (w2b, sh_1, 0, sh_2);
>      }
>  
> -  return c1 - c2;
> +  return final_cmp (w1, w2, n);


More information about the Libc-alpha mailing list