From a56ee40b176d0a3f47f2a7eb75208f2e3763c9fd Mon Sep 17 00:00:00 2001 From: Will Newton Date: Thu, 10 Oct 2013 13:17:13 +0100 Subject: [PATCH] malloc: Fix for infinite loop in memalign/posix_memalign. A very large alignment argument passed to mealign/posix_memalign causes _int_memalign to enter an infinite loop. Limit the maximum alignment value to the maximum representable power of two to prevent this from happening. Changelog: 2013-10-30 Will Newton [BZ #16038] * malloc/hooks.c (memalign_check): Limit alignment to the maximum representable power of two. * malloc/malloc.c (__libc_memalign): Likewise. * malloc/tst-memalign.c (do_test): Add test for very large alignment values. * malloc/tst-posix_memalign.c (do_test): Likewise. --- ChangeLog | 10 ++++++++++ malloc/hooks.c | 8 ++++++++ malloc/malloc.c | 8 ++++++++ malloc/tst-memalign.c | 15 +++++++++++++++ malloc/tst-posix_memalign.c | 10 ++++++++++ 5 files changed, 51 insertions(+) diff --git a/ChangeLog b/ChangeLog index 44448684d8d..4d7a9513c7a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2013-10-30 Will Newton + + [BZ #16038] + * malloc/hooks.c (memalign_check): Limit alignment to the + maximum representable power of two. + * malloc/malloc.c (__libc_memalign): Likewise. + * malloc/tst-memalign.c (do_test): Add test for very + large alignment values. + * malloc/tst-posix_memalign.c (do_test): Likewise. + 2013-10-30 Ondřej Bílka [BZ #11087] diff --git a/malloc/hooks.c b/malloc/hooks.c index 3f663bb6b2e..1dbe93f383b 100644 --- a/malloc/hooks.c +++ b/malloc/hooks.c @@ -361,6 +361,14 @@ memalign_check(size_t alignment, size_t bytes, const void *caller) if (alignment <= MALLOC_ALIGNMENT) return malloc_check(bytes, NULL); if (alignment < MINSIZE) alignment = MINSIZE; + /* If the alignment is greater than SIZE_MAX / 2 + 1 it cannot be a + power of 2 and will cause overflow in the check below. */ + if (alignment > SIZE_MAX / 2 + 1) + { + __set_errno (EINVAL); + return 0; + } + /* Check for overflow. */ if (bytes > SIZE_MAX - alignment - MINSIZE) { diff --git a/malloc/malloc.c b/malloc/malloc.c index 79025b16d92..29796fe4618 100644 --- a/malloc/malloc.c +++ b/malloc/malloc.c @@ -3016,6 +3016,14 @@ __libc_memalign(size_t alignment, size_t bytes) /* Otherwise, ensure that it is at least a minimum chunk size */ if (alignment < MINSIZE) alignment = MINSIZE; + /* If the alignment is greater than SIZE_MAX / 2 + 1 it cannot be a + power of 2 and will cause overflow in the check below. */ + if (alignment > SIZE_MAX / 2 + 1) + { + __set_errno (EINVAL); + return 0; + } + /* Check for overflow. */ if (bytes > SIZE_MAX - alignment - MINSIZE) { diff --git a/malloc/tst-memalign.c b/malloc/tst-memalign.c index 1c597524832..cf48e7ed1fc 100644 --- a/malloc/tst-memalign.c +++ b/malloc/tst-memalign.c @@ -70,6 +70,21 @@ do_test (void) free (p); + errno = 0; + + /* Test to expose integer overflow in malloc internals from BZ #16038. */ + p = memalign (-1, pagesize); + + save = errno; + + if (p != NULL) + merror ("memalign (-1, pagesize) succeeded."); + + if (p == NULL && save != EINVAL) + merror ("memalign (-1, pagesize) errno is not set correctly"); + + free (p); + /* A zero-sized allocation should succeed with glibc, returning a non-NULL value. */ p = memalign (sizeof (void *), 0); diff --git a/malloc/tst-posix_memalign.c b/malloc/tst-posix_memalign.c index 27c0dd2bd40..7f34e37bd2b 100644 --- a/malloc/tst-posix_memalign.c +++ b/malloc/tst-posix_memalign.c @@ -65,6 +65,16 @@ do_test (void) p = NULL; + /* Test to expose integer overflow in malloc internals from BZ #16038. */ + ret = posix_memalign (&p, -1, pagesize); + + if (ret != EINVAL) + merror ("posix_memalign (&p, -1, pagesize) succeeded."); + + free (p); + + p = NULL; + /* A zero-sized allocation should succeed with glibc, returning zero and setting p to a non-NULL value. */ ret = posix_memalign (&p, sizeof (void *), 0); -- 2.39.2