x86-64 memchr/wmemchr: Properly handle the length parameter [BZ #24097]

On x32, the size_t parameter may be passed in the lower 32 bits of a
64-bit register with the non-zero upper 32 bits.  The string/memory
functions written in assembly can only use the lower 32 bits of a
64-bit register as length or must clear the upper 32 bits before using
the full 64-bit register for length.

This pach fixes memchr/wmemchr for x32.  Tested on x86-64 and x32.  On
x86-64, libc.so is the same with and withou the fix.

	[BZ #24097]
	CVE-2019-6488
	* sysdeps/x86_64/memchr.S: Use RDX_LP for length.  Clear the
	upper 32 bits of RDX register.
	* sysdeps/x86_64/multiarch/memchr-avx2.S: Likewise.
	* sysdeps/x86_64/x32/Makefile (tests): Add tst-size_t-memchr and
	tst-size_t-wmemchr.
	* sysdeps/x86_64/x32/test-size_t.h: New file.
	* sysdeps/x86_64/x32/tst-size_t-memchr.c: Likewise.
	* sysdeps/x86_64/x32/tst-size_t-wmemchr.c: Likewise.

(cherry picked from commit 97700a34f3)
This commit is contained in:
H.J. Lu 2019-02-01 12:17:09 -08:00
parent b297581acb
commit 492524a691
8 changed files with 169 additions and 5 deletions

View File

@ -1,3 +1,16 @@
2019-02-01 H.J. Lu <hongjiu.lu@intel.com>
[BZ #24097]
CVE-2019-6488
* sysdeps/x86_64/memchr.S: Use RDX_LP for length. Clear the
upper 32 bits of RDX register.
* sysdeps/x86_64/multiarch/memchr-avx2.S: Likewise.
* sysdeps/x86_64/x32/Makefile (tests): Add tst-size_t-memchr and
tst-size_t-wmemchr.
* sysdeps/x86_64/x32/test-size_t.h: New file.
* sysdeps/x86_64/x32/tst-size_t-memchr.c: Likewise.
* sysdeps/x86_64/x32/tst-size_t-wmemchr.c: Likewise.
2019-01-16 Tulio Magno Quites Machado Filho <tuliom@linux.ibm.com> 2019-01-16 Tulio Magno Quites Machado Filho <tuliom@linux.ibm.com>
* math/libm-test-fma.inc (fma_test_data): Set * math/libm-test-fma.inc (fma_test_data): Set

8
NEWS
View File

@ -34,12 +34,20 @@ The following bugs are resolved with this release:
[24024] strerror() might set errno to ENOMEM due to -fno-math-error [24024] strerror() might set errno to ENOMEM due to -fno-math-error
[24027] malloc: Integer overflow in realloc [24027] malloc: Integer overflow in realloc
[24034] tst-cancel21-static fails with SIGBUS on pre-ARMv7 when using GCC 8 [24034] tst-cancel21-static fails with SIGBUS on pre-ARMv7 when using GCC 8
[24097] Can't use 64-bit register for size_t in assembly codes for x32 (CVE-2019-6488)
Security related changes: Security related changes:
CVE-2018-19591: A file descriptor leak in if_nametoindex can lead to a CVE-2018-19591: A file descriptor leak in if_nametoindex can lead to a
denial of service due to resource exhaustion when processing getaddrinfo denial of service due to resource exhaustion when processing getaddrinfo
calls with crafted host names. Reported by Guido Vranken. calls with crafted host names. Reported by Guido Vranken.
CVE-2019-6488: On x32, the size_t parameter may be passed in the lower
32 bits of a 64-bit register with with non-zero upper 32 bit. When it
happened, accessing the 32-bit size_t value as the full 64-bit register
in the assembly string/memory functions would cause a buffer overflow.
Reported by H.J. Lu.
Version 2.28 Version 2.28

View File

@ -34,12 +34,16 @@ ENTRY(MEMCHR)
mov %edi, %ecx mov %edi, %ecx
#ifdef USE_AS_WMEMCHR #ifdef USE_AS_WMEMCHR
test %rdx, %rdx test %RDX_LP, %RDX_LP
jz L(return_null) jz L(return_null)
shl $2, %rdx shl $2, %RDX_LP
#else #else
# ifdef __ILP32__
/* Clear the upper 32 bits. */
movl %edx, %edx
# endif
punpcklbw %xmm1, %xmm1 punpcklbw %xmm1, %xmm1
test %rdx, %rdx test %RDX_LP, %RDX_LP
jz L(return_null) jz L(return_null)
punpcklbw %xmm1, %xmm1 punpcklbw %xmm1, %xmm1
#endif #endif

View File

@ -40,16 +40,20 @@
ENTRY (MEMCHR) ENTRY (MEMCHR)
# ifndef USE_AS_RAWMEMCHR # ifndef USE_AS_RAWMEMCHR
/* Check for zero length. */ /* Check for zero length. */
testq %rdx, %rdx test %RDX_LP, %RDX_LP
jz L(null) jz L(null)
# endif # endif
movl %edi, %ecx movl %edi, %ecx
/* Broadcast CHAR to YMM0. */ /* Broadcast CHAR to YMM0. */
vmovd %esi, %xmm0 vmovd %esi, %xmm0
# ifdef USE_AS_WMEMCHR # ifdef USE_AS_WMEMCHR
shl $2, %rdx shl $2, %RDX_LP
vpbroadcastd %xmm0, %ymm0 vpbroadcastd %xmm0, %ymm0
# else # else
# ifdef __ILP32__
/* Clear the upper 32 bits. */
movl %edx, %edx
# endif
vpbroadcastb %xmm0, %ymm0 vpbroadcastb %xmm0, %ymm0
# endif # endif
/* Check if we may cross page boundary with one vector load. */ /* Check if we may cross page boundary with one vector load. */

View File

@ -4,3 +4,11 @@ ifeq ($(subdir),math)
# 64-bit llround. Add -fno-builtin-lround to silence the compiler. # 64-bit llround. Add -fno-builtin-lround to silence the compiler.
CFLAGS-s_llround.c += -fno-builtin-lround CFLAGS-s_llround.c += -fno-builtin-lround
endif endif
ifeq ($(subdir),string)
tests += tst-size_t-memchr
endif
ifeq ($(subdir),wcsmbs)
tests += tst-size_t-wmemchr
endif

View File

@ -0,0 +1,35 @@
/* Test string/memory functions with size_t in the lower 32 bits of
64-bit register.
Copyright (C) 2019 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
#define TEST_MAIN
#include <string/test-string.h>
/* On x32, parameter_t may be passed in a 64-bit register with the LEN
field in the lower 32 bits. When the LEN field of 64-bit register
is passed to string/memory function as the size_t parameter, only
the lower 32 bits can be used. */
typedef struct
{
union
{
size_t len;
void (*fn) (void);
};
void *p;
} parameter_t;

View File

@ -0,0 +1,72 @@
/* Test memchr with size_t in the lower 32 bits of 64-bit register.
Copyright (C) 2019 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
#ifndef WIDE
# define TEST_NAME "memchr"
#else
# define TEST_NAME "wmemchr"
#endif /* WIDE */
#include "test-size_t.h"
#ifndef WIDE
# define MEMCHR memchr
# define CHAR char
# define UCHAR unsigned char
#else
# include <wchar.h>
# define MEMCHR wmemchr
# define CHAR wchar_t
# define UCHAR wchar_t
#endif /* WIDE */
IMPL (MEMCHR, 1)
typedef CHAR * (*proto_t) (const CHAR*, int, size_t);
static CHAR *
__attribute__ ((noinline, noclone))
do_memchr (parameter_t a, parameter_t b)
{
return CALL (&b, a.p, (uintptr_t) b.p, a.len);
}
static int
test_main (void)
{
test_init ();
parameter_t src = { { page_size / sizeof (CHAR) }, buf2 };
parameter_t c = { { 0 }, (void *) (uintptr_t) 0x12 };
int ret = 0;
FOR_EACH_IMPL (impl, 0)
{
c.fn = impl->fn;
CHAR *res = do_memchr (src, c);
if (res)
{
error (0, 0, "Wrong result in function %s: %p != NULL",
impl->name, res);
ret = 1;
}
}
return ret ? EXIT_FAILURE : EXIT_SUCCESS;
}
#include <support/test-driver.c>

View File

@ -0,0 +1,20 @@
/* Test wmemchr with size_t in the lower 32 bits of 64-bit register.
Copyright (C) 2019 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
#define WIDE 1
#include "tst-size_t-memchr.c"