1 : /*
2 : * Copyright 2010 The Native Client Authors. All rights reserved.
3 : * Use of this source code is governed by a BSD-style license that can
4 : * be 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/sys/errno.h"
19 : #include "native_client/src/trusted/service_runtime/include/sys/mman.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 : 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 : 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 : size_t MemWalk(size_t (*visitor)(uint32_t *, uintptr_t),
63 : uint32_t *buf,
64 4 : size_t nwords) {
65 4 : size_t ix = 0;
66 4 : size_t err_count = 0;
67 :
68 196612 : for (ix = 0; ix < nwords; ++ix) {
69 196608 : err_count += (*visitor)(&buf[ix], ix);
70 : }
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 393218 : if (self->cur_ix == self->nbytes) return -1;
88 393216 : *checkbytes = 1;
89 393216 : return self->cur_ix++;
90 : }
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 : int r;
125 : 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 4096 : CHECK(r >= 0);
133 4096 : remain = self->nbytes - r;
134 4096 : if (remain > MAX_CHECK) {
135 3999 : remain = MAX_CHECK;
136 : }
137 4096 : *checkbytes = rand() % remain;
138 4096 : CHECK(*checkbytes <= remain);
139 4096 : return r;
140 : }
141 :
142 : void RandomProberCtor(struct RandomProber *self,
143 : 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 : size_t CheckGioOpWithProber(struct Prober *pp,
157 : struct Gio *gp,
158 : uint8_t *addr,
159 : size_t nbytes,
160 6 : ssize_t (*Op)(struct Gio *, void *, size_t)) {
161 6 : size_t errs = 0;
162 : ssize_t ix;
163 : size_t checkbytes;
164 : uint8_t val[MAX_CHECK];
165 : 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 : }
174 790528 : if (checkbytes > sizeof val) {
175 0 : checkbytes = sizeof val;
176 : }
177 :
178 : /* fill with something we don't expect to be in real data */
179 9897614 : for (valix = 0; valix < checkbytes; ++valix) {
180 9107086 : val[valix] = (uint8_t) (~valix);
181 : }
182 :
183 790528 : if (gVerbose > 2) {
184 0 : printf("Seeking to 0x%"NACL_PRIxS"\n", ix);
185 : }
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 : }
191 0 : ++errs;
192 0 : continue;
193 : }
194 790528 : if (gVerbose > 2) {
195 0 : printf("Operating on 0x%"NACL_PRIxS" bytes\n", checkbytes);
196 : }
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 : }
202 0 : ++errs;
203 0 : continue;
204 : }
205 :
206 790528 : if (gVerbose > 2) {
207 0 : printf("Comparing against plain mmap view\n");
208 : }
209 9897614 : 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 : }
216 9107086 : if (val[valix] != addr[ix + valix]) {
217 0 : ++errs;
218 : }
219 : }
220 : }
221 6 : return errs;
222 : }
223 :
224 : size_t CheckGioReadWithProber(struct Prober *pp,
225 : struct Gio *gp,
226 : uint8_t *addr,
227 3 : size_t nbytes) {
228 3 : return CheckGioOpWithProber(pp, gp, addr, nbytes, gp->vtbl->Read);
229 : }
230 :
231 : size_t CheckGioWriteWithProber(struct Prober *pp,
232 : struct Gio *gp,
233 : 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 : size_t CheckGioOp(struct Gio *gp,
242 : uint8_t *addr,
243 : size_t nbytes,
244 : size_t (*Op)(struct Prober *,
245 : struct Gio *,
246 : uint8_t *,
247 2 : size_t)) {
248 : struct LinearProber lp;
249 : struct ReverseProber rp;
250 : 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 : size_t CheckGioRead(struct Gio *gp,
269 : uint8_t *addr,
270 1 : size_t nbytes) {
271 1 : return CheckGioOp(gp, addr, nbytes, CheckGioReadWithProber);
272 : }
273 :
274 : size_t CheckGioWrite(struct Gio *gp,
275 : uint8_t *addr,
276 1 : size_t nbytes) {
277 1 : return CheckGioOp(gp, addr, nbytes, CheckGioWriteWithProber);
278 : }
279 :
280 : size_t CheckGioZeros(struct Gio *gp,
281 1 : size_t nbytes) {
282 : unsigned char byte;
283 : ssize_t rv;
284 1 : size_t nerrors = 0;
285 : 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 196609 : 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 : }
308 : }
309 1 : return nerrors;
310 : }
311 :
312 :
313 : int main(int ac,
314 1 : char **av) {
315 : int opt;
316 :
317 : struct NaClDescImcShm *shmp;
318 : struct NaClDescEffectorTrustedMem eff;
319 : struct NaClDesc *dp;
320 : struct NaClDescEffector *effp;
321 : uintptr_t addr;
322 : uintptr_t addr2;
323 : size_t nbytes;
324 : size_t errs;
325 : int rv;
326 : struct NaClGioShm gio_shm;
327 1 : size_t map_chunks = NCHUNKS;
328 :
329 2 : while (EOF != (opt = getopt(ac, av, "m:n:s:v"))) {
330 0 : switch (opt) {
331 : case 'm':
332 0 : map_chunks = strtoul(optarg, (char **) NULL, 0);
333 0 : break;
334 : case 'n':
335 0 : gNumSamples = strtoul(optarg, (char **) NULL, 0);
336 0 : break;
337 : case 's':
338 0 : gRandomSeed = strtoul(optarg, (char **) NULL, 0);
339 0 : break;
340 : case 'v':
341 0 : ++gVerbose;
342 0 : break;
343 : default:
344 0 : fprintf(stderr,
345 : ("Usage: gio_shm_test [-v] [-m map_chunks]"
346 : " [-n num_samples] [-s seed]\n"));
347 0 : return EXIT_FAILURE;
348 : }
349 : }
350 :
351 1 : printf("Using seed %d (0x%x)\n", gRandomSeed, gRandomSeed);
352 1 : srand(gRandomSeed);
353 :
354 1 : NaClNrdAllModulesInit();
355 :
356 1 : shmp = malloc(sizeof *shmp);
357 1 : if (NULL == shmp) {
358 0 : printf("No memory\n");
359 0 : printf("FAILED\n");
360 0 : return EXIT_FAILURE;
361 : }
362 :
363 1 : nbytes = map_chunks * NACL_MAP_PAGESIZE;
364 1 : if (!NaClDescImcShmAllocCtor(shmp, nbytes, /* executable= */ 0)) {
365 0 : printf("NaClDescImcShmAllocCtor failed\n");
366 0 : printf("FAILED\n");
367 0 : return EXIT_FAILURE;
368 : }
369 1 : if (!NaClDescEffectorTrustedMemCtor(&eff)) {
370 0 : printf("NaClDescEffectorTrustedMemCtor failed\n");
371 0 : printf("FAILED\n");
372 0 : return EXIT_FAILURE;
373 : }
374 1 : dp = &shmp->base;
375 1 : effp = &eff.base;
376 :
377 1 : addr = (*((struct NaClDescVtbl const *) dp->base.vtbl)->
378 : Map)(dp,
379 : effp,
380 : NULL,
381 : nbytes,
382 : NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
383 : NACL_ABI_MAP_SHARED,
384 : 0);
385 1 : if (NaClPtrIsNegErrno(&addr)) {
386 0 : printf("Map failed\n");
387 0 : return EXIT_FAILURE;
388 : }
389 :
390 1 : MemWalk(MemFiller, (uint32_t *) addr, nbytes / sizeof(uint32_t));
391 1 : printf("Checking basic consistency\n");
392 1 : if (0 != MemWalk(MemChecker, (uint32_t *) addr, nbytes / sizeof(uint32_t))) {
393 0 : printf("Initial consistency check failed\n");
394 0 : printf("FAILED\n");
395 0 : return EXIT_FAILURE;
396 : }
397 :
398 1 : addr2 = (*((struct NaClDescVtbl const *) dp->base.vtbl)->
399 : Map)(dp,
400 : effp,
401 : NULL,
402 : nbytes,
403 : NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
404 : NACL_ABI_MAP_SHARED,
405 : 0);
406 1 : if (NaClPtrIsNegErrno(&addr2)) {
407 0 : printf("Second Map failed\n");
408 0 : return EXIT_FAILURE;
409 : }
410 1 : printf("Checking second view consistency\n");
411 1 : if (0 != MemWalk(MemChecker, (uint32_t *) addr2, nbytes / sizeof(uint32_t))) {
412 0 : printf("Second view consistency check failed\n");
413 0 : printf("FAILED\n");
414 0 : return EXIT_FAILURE;
415 : }
416 1 : if (0 != (rv = (*((struct NaClDescVtbl const *) dp->base.vtbl)->
417 : UnmapUnsafe)(dp, effp, (void *) addr2, nbytes))) {
418 0 : printf("UnmapUnsafe failed, returned %d\n", rv);
419 0 : printf("FAILED\n");
420 0 : return EXIT_FAILURE;
421 : }
422 :
423 1 : if (!NaClGioShmCtor(&gio_shm, dp, nbytes)) {
424 0 : printf("NaClGioShmCtor failed\n");
425 0 : printf("FAILED\n");
426 0 : return EXIT_FAILURE;
427 : }
428 :
429 1 : printf("Checking Gio vs direct shm consistency, read\n");
430 1 : if (0 != (errs = CheckGioRead((struct Gio *) &gio_shm,
431 : (uint8_t *) addr,
432 : nbytes))) {
433 0 : printf("ERROR: CheckGioRead failed, found %"NACL_PRIdS" errors\n", errs);
434 : }
435 :
436 1 : printf("Zeroing shared memory\n");
437 1 : MemWalk(ZeroFiller, (uint32_t *) addr, nbytes / sizeof(uint32_t));
438 1 : printf("Reading for zeros\n");
439 1 : if (0 != (errs = CheckGioZeros((struct Gio *) &gio_shm,
440 : nbytes))) {
441 0 : printf("ERROR: Gio found non-zero bytes!\n");
442 : }
443 :
444 1 : printf("Checking Gio vs direct shm consistency, write\n");
445 1 : if (0 != (errs = CheckGioWrite((struct Gio *) &gio_shm,
446 : (uint8_t *) addr,
447 : nbytes))) {
448 0 : printf("ERROR: CheckGioWrite failed, found %"NACL_PRIdS" errors\n", errs);
449 : }
450 :
451 1 : (*gio_shm.base.vtbl->Dtor)((struct Gio *) &gio_shm);
452 :
453 1 : NaClDescUnref(dp);
454 1 : (*effp->vtbl->Dtor)(effp);
455 :
456 1 : NaClNrdAllModulesFini();
457 1 : if (0 != errs) {
458 0 : printf("FAILED\n");
459 0 : return EXIT_FAILURE;
460 : } else {
461 1 : printf("PASSED\n");
462 1 : return EXIT_SUCCESS;
463 : }
464 : }
|