Skip to content
This repository was archived by the owner on May 21, 2019. It is now read-only.

Commit 77afdbc

Browse files
author
Kostya Kortchinsky
committed
[scudo] Check for pvalloc overflow
Summary: Previously we were rounding up the size passed to `pvalloc` to the next multiple of page size no matter what. There is an overflow possibility that wasn't accounted for. So now, return null in the event of an overflow. The man page doesn't seem to indicate the errno to set in this particular situation, but the glibc unit tests go for ENOMEM (https://code.woboq.org/userspace/glibc/malloc/tst-pvalloc.c.html#54) so we'll do the same. Update the aligned allocation funtions tests to check for properly aligned returned pointers, and the `pvalloc` corner cases. @alekseyshl: do you want me to do the same in the other Sanitizers? Reviewers: alekseyshl Reviewed By: alekseyshl Subscribers: kubamracek, alekseyshl, llvm-commits Differential Revision: https://reviews.llvm.org/D35818 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@309033 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 2295a0e commit 77afdbc

File tree

4 files changed

+80
-7
lines changed

4 files changed

+80
-7
lines changed

lib/sanitizer_common/sanitizer_allocator_checks.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@ INLINE bool CheckForCallocOverflow(uptr size, uptr n) {
5959
return (max / size) < n;
6060
}
6161

62+
// Returns true if the size passed to pvalloc overflows when rounded to the next
63+
// multiple of page_size.
64+
INLINE bool CheckForPvallocOverflow(uptr size, uptr page_size) {
65+
return RoundUpTo(size, page_size) < size;
66+
}
67+
6268
} // namespace __sanitizer
6369

6470
#endif // SANITIZER_ALLOCATOR_CHECKS_H

lib/scudo/scudo_allocator.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -665,6 +665,10 @@ void *scudoValloc(uptr Size) {
665665

666666
void *scudoPvalloc(uptr Size) {
667667
uptr PageSize = GetPageSizeCached();
668+
if (UNLIKELY(CheckForPvallocOverflow(Size, PageSize))) {
669+
errno = errno_ENOMEM;
670+
return ScudoAllocator::FailureHandler::OnBadRequest();
671+
}
668672
// pvalloc(0) should allocate one page.
669673
Size = Size ? RoundUpTo(Size, PageSize) : PageSize;
670674
return SetErrnoOnNull(Instance.allocate(Size, PageSize, FromMemalign));

test/scudo/memalign.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,13 @@
88
#include <assert.h>
99
#include <errno.h>
1010
#include <malloc.h>
11+
#include <stdint.h>
1112
#include <stdlib.h>
1213
#include <string.h>
13-
14-
// Reduce the size of the quarantine, or the test can run out of aligned memory
15-
// on 32-bit for the larger alignments.
16-
extern "C" const char *__scudo_default_options() {
17-
return "QuarantineSizeMb=1";
18-
}
14+
#include <unistd.h>
1915

2016
// Sometimes the headers may not have this...
21-
extern "C" void *aligned_alloc (size_t alignment, size_t size);
17+
extern "C" void *aligned_alloc(size_t alignment, size_t size);
2218

2319
int main(int argc, char **argv)
2420
{
@@ -32,9 +28,11 @@ int main(int argc, char **argv)
3228
if (!strcmp(argv[1], "valid")) {
3329
posix_memalign(&p, alignment, size);
3430
assert(p);
31+
assert(((uintptr_t)p & (alignment - 1)) == 0);
3532
free(p);
3633
p = aligned_alloc(alignment, size);
3734
assert(p);
35+
assert(((uintptr_t)p & (alignment - 1)) == 0);
3836
free(p);
3937
// Tests various combinations of alignment and sizes
4038
for (int i = (sizeof(void *) == 4) ? 3 : 4; i < 19; i++) {
@@ -44,6 +42,7 @@ int main(int argc, char **argv)
4442
for (int k = 0; k < 3; k++) {
4543
p = memalign(alignment, size - (2 * sizeof(void *) * k));
4644
assert(p);
45+
assert(((uintptr_t)p & (alignment - 1)) == 0);
4746
free(p);
4847
}
4948
}
@@ -54,6 +53,7 @@ int main(int argc, char **argv)
5453
for (int k = 0; k < 3; k++) {
5554
p = memalign(alignment, 0x1000 - (2 * sizeof(void *) * k));
5655
assert(p);
56+
assert(((uintptr_t)p & (alignment - 1)) == 0);
5757
free(p);
5858
}
5959
}

test/scudo/valloc.cpp

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// RUN: %clang_scudo %s -o %t
2+
// RUN: %run %t valid 2>&1
3+
// RUN: %run %t invalid 2>&1
4+
5+
// Tests that valloc and pvalloc work as intended.
6+
7+
#include <assert.h>
8+
#include <errno.h>
9+
#include <malloc.h>
10+
#include <stdint.h>
11+
#include <string.h>
12+
#include <unistd.h>
13+
14+
size_t round_up_to(size_t size, size_t alignment) {
15+
return (size + alignment - 1) & ~(alignment - 1);
16+
}
17+
18+
int main(int argc, char **argv)
19+
{
20+
void *p = nullptr;
21+
size_t size, page_size;
22+
23+
assert(argc == 2);
24+
25+
page_size = sysconf(_SC_PAGESIZE);
26+
// Check that the page size is a power of two.
27+
assert((page_size & (page_size - 1)) == 0);
28+
29+
if (!strcmp(argv[1], "valid")) {
30+
for (int i = (sizeof(void *) == 4) ? 3 : 4; i < 21; i++) {
31+
size = 1U << i;
32+
p = valloc(size - (2 * sizeof(void *)));
33+
assert(p);
34+
assert(((uintptr_t)p & (page_size - 1)) == 0);
35+
free(p);
36+
p = pvalloc(size - (2 * sizeof(void *)));
37+
assert(p);
38+
assert(((uintptr_t)p & (page_size - 1)) == 0);
39+
assert(malloc_usable_size(p) >= round_up_to(size, page_size));
40+
free(p);
41+
p = valloc(size);
42+
assert(p);
43+
assert(((uintptr_t)p & (page_size - 1)) == 0);
44+
free(p);
45+
p = pvalloc(size);
46+
assert(p);
47+
assert(((uintptr_t)p & (page_size - 1)) == 0);
48+
assert(malloc_usable_size(p) >= round_up_to(size, page_size));
49+
free(p);
50+
}
51+
}
52+
if (!strcmp(argv[1], "invalid")) {
53+
// Size passed to pvalloc overflows when rounded up.
54+
p = pvalloc((size_t)-1);
55+
assert(!p);
56+
assert(errno == ENOMEM);
57+
errno = 0;
58+
p = pvalloc((size_t)-page_size);
59+
assert(!p);
60+
assert(errno == ENOMEM);
61+
}
62+
return 0;
63+
}

0 commit comments

Comments
 (0)