1 : /*
2 : * Copyright (c) 2012 The Native Client Authors. All rights reserved.
3 : * Use of this source code is governed by a BSD-style license that can be
4 : * found in the LICENSE file.
5 : */
6 :
7 : #include <stdio.h>
8 : #include <stdlib.h>
9 :
10 : #include "native_client/src/include/portability.h"
11 :
12 : #include "native_client/src/shared/platform/nacl_check.h"
13 :
14 : #include "native_client/src/trusted/desc/nacl_desc_base.h"
15 : #include "native_client/src/trusted/desc/nacl_desc_imc_shm.h"
16 : #include "native_client/src/trusted/desc/nacl_desc_effector_trusted_mem.h"
17 :
18 : #include "native_client/src/trusted/service_runtime/include/bits/mman.h"
19 : #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
20 : #include "native_client/src/trusted/service_runtime/include/sys/stat.h"
21 : #include "native_client/src/trusted/gio/gio_shm.h"
22 : #include "native_client/src/trusted/desc/nrd_all_modules.h"
23 : #include "native_client/src/trusted/service_runtime/nacl_config.h"
24 :
25 : #define NCHUNKS 3
26 :
27 : #define MAX_CHECK (4096)
28 :
29 : int gVerbose = 0;
30 : unsigned int gRandomSeed = 0x31415926;
31 : size_t gNumSamples = 2048;
32 :
33 147456 : uint32_t patgen(uint32_t offset) {
34 147456 : return (((offset + 3) << (3 * 8)) ^
35 : ((offset + 2) << (2 * 8)) ^
36 : ((offset + 1) << (1 * 8)) ^
37 : ((offset + 0) << (0 * 8)));
38 : }
39 :
40 :
41 49152 : size_t ZeroFiller(uint32_t *mem, size_t offset) {
42 98304 : UNREFERENCED_PARAMETER(offset);
43 49152 : *mem = 0;
44 49152 : return 0;
45 : }
46 :
47 0 : size_t ZeroChecker(uint32_t *mem, size_t offset) {
48 0 : UNREFERENCED_PARAMETER(offset);
49 0 : return *mem != 0;
50 : }
51 :
52 49152 : size_t MemFiller(uint32_t *mem, size_t offset) {
53 49152 : *mem = patgen((uint32_t) offset);
54 49152 : return 0;
55 : }
56 :
57 98304 : size_t MemChecker(uint32_t *mem, size_t offset) {
58 98304 : uint32_t pat = patgen((uint32_t) offset);
59 98304 : return *mem != pat;
60 : }
61 :
62 4 : size_t MemWalk(size_t (*visitor)(uint32_t *, uintptr_t),
63 4 : uint32_t *buf,
64 4 : size_t nwords) {
65 4 : size_t ix = 0;
66 4 : size_t err_count = 0;
67 :
68 393224 : for (ix = 0; ix < nwords; ++ix) {
69 196608 : err_count += (*visitor)(&buf[ix], ix);
70 196608 : }
71 4 : return err_count;
72 : }
73 :
74 : struct Prober {
75 : /* inline vtbl */
76 : ssize_t (*NextIx)(struct Prober *self, size_t *nbytes);
77 : };
78 :
79 : struct LinearProber {
80 : struct Prober base;
81 : size_t cur_ix;
82 : size_t nbytes;
83 : };
84 :
85 393218 : ssize_t LinearProberIndex(struct Prober *vself, size_t *checkbytes) {
86 393218 : struct LinearProber *self = (struct LinearProber *) vself;
87 393220 : if (self->cur_ix == self->nbytes) return -1;
88 393216 : *checkbytes = 1;
89 393216 : return self->cur_ix++;
90 393218 : }
91 :
92 2 : void LinearProberCtor(struct LinearProber *self, size_t nbytes) {
93 2 : self->base.NextIx = LinearProberIndex;
94 2 : self->cur_ix = 0;
95 2 : self->nbytes = nbytes;
96 2 : }
97 :
98 : struct ReverseProber {
99 : struct Prober base;
100 : size_t nbytes;
101 : };
102 :
103 393218 : ssize_t ReverseProberIndex(struct Prober *vself, size_t *checkbytes) {
104 393218 : struct ReverseProber *self = (struct ReverseProber *) vself;
105 :
106 393218 : *checkbytes = 1;
107 393218 : return --self->nbytes;
108 : }
109 :
110 2 : void ReverseProberCtor(struct ReverseProber *self, size_t nbytes) {
111 2 : self->base.NextIx = ReverseProberIndex;
112 2 : self->nbytes = nbytes;
113 2 : }
114 :
115 : struct RandomProber {
116 : struct Prober base;
117 : size_t nbytes;
118 : /* windows does not have rand_r, so this test must be single threaded */
119 : size_t count;
120 : };
121 :
122 4098 : ssize_t RandomProberIndex(struct Prober *vself, size_t *checkbytes) {
123 4098 : struct RandomProber *self = (struct RandomProber *) vself;
124 4098 : int r;
125 4098 : size_t remain;
126 :
127 4098 : if (0 == self->count) {
128 2 : return -1;
129 : }
130 4096 : --self->count;
131 4096 : r = (int) ((size_t) rand() % self->nbytes);
132 12288 : CHECK(r >= 0);
133 4096 : remain = self->nbytes - r;
134 4096 : if (remain > MAX_CHECK) {
135 3999 : remain = MAX_CHECK;
136 3999 : }
137 4096 : *checkbytes = rand() % remain;
138 12288 : CHECK(*checkbytes <= remain);
139 4096 : return r;
140 4098 : }
141 :
142 2 : void RandomProberCtor(struct RandomProber *self,
143 2 : size_t nbytes,
144 2 : size_t nsamples) {
145 2 : self->base.NextIx = RandomProberIndex;
146 2 : self->nbytes = nbytes;
147 2 : self->count = nsamples;
148 2 : }
149 :
150 : /*
151 : * Op is sort of a funny virtual function pointer -- it's not an
152 : * offset in the vtbl, so changing the object is bad (esp w/
153 : * subclasses that might have overridden the virtual function), but
154 : * the extracted function pointer.
155 : */
156 6 : size_t CheckGioOpWithProber(struct Prober *pp,
157 6 : struct Gio *gp,
158 6 : uint8_t *addr,
159 6 : size_t nbytes,
160 6 : ssize_t (*Op)(struct Gio *, void *, size_t)) {
161 6 : size_t errs = 0;
162 6 : ssize_t ix;
163 6 : size_t checkbytes;
164 6 : uint8_t val[MAX_CHECK];
165 6 : size_t valix;
166 :
167 790540 : while (-1 != (ix = (*pp->NextIx)(pp, &checkbytes))) {
168 790528 : if (nbytes <= (size_t) ix) {
169 0 : break;
170 : }
171 790528 : if (gVerbose > 1) {
172 0 : printf("0x%"NACL_PRIxS", 0x%"NACL_PRIxS"\n", ix, checkbytes);
173 0 : }
174 790528 : if (checkbytes > sizeof val) {
175 0 : checkbytes = sizeof val;
176 0 : }
177 :
178 : /* fill with something we don't expect to be in real data */
179 19795228 : for (valix = 0; valix < checkbytes; ++valix) {
180 9107086 : val[valix] = (uint8_t) (~valix);
181 9107086 : }
182 :
183 790528 : if (gVerbose > 2) {
184 0 : printf("Seeking to 0x%"NACL_PRIxS"\n", ix);
185 0 : }
186 :
187 790528 : if (-1 == (*gp->vtbl->Seek)(gp, (off_t) ix, SEEK_SET)) {
188 0 : if (gVerbose) {
189 0 : printf("Seek to %"NACL_PRIdS" failed\n", ix);
190 0 : }
191 0 : ++errs;
192 0 : continue;
193 : }
194 790528 : if (gVerbose > 2) {
195 0 : printf("Operating on 0x%"NACL_PRIxS" bytes\n", checkbytes);
196 0 : }
197 :
198 790528 : if (-1 == (*Op)(gp, val, checkbytes)) {
199 0 : if (gVerbose) {
200 0 : printf("Apply Op at %"NACL_PRIdS" failed\n", ix);
201 0 : }
202 0 : ++errs;
203 0 : continue;
204 : }
205 :
206 790528 : if (gVerbose > 2) {
207 0 : printf("Comparing against plain mmap view\n");
208 0 : }
209 19795228 : for (valix = 0; valix < checkbytes; ++valix) {
210 9107086 : if (1 < gVerbose) {
211 0 : printf(("Value from gio is 0x%08"NACL_PRIx8","
212 : " from memory is 0x%08"NACL_PRIx8"\n"),
213 : val[valix],
214 : addr[ix + valix]);
215 0 : }
216 9107086 : if (val[valix] != addr[ix + valix]) {
217 0 : ++errs;
218 0 : }
219 9107086 : }
220 790528 : }
221 6 : return errs;
222 : }
223 :
224 3 : size_t CheckGioReadWithProber(struct Prober *pp,
225 3 : struct Gio *gp,
226 3 : uint8_t *addr,
227 3 : size_t nbytes) {
228 3 : return CheckGioOpWithProber(pp, gp, addr, nbytes, gp->vtbl->Read);
229 : }
230 :
231 3 : size_t CheckGioWriteWithProber(struct Prober *pp,
232 3 : struct Gio *gp,
233 3 : uint8_t *addr,
234 3 : size_t nbytes) {
235 3 : return CheckGioOpWithProber(pp, gp, addr, nbytes,
236 : (ssize_t (*)(struct Gio *, void *, size_t))
237 : gp->vtbl->Write);
238 : }
239 :
240 :
241 2 : size_t CheckGioOp(struct Gio *gp,
242 2 : uint8_t *addr,
243 2 : size_t nbytes,
244 2 : size_t (*Op)(struct Prober *,
245 : struct Gio *,
246 : uint8_t *,
247 : size_t)) {
248 2 : struct LinearProber lp;
249 2 : struct ReverseProber rp;
250 2 : struct RandomProber rand_probe;
251 2 : ssize_t num_err = 0;
252 :
253 2 : LinearProberCtor(&lp, nbytes);
254 2 : printf("Testing w/ LinearProber\n");
255 2 : num_err += (*Op)((struct Prober *) &lp, gp, addr, nbytes);
256 :
257 2 : ReverseProberCtor(&rp, nbytes);
258 2 : printf("Testing w/ ReverseProber\n");
259 2 : num_err += (*Op)((struct Prober *) &rp, gp, addr, nbytes);
260 :
261 2 : RandomProberCtor(&rand_probe, nbytes, gNumSamples);
262 2 : printf("Testing w/ RandomProber\n");
263 2 : num_err += (*Op)((struct Prober *) &rand_probe, gp, addr, nbytes);
264 :
265 2 : return num_err;
266 : }
267 :
268 1 : size_t CheckGioRead(struct Gio *gp,
269 1 : uint8_t *addr,
270 1 : size_t nbytes) {
271 1 : return CheckGioOp(gp, addr, nbytes, CheckGioReadWithProber);
272 : }
273 :
274 1 : size_t CheckGioWrite(struct Gio *gp,
275 1 : uint8_t *addr,
276 1 : size_t nbytes) {
277 1 : return CheckGioOp(gp, addr, nbytes, CheckGioWriteWithProber);
278 : }
279 :
280 1 : size_t CheckGioZeros(struct Gio *gp,
281 1 : size_t nbytes) {
282 1 : unsigned char byte;
283 1 : ssize_t rv;
284 1 : size_t nerrors = 0;
285 1 : size_t ix;
286 1 : uint64_t temp_nbytes = nbytes;
287 :
288 1 : if (temp_nbytes > OFF_T_MAX) {
289 0 : return 1;
290 : }
291 :
292 393218 : for (ix = 0; ix < nbytes; ++ix) {
293 196608 : byte = 0xff;
294 196608 : if (-1 == (*gp->vtbl->Seek)(gp, (off_t) ix, SEEK_SET)) {
295 0 : printf("Seek to byt %"NACL_PRIuS" failed\n", ix);
296 0 : ++nerrors;
297 0 : continue;
298 : }
299 196608 : if (1 != (rv = (*gp->vtbl->Read)(gp, &byte, 1))) {
300 0 : printf("Read of byte %"NACL_PRIuS" failed\n", ix);
301 0 : ++nerrors;
302 0 : continue;
303 : }
304 196608 : if (0 != byte) {
305 0 : printf("Byte %"NACL_PRIuS" not zero: 0x%02x\n", ix, 0xff & byte);
306 0 : ++nerrors;
307 0 : }
308 196608 : }
309 1 : return nerrors;
310 1 : }
311 :
312 :
313 1 : int main(int ac,
314 1 : char **av) {
315 1 : int opt;
316 :
317 1 : struct NaClDescImcShm *shmp;
318 1 : struct NaClDesc *dp;
319 1 : uintptr_t addr;
320 1 : uintptr_t addr2;
321 1 : size_t nbytes;
322 1 : size_t errs;
323 1 : struct NaClGioShm gio_shm;
324 1 : size_t map_chunks = NCHUNKS;
325 :
326 2 : while (EOF != (opt = getopt(ac, av, "m:n:s:v"))) {
327 0 : switch (opt) {
328 : case 'm':
329 0 : map_chunks = strtoul(optarg, (char **) NULL, 0);
330 0 : break;
331 : case 'n':
332 0 : gNumSamples = strtoul(optarg, (char **) NULL, 0);
333 0 : break;
334 : case 's':
335 0 : gRandomSeed = strtoul(optarg, (char **) NULL, 0);
336 0 : break;
337 : case 'v':
338 0 : ++gVerbose;
339 0 : break;
340 : default:
341 0 : fprintf(stderr,
342 : ("Usage: gio_shm_test [-v] [-m map_chunks]"
343 : " [-n num_samples] [-s seed]\n"));
344 0 : return EXIT_FAILURE;
345 : }
346 0 : }
347 :
348 1 : printf("Using seed %d (0x%x)\n", gRandomSeed, gRandomSeed);
349 1 : srand(gRandomSeed);
350 :
351 1 : NaClNrdAllModulesInit();
352 :
353 1 : shmp = malloc(sizeof *shmp);
354 1 : if (NULL == shmp) {
355 0 : printf("No memory\n");
356 0 : printf("FAILED\n");
357 0 : return EXIT_FAILURE;
358 : }
359 :
360 1 : nbytes = map_chunks * NACL_MAP_PAGESIZE;
361 1 : if (!NaClDescImcShmAllocCtor(shmp, nbytes, /* executable= */ 0)) {
362 0 : printf("NaClDescImcShmAllocCtor failed\n");
363 0 : printf("FAILED\n");
364 0 : return EXIT_FAILURE;
365 : }
366 1 : dp = &shmp->base;
367 :
368 2 : addr = (*((struct NaClDescVtbl const *) dp->base.vtbl)->
369 : Map)(dp,
370 1 : NaClDescEffectorTrustedMem(),
371 : NULL,
372 : nbytes,
373 : NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
374 : NACL_ABI_MAP_SHARED,
375 : 0);
376 1 : if (NaClPtrIsNegErrno(&addr)) {
377 0 : printf("Map failed\n");
378 0 : return EXIT_FAILURE;
379 : }
380 :
381 1 : MemWalk(MemFiller, (uint32_t *) addr, nbytes / sizeof(uint32_t));
382 1 : printf("Checking basic consistency\n");
383 1 : if (0 != MemWalk(MemChecker, (uint32_t *) addr, nbytes / sizeof(uint32_t))) {
384 0 : printf("Initial consistency check failed\n");
385 0 : printf("FAILED\n");
386 0 : return EXIT_FAILURE;
387 : }
388 :
389 2 : addr2 = (*((struct NaClDescVtbl const *) dp->base.vtbl)->
390 : Map)(dp,
391 1 : NaClDescEffectorTrustedMem(),
392 : NULL,
393 : nbytes,
394 : NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
395 : NACL_ABI_MAP_SHARED,
396 : 0);
397 1 : if (NaClPtrIsNegErrno(&addr2)) {
398 0 : printf("Second Map failed\n");
399 0 : return EXIT_FAILURE;
400 : }
401 1 : printf("Checking second view consistency\n");
402 1 : if (0 != MemWalk(MemChecker, (uint32_t *) addr2, nbytes / sizeof(uint32_t))) {
403 0 : printf("Second view consistency check failed\n");
404 0 : printf("FAILED\n");
405 0 : return EXIT_FAILURE;
406 : }
407 1 : NaClDescUnmapUnsafe(dp, (void *) addr2, nbytes);
408 :
409 1 : if (!NaClGioShmCtor(&gio_shm, dp, nbytes)) {
410 0 : printf("NaClGioShmCtor failed\n");
411 0 : printf("FAILED\n");
412 0 : return EXIT_FAILURE;
413 : }
414 :
415 1 : printf("Checking Gio vs direct shm consistency, read\n");
416 1 : if (0 != (errs = CheckGioRead((struct Gio *) &gio_shm,
417 : (uint8_t *) addr,
418 : nbytes))) {
419 0 : printf("ERROR: CheckGioRead failed, found %"NACL_PRIdS" errors\n", errs);
420 0 : }
421 :
422 1 : printf("Zeroing shared memory\n");
423 1 : MemWalk(ZeroFiller, (uint32_t *) addr, nbytes / sizeof(uint32_t));
424 1 : printf("Reading for zeros\n");
425 1 : if (0 != (errs = CheckGioZeros((struct Gio *) &gio_shm,
426 : nbytes))) {
427 0 : printf("ERROR: Gio found non-zero bytes!\n");
428 0 : }
429 :
430 1 : printf("Checking Gio vs direct shm consistency, write\n");
431 1 : if (0 != (errs = CheckGioWrite((struct Gio *) &gio_shm,
432 : (uint8_t *) addr,
433 : nbytes))) {
434 0 : printf("ERROR: CheckGioWrite failed, found %"NACL_PRIdS" errors\n", errs);
435 0 : }
436 :
437 1 : (*gio_shm.base.vtbl->Dtor)((struct Gio *) &gio_shm);
438 :
439 1 : NaClDescUnref(dp);
440 :
441 1 : NaClNrdAllModulesFini();
442 1 : if (0 != errs) {
443 0 : printf("FAILED\n");
444 0 : return EXIT_FAILURE;
445 : } else {
446 1 : printf("PASSED\n");
447 1 : return EXIT_SUCCESS;
448 : }
449 1 : }
|