File: mem_test.cc

package info (click to toggle)
chromium-browser 57.0.2987.98-1~deb8u1
  • links: PTS, VCS
  • area: main
  • in suites: jessie
  • size: 2,637,852 kB
  • ctags: 2,544,394
  • sloc: cpp: 12,815,961; ansic: 3,676,222; python: 1,147,112; asm: 526,608; java: 523,212; xml: 286,794; perl: 92,654; sh: 86,408; objc: 73,271; makefile: 27,698; cs: 18,487; yacc: 13,031; tcl: 12,957; pascal: 4,875; ml: 4,716; lex: 3,904; sql: 3,862; ruby: 1,982; lisp: 1,508; php: 1,368; exp: 404; awk: 325; csh: 117; jsp: 39; sed: 37
file content (203 lines) | stat: -rw-r--r-- 7,145 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
/*
 * Copyright (c) 2010 The Native Client Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include <errno.h>
#include <sys/mman.h>

#include <cstdlib>
#include <cstring>

#include "native_client/tests/syscalls/test.h"

namespace {
// Use 64Kb regions in the memory tests.  This is usually a whole number of
// pages.  The 32Kb size is used for certain other failure modes.
const size_t k64Kbytes = 64 * 1024;
const size_t k32Kbytes = 32 * 1024;

// |MAP_ANONYMOUS| expects a filedesc of -1.  While this is not strictly true
// on all systems, portable code should work this way.
const int kAnonymousFiledesc = -1;

// When |MAP_ANONYMOUS| is not specified, any negative file desc should report
// EBADF.
const int kBadFiledesc = -3;

// Try to mmap a 0-length region.  This is expected to fail.
int TestZeroLengthRegion() {
  START_TEST("TestZeroLengthRegion");
  void* mmap_ptr = mmap(NULL,
                        0,
                        PROT_READ,
                        MAP_PRIVATE | MAP_ANONYMOUS,
                        kAnonymousFiledesc,
                        0);
  EXPECT(MAP_FAILED == mmap_ptr);
  EXPECT(EINVAL == errno);
  END_TEST();
}

// Hand in a bad file descriptor, this test is successful if mmap() fails.
// The |MAP_ANONYMOUS| flag is deliberately not used for this test, because
// we are trying to map an actual (but bad) filedesc.
int TestBadFiledesc() {
  START_TEST("TestBadFiledesc");
  void* mmap_ptr = mmap(NULL,
                        k64Kbytes,
                        PROT_READ,
                        MAP_PRIVATE,
                        kBadFiledesc,
                        0);
  EXPECT(MAP_FAILED == mmap_ptr);
  EXPECT(EBADF == errno);
  END_TEST();
}

// Verify that mmap does not fail if a bad hint address is passed, but
// |MMAP_FIXED| is not specified.
int TestMmapBadHint() {
  START_TEST("TestMmapBadHint");
  void* bad_hint = (void *) 0x123;
  void* mmap_ptr = mmap(bad_hint,
                        k64Kbytes,
                        PROT_READ,
                        MAP_PRIVATE | MAP_ANONYMOUS,
                        kAnonymousFiledesc,
                        0);
  EXPECT(MAP_FAILED != mmap_ptr);
  EXPECT(mmap_ptr != bad_hint);
  EXPECT(munmap(mmap_ptr, k64Kbytes) == 0);
  END_TEST();
}

// Verify that mmap does fail if a bad hint address is passed and
// |MMAP_FIXED| is specified.
int TestMmapBadHintFixed() {
  START_TEST("TestMmapBadHintFixed");
  void* bad_hint = (void *) 0x123;
  void* mmap_ptr = mmap(bad_hint,
                        k64Kbytes,
                        PROT_READ,
                        MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
                        kAnonymousFiledesc,
                        0);
  EXPECT(MAP_FAILED == mmap_ptr);
  END_TEST();
}

// Test mmap() and munmap(), since these often to go together.  Tries to mmap
// a 64 Kb region of memory and then tests to make sure that the pages have all
// been 0-filled.
int TestMmapMunmap() {
  START_TEST("TestMmapMunmap");
  void* mmap_ptr = mmap(NULL,
                        k64Kbytes,
                        PROT_READ,
                        MAP_PRIVATE | MAP_ANONYMOUS,
                        kAnonymousFiledesc,
                        0);
  EXPECT(MAP_FAILED != mmap_ptr);
  // Create a zero-filled region on the heap for comparison with the mmaped
  // region.
  void* zeroes = std::malloc(k64Kbytes);
  std::memset(zeroes, 0, k64Kbytes);
  EXPECT(std::memcmp(mmap_ptr, zeroes, k64Kbytes) == 0);
  // Attempt to release the mapped memory.
  EXPECT(munmap(mmap_ptr, k64Kbytes) == 0);
  std::free(zeroes);
  END_TEST();
}

// munmap() of text (executable) pages should fail.
int TestMunmapText() {
  START_TEST("TestMunmapText");
  // Text pages start at 64K for the syscall trampolines.  If this first call
  // to munmap() succeeds, we will get a segfault on the next trampoline usage.
  // In this case, sel_ldr will return a recognizable error code.
  int rv = munmap(reinterpret_cast<void*>(k64Kbytes), k64Kbytes);
  // Note: if the munmap succeeds, this code is probably not running any more.
  EXPECT(rv == -1);
  EXPECT(EINVAL == errno);
  // Untrusted code text starts at 128K.  If this second call to munmap()
  // succeeds, there will be a rapid segfault and sel_ldr will return a
  // recognizable error code.
  rv = munmap(reinterpret_cast<void*>(k64Kbytes*2), k64Kbytes);
  // Note: if the munmap succeeds, this code is probably not running any more.
  EXPECT(rv == -1);
  EXPECT(EINVAL == errno);
  END_TEST();
}

// Verify that mmap into the NULL pointer guard page will fail.  This uses the
// |MAP_FIXED| flag to try an force mmap() to pin the region at NULL.
int TestMmapNULL() {
  START_TEST("TestMmapNULL");
  void *mmap_ptr = mmap(NULL,
                        k64Kbytes,
                        PROT_READ,
                        MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
                        kAnonymousFiledesc,
                        0);
  EXPECT(MAP_FAILED == mmap_ptr);
  EXPECT(EINVAL == errno);
  END_TEST();
}

// Attempt to allocate 32Kb, starting at 32Kb.  This should fail.
int TestMmap32k() {
  START_TEST("TestMmap32k");
  void *mmap_ptr = mmap(reinterpret_cast<void*>(k32Kbytes),
                        k32Kbytes,
                        PROT_READ,
                        MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
                        kAnonymousFiledesc,
                        0);
  EXPECT(MAP_FAILED == mmap_ptr);
  EXPECT(EINVAL == errno);
  END_TEST();
}

// Verify that mmap() with the |MAP_FIXED| flag and a non-page-aligned address
// will fail.
int TestMmapNonPageAligned() {
  START_TEST("TestMmapNonPageAligned");
  // Reserve some legal (page-aligned) address space in which to perform the
  // test.
  char* local_heap = reinterpret_cast<char*>(mmap(NULL,
                                                  k64Kbytes,
                                                  PROT_NONE,
                                                  MAP_PRIVATE | MAP_ANONYMOUS,
                                                  kAnonymousFiledesc,
                                                  0));
  EXPECT(MAP_FAILED != local_heap);

  void* unaligned_ptr = mmap(static_cast<void*>(local_heap + 0x100),
                             k64Kbytes,
                             PROT_READ,
                             MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
                             kAnonymousFiledesc,
                             0);
  EXPECT(MAP_FAILED == unaligned_ptr);
  EXPECT(EINVAL == errno);
  END_TEST();
}
}  // namespace

// Run through the complete sequence of memory tests.  Sets the exit code to
// the number of failed tests.  Exit code 0 means all passed.
int main() {
  int fail_count = 0;
  fail_count += TestZeroLengthRegion();
  fail_count += TestBadFiledesc();
  fail_count += TestMmapBadHint();
  fail_count += TestMmapBadHintFixed();
  fail_count += TestMmapMunmap();
  fail_count += TestMunmapText();
  fail_count += TestMmapNULL();
  fail_count += TestMmap32k();
  fail_count += TestMmapNonPageAligned();
  return fail_count;
}