mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-23 17:53:37 +08:00
x86-64 memcmp: Use unsigned Jcc instructions on size [BZ #24155]
Since the size argument is unsigned. we should use unsigned Jcc
instructions, instead of signed, to check size.
Tested on x86-64 and x32, with and without --disable-multi-arch.
[BZ #24155]
CVE-2019-7309
* NEWS: Updated for CVE-2019-7309.
* sysdeps/x86_64/memcmp.S: Use RDX_LP for size. Clear the
upper 32 bits of RDX register for x32. Use unsigned Jcc
instructions, instead of signed.
* sysdeps/x86_64/x32/Makefile (tests): Add tst-size_t-memcmp-2.
* sysdeps/x86_64/x32/tst-size_t-memcmp-2.c: New test.
(cherry picked from commit 3f635fb433
)
This commit is contained in:
parent
86013ef5ce
commit
726a78867b
11
ChangeLog
11
ChangeLog
@ -1,3 +1,14 @@
|
||||
2019-02-04 H.J. Lu <hongjiu.lu@intel.com>
|
||||
|
||||
[BZ #24155]
|
||||
CVE-2019-7309
|
||||
* NEWS: Updated for CVE-2019-7309.
|
||||
* sysdeps/x86_64/memcmp.S: Use RDX_LP for size. Clear the
|
||||
upper 32 bits of RDX register for x32. Use unsigned Jcc
|
||||
instructions, instead of signed.
|
||||
* sysdeps/x86_64/x32/Makefile (tests): Add tst-size_t-memcmp-2.
|
||||
* sysdeps/x86_64/x32/tst-size_t-memcmp-2.c: New test.
|
||||
|
||||
2019-01-31 Carlos O'Donell <carlos@redhat.com>
|
||||
Torvald Riegel <triegel@redhat.com>
|
||||
Rik Prohaska <prohaska7@gmail.com>
|
||||
|
17
NEWS
17
NEWS
@ -4,6 +4,23 @@ See the end for copying conditions.
|
||||
|
||||
Please send GNU C library bug reports via <https://sourceware.org/bugzilla/>
|
||||
using `glibc' in the "product" field.
|
||||
|
||||
Version 2.29.1
|
||||
|
||||
The following bugs are resolved with this release:
|
||||
|
||||
[24155] x32 memcmp can treat positive length as 0 (if sign bit in RDX is set) (CVE-2019-7309)
|
||||
|
||||
Security related changes:
|
||||
|
||||
CVE-2019-7309: x86-64 memcmp used signed Jcc instructions to check
|
||||
size. For x86-64, memcmp on an object size larger than SSIZE_MAX
|
||||
has undefined behavior. On x32, the size_t argument may be passed
|
||||
in the lower 32 bits of the 64-bit RDX register with non-zero upper
|
||||
32 bits. When it happened with the sign bit of RDX register set,
|
||||
memcmp gave the wrong result since it treated the size argument as
|
||||
zero. Reported by H.J. Lu.
|
||||
|
||||
|
||||
Version 2.29
|
||||
|
||||
|
@ -21,14 +21,18 @@
|
||||
|
||||
.text
|
||||
ENTRY (memcmp)
|
||||
test %rdx, %rdx
|
||||
#ifdef __ILP32__
|
||||
/* Clear the upper 32 bits. */
|
||||
movl %edx, %edx
|
||||
#endif
|
||||
test %RDX_LP, %RDX_LP
|
||||
jz L(finz)
|
||||
cmpq $1, %rdx
|
||||
jle L(finr1b)
|
||||
jbe L(finr1b)
|
||||
subq %rdi, %rsi
|
||||
movq %rdx, %r10
|
||||
cmpq $32, %r10
|
||||
jge L(gt32)
|
||||
jae L(gt32)
|
||||
/* Handle small chunks and last block of less than 32 bytes. */
|
||||
L(small):
|
||||
testq $1, %r10
|
||||
@ -156,7 +160,7 @@ L(A32):
|
||||
movq %r11, %r10
|
||||
andq $-32, %r10
|
||||
cmpq %r10, %rdi
|
||||
jge L(mt16)
|
||||
jae L(mt16)
|
||||
/* Pre-unroll to be ready for unrolled 64B loop. */
|
||||
testq $32, %rdi
|
||||
jz L(A64)
|
||||
@ -178,7 +182,7 @@ L(A64):
|
||||
movq %r11, %r10
|
||||
andq $-64, %r10
|
||||
cmpq %r10, %rdi
|
||||
jge L(mt32)
|
||||
jae L(mt32)
|
||||
|
||||
L(A64main):
|
||||
movdqu (%rdi,%rsi), %xmm0
|
||||
@ -216,7 +220,7 @@ L(mt32):
|
||||
movq %r11, %r10
|
||||
andq $-32, %r10
|
||||
cmpq %r10, %rdi
|
||||
jge L(mt16)
|
||||
jae L(mt16)
|
||||
|
||||
L(A32main):
|
||||
movdqu (%rdi,%rsi), %xmm0
|
||||
@ -254,7 +258,7 @@ L(ATR):
|
||||
movq %r11, %r10
|
||||
andq $-32, %r10
|
||||
cmpq %r10, %rdi
|
||||
jge L(mt16)
|
||||
jae L(mt16)
|
||||
testq $16, %rdi
|
||||
jz L(ATR32)
|
||||
|
||||
@ -325,7 +329,7 @@ L(ATR64main):
|
||||
movq %r11, %r10
|
||||
andq $-32, %r10
|
||||
cmpq %r10, %rdi
|
||||
jge L(mt16)
|
||||
jae L(mt16)
|
||||
|
||||
L(ATR32res):
|
||||
movdqa (%rdi,%rsi), %xmm0
|
||||
|
@ -8,7 +8,8 @@ endif
|
||||
ifeq ($(subdir),string)
|
||||
tests += tst-size_t-memchr tst-size_t-memcmp tst-size_t-memcpy \
|
||||
tst-size_t-memrchr tst-size_t-memset tst-size_t-strncasecmp \
|
||||
tst-size_t-strncmp tst-size_t-strncpy tst-size_t-strnlen
|
||||
tst-size_t-strncmp tst-size_t-strncpy tst-size_t-strnlen \
|
||||
tst-size_t-memcmp-2
|
||||
endif
|
||||
|
||||
ifeq ($(subdir),wcsmbs)
|
||||
|
79
sysdeps/x86_64/x32/tst-size_t-memcmp-2.c
Normal file
79
sysdeps/x86_64/x32/tst-size_t-memcmp-2.c
Normal file
@ -0,0 +1,79 @@
|
||||
/* Test memcmp 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
|
||||
#ifdef WIDE
|
||||
# define TEST_NAME "wmemcmp"
|
||||
#else
|
||||
# define TEST_NAME "memcmp"
|
||||
#endif
|
||||
|
||||
#include "test-size_t.h"
|
||||
|
||||
#ifdef WIDE
|
||||
# include <inttypes.h>
|
||||
# include <wchar.h>
|
||||
|
||||
# define MEMCMP wmemcmp
|
||||
# define CHAR wchar_t
|
||||
#else
|
||||
# define MEMCMP memcmp
|
||||
# define CHAR char
|
||||
#endif
|
||||
|
||||
IMPL (MEMCMP, 1)
|
||||
|
||||
typedef int (*proto_t) (const CHAR *, const CHAR *, size_t);
|
||||
|
||||
static int
|
||||
__attribute__ ((noinline, noclone))
|
||||
do_memcmp (parameter_t a, parameter_t b)
|
||||
{
|
||||
return CALL (&b, a.p, b.p, a.len);
|
||||
}
|
||||
|
||||
static int
|
||||
test_main (void)
|
||||
{
|
||||
test_init ();
|
||||
|
||||
parameter_t dest = { { page_size / sizeof (CHAR) }, buf1 };
|
||||
parameter_t src = { { 0 }, buf2 };
|
||||
|
||||
memcpy (buf1, buf2, page_size);
|
||||
|
||||
CHAR *p = (CHAR *) buf1;
|
||||
p[page_size / sizeof (CHAR) - 1] = (CHAR) 1;
|
||||
|
||||
int ret = 0;
|
||||
FOR_EACH_IMPL (impl, 0)
|
||||
{
|
||||
src.fn = impl->fn;
|
||||
int res = do_memcmp (dest, src);
|
||||
if (res >= 0)
|
||||
{
|
||||
error (0, 0, "Wrong result in function %s: %i >= 0",
|
||||
impl->name, res);
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return ret ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
Loading…
Reference in New Issue
Block a user