[Toybox] xmemcmp()

Ray Gardner raygard at gmail.com
Sun Jan 1 16:06:22 PST 2023


Some questions and comments on the memcmp() issue from the 2022-12-23
notes.html entry.

I suspect that memcmp("a", "abc", 4); is a simplified version of the actual
case that caused an issue with ASAN. What was the actual case like? Was
part of either buffer in unallocated memory? If so, could that memory be
accessed in some other scenario?

xmemcmp() doesn't do the same thing as memcmp(). memcmp() compares char as
unsigned, and xmemcmp uses plain char *, so if plain char is signed by
default, xmemcmp will return the opposite "sense" from memcmp for e.g.
xmemcmp("0xF0", "a", 2). Easy fix is to use

  while (len--) if ((ii = *(unsigned char *)one++ - *(unsigned char
*)two++)) break;

It appears memcmp() is only used for equality testing now, but if you leave
xmemcmp() unchanged it could cause trouble later if it's used for
less/equal/greater comparison.

As for ASAN, you can disable the catching of memcmp. I know nothing of
toybox or linux or ASAN, so I may be off base here, but here's my testing:

// xwraptest.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// ASAN flips out about memcmp("a", "abc", 4) but the result is
well-defined.
// This one's guaranteed to stop at len _or_ the first difference.
int xmemcmp(char *one, char *two, unsigned long len)
{
  int ii = 0;

  while (len--) if ((ii = *(unsigned char*)one++ - *(unsigned char*)two++))
break;

  return ii;
}

int main()
{
    char *a = strdup("a");
    char *b = strdup("abc");
    printf("memcmp(a, b, 4):  %d\n", memcmp(a, b, 4));
    printf("xmemcmp(a, b, 4): %d\n", xmemcmp(a, b, 4));
    free(a);
    free(b);
    return 0;
}

Then, in WSL Ubuntu:
ray at radon:/mnt/e/r/toybox/z$ gcc xwraptest.c -Wall -Wextra -o foo
-fsanitize=address -g
ray at radon:/mnt/e/r/toybox/z$
ASAN_OPTIONS=intercept_memcmp=0:strict_memcmp=0 ./foo
memcmp(a, b, 4):  -1
xmemcmp(a, b, 4): -98
ray at radon:/mnt/e/r/toybox/z$
ASAN_OPTIONS=intercept_memcmp=1:strict_memcmp=0 ./foo
memcmp(a, b, 4):  -1
xmemcmp(a, b, 4): -98
ray at radon:/mnt/e/r/toybox/z$
ASAN_OPTIONS=intercept_memcmp=1:strict_memcmp=1 ./foo
=================================================================
==583==ERROR: AddressSanitizer: heap-buffer-overflow on address
0x602000000012 at pc 0x7fd32d66cd00 bp 0x7ffc7af61e80 sp 0x7ffc7af61628
[... more error info ...]

No ASAN memcmp testing is done if intercept_memcmp is 0. Not sure if
turning off strict_memcmp will shut up the error you encountered, but it
does for the case above. You can also compile the options into the source
(see https://github.com/google/sanitizers/wiki/AddressSanitizerFlags), e.g.:

const char *__asan_default_options() {
  return "intercept_memcmp=1:strict_memcmp=0";
}

ASAN may be overly paranoid with strict_memcmp, but I think it's looking
(with strict) to see if any of the two buffers fall in unallocated (or even
just uninitialized? how would it know?) memory.

Here's an interesting anecdote about accessing allocated but uninitialized
memory: https://youtu.be/kPR8h4-qZdk?t=1144 (The whole talk is interesting
even if you don't do C++.) (I don't either.)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.landley.net/pipermail/toybox-landley.net/attachments/20230101/cbea4dec/attachment.htm>


More information about the Toybox mailing list