]>
Commit | Line | Data |
---|---|---|
92a42be0 SL |
1 | // RUN: %clang_dfsan %s -o %t && DFSAN_OPTIONS="strict_data_dependencies=0" %run %t |
2 | // RUN: %clang_dfsan -mllvm -dfsan-args-abi %s -o %t && DFSAN_OPTIONS="strict_data_dependencies=0" %run %t | |
3 | // RUN: %clang_dfsan -DSTRICT_DATA_DEPENDENCIES %s -o %t && %run %t | |
4 | // RUN: %clang_dfsan -DSTRICT_DATA_DEPENDENCIES -mllvm -dfsan-args-abi %s -o %t && %run %t | |
1a4d82fc | 5 | |
7cac9316 XL |
6 | // XFAIL: target-is-mips64el |
7 | ||
1a4d82fc JJ |
8 | // Tests custom implementations of various glibc functions. |
9 | ||
1a4d82fc JJ |
10 | #include <sanitizer/dfsan_interface.h> |
11 | ||
12 | #include <arpa/inet.h> | |
13 | #include <assert.h> | |
14 | #include <fcntl.h> | |
15 | #include <link.h> | |
16 | #include <poll.h> | |
17 | #include <pthread.h> | |
18 | #include <pwd.h> | |
19 | #include <sched.h> | |
20 | #include <signal.h> | |
21 | #include <stdio.h> | |
92a42be0 | 22 | #include <stdint.h> |
1a4d82fc JJ |
23 | #include <stdlib.h> |
24 | #include <string.h> | |
25 | #include <sys/select.h> | |
26 | #include <sys/resource.h> | |
27 | #include <sys/stat.h> | |
28 | #include <sys/time.h> | |
29 | #include <sys/types.h> | |
30 | #include <time.h> | |
31 | #include <unistd.h> | |
32 | ||
33 | dfsan_label i_label = 0; | |
34 | dfsan_label j_label = 0; | |
35 | dfsan_label k_label = 0; | |
36 | dfsan_label i_j_label = 0; | |
37 | ||
38 | #define ASSERT_ZERO_LABEL(data) \ | |
39 | assert(0 == dfsan_get_label((long) (data))) | |
40 | ||
41 | #define ASSERT_READ_ZERO_LABEL(ptr, size) \ | |
42 | assert(0 == dfsan_read_label(ptr, size)) | |
43 | ||
44 | #define ASSERT_LABEL(data, label) \ | |
45 | assert(label == dfsan_get_label((long) (data))) | |
46 | ||
47 | #define ASSERT_READ_LABEL(ptr, size, label) \ | |
48 | assert(label == dfsan_read_label(ptr, size)) | |
49 | ||
50 | void test_stat() { | |
51 | int i = 1; | |
52 | dfsan_set_label(i_label, &i, sizeof(i)); | |
53 | ||
54 | struct stat s; | |
55 | s.st_dev = i; | |
56 | assert(0 == stat("/", &s)); | |
57 | ASSERT_ZERO_LABEL(s.st_dev); | |
58 | ||
59 | s.st_dev = i; | |
60 | assert(-1 == stat("/nonexistent", &s)); | |
61 | ASSERT_LABEL(s.st_dev, i_label); | |
62 | } | |
63 | ||
64 | void test_fstat() { | |
65 | int i = 1; | |
66 | dfsan_set_label(i_label, &i, sizeof(i)); | |
67 | ||
68 | struct stat s; | |
69 | int fd = open("/dev/zero", O_RDONLY); | |
70 | s.st_dev = i; | |
71 | int rv = fstat(fd, &s); | |
72 | assert(0 == rv); | |
73 | ASSERT_ZERO_LABEL(s.st_dev); | |
74 | } | |
75 | ||
76 | void test_memcmp() { | |
77 | char str1[] = "str1", str2[] = "str2"; | |
78 | dfsan_set_label(i_label, &str1[3], 1); | |
79 | dfsan_set_label(j_label, &str2[3], 1); | |
80 | ||
81 | int rv = memcmp(str1, str2, sizeof(str1)); | |
82 | assert(rv < 0); | |
83 | #ifdef STRICT_DATA_DEPENDENCIES | |
84 | ASSERT_ZERO_LABEL(rv); | |
85 | #else | |
86 | ASSERT_LABEL(rv, i_j_label); | |
87 | #endif | |
88 | } | |
89 | ||
90 | void test_memcpy() { | |
91 | char str1[] = "str1"; | |
92 | char str2[sizeof(str1)]; | |
93 | dfsan_set_label(i_label, &str1[3], 1); | |
94 | ||
95 | ASSERT_ZERO_LABEL(memcpy(str2, str1, sizeof(str1))); | |
96 | assert(0 == memcmp(str2, str1, sizeof(str1))); | |
97 | ASSERT_ZERO_LABEL(str2[0]); | |
98 | ASSERT_LABEL(str2[3], i_label); | |
99 | } | |
100 | ||
101 | void test_memset() { | |
102 | char buf[8]; | |
103 | int j = 'a'; | |
104 | dfsan_set_label(j_label, &j, sizeof(j)); | |
105 | ||
106 | ASSERT_ZERO_LABEL(memset(&buf, j, sizeof(buf))); | |
107 | for (int i = 0; i < 8; ++i) { | |
108 | ASSERT_LABEL(buf[i], j_label); | |
109 | assert(buf[i] == 'a'); | |
110 | } | |
111 | } | |
112 | ||
113 | void test_strcmp() { | |
114 | char str1[] = "str1", str2[] = "str2"; | |
115 | dfsan_set_label(i_label, &str1[3], 1); | |
116 | dfsan_set_label(j_label, &str2[3], 1); | |
117 | ||
118 | int rv = strcmp(str1, str2); | |
119 | assert(rv < 0); | |
120 | #ifdef STRICT_DATA_DEPENDENCIES | |
121 | ASSERT_ZERO_LABEL(rv); | |
122 | #else | |
123 | ASSERT_LABEL(rv, i_j_label); | |
124 | #endif | |
125 | } | |
126 | ||
127 | void test_strlen() { | |
128 | char str1[] = "str1"; | |
129 | dfsan_set_label(i_label, &str1[3], 1); | |
130 | ||
131 | int rv = strlen(str1); | |
132 | assert(rv == 4); | |
133 | #ifdef STRICT_DATA_DEPENDENCIES | |
134 | ASSERT_ZERO_LABEL(rv); | |
135 | #else | |
136 | ASSERT_LABEL(rv, i_label); | |
137 | #endif | |
138 | } | |
139 | ||
140 | void test_strdup() { | |
141 | char str1[] = "str1"; | |
142 | dfsan_set_label(i_label, &str1[3], 1); | |
143 | ||
144 | char *strd = strdup(str1); | |
145 | ASSERT_ZERO_LABEL(strd[0]); | |
146 | ASSERT_LABEL(strd[3], i_label); | |
147 | free(strd); | |
148 | } | |
149 | ||
150 | void test_strncpy() { | |
151 | char str1[] = "str1"; | |
152 | char str2[sizeof(str1)]; | |
153 | dfsan_set_label(i_label, &str1[3], 1); | |
154 | ||
155 | char *strd = strncpy(str2, str1, 5); | |
156 | assert(strd == str2); | |
157 | assert(strcmp(str1, str2) == 0); | |
158 | ASSERT_ZERO_LABEL(strd); | |
159 | ASSERT_ZERO_LABEL(strd[0]); | |
160 | ASSERT_ZERO_LABEL(strd[1]); | |
161 | ASSERT_ZERO_LABEL(strd[2]); | |
162 | ASSERT_LABEL(strd[3], i_label); | |
163 | ||
164 | strd = strncpy(str2, str1, 3); | |
165 | assert(strd == str2); | |
166 | assert(strncmp(str1, str2, 3) == 0); | |
167 | ASSERT_ZERO_LABEL(strd); | |
168 | ASSERT_ZERO_LABEL(strd[0]); | |
169 | ASSERT_ZERO_LABEL(strd[1]); | |
170 | ASSERT_ZERO_LABEL(strd[2]); | |
171 | } | |
172 | ||
173 | void test_strncmp() { | |
174 | char str1[] = "str1", str2[] = "str2"; | |
175 | dfsan_set_label(i_label, &str1[3], 1); | |
176 | dfsan_set_label(j_label, &str2[3], 1); | |
177 | ||
178 | int rv = strncmp(str1, str2, sizeof(str1)); | |
179 | assert(rv < 0); | |
180 | #ifdef STRICT_DATA_DEPENDENCIES | |
181 | ASSERT_ZERO_LABEL(rv); | |
182 | #else | |
183 | ASSERT_LABEL(rv, dfsan_union(i_label, j_label)); | |
184 | #endif | |
185 | ||
186 | rv = strncmp(str1, str2, 3); | |
187 | assert(rv == 0); | |
188 | ASSERT_ZERO_LABEL(rv); | |
189 | } | |
190 | ||
191 | void test_strcasecmp() { | |
192 | char str1[] = "str1", str2[] = "str2", str3[] = "Str1"; | |
193 | dfsan_set_label(i_label, &str1[3], 1); | |
194 | dfsan_set_label(j_label, &str2[3], 1); | |
195 | dfsan_set_label(j_label, &str3[2], 1); | |
196 | ||
197 | int rv = strcasecmp(str1, str2); | |
198 | assert(rv < 0); | |
199 | #ifdef STRICT_DATA_DEPENDENCIES | |
200 | ASSERT_ZERO_LABEL(rv); | |
201 | #else | |
202 | ASSERT_LABEL(rv, dfsan_union(i_label, j_label)); | |
203 | #endif | |
204 | ||
205 | rv = strcasecmp(str1, str3); | |
206 | assert(rv == 0); | |
207 | #ifdef STRICT_DATA_DEPENDENCIES | |
208 | ASSERT_ZERO_LABEL(rv); | |
209 | #else | |
210 | ASSERT_LABEL(rv, dfsan_union(i_label, j_label)); | |
211 | #endif | |
212 | } | |
213 | ||
214 | void test_strncasecmp() { | |
215 | char str1[] = "Str1", str2[] = "str2"; | |
216 | dfsan_set_label(i_label, &str1[3], 1); | |
217 | dfsan_set_label(j_label, &str2[3], 1); | |
218 | ||
219 | int rv = strncasecmp(str1, str2, sizeof(str1)); | |
220 | assert(rv < 0); | |
221 | #ifdef STRICT_DATA_DEPENDENCIES | |
222 | ASSERT_ZERO_LABEL(rv); | |
223 | #else | |
224 | ASSERT_LABEL(rv, dfsan_union(i_label, j_label)); | |
225 | #endif | |
226 | ||
227 | rv = strncasecmp(str1, str2, 3); | |
228 | assert(rv == 0); | |
229 | ASSERT_ZERO_LABEL(rv); | |
230 | } | |
231 | ||
232 | void test_strchr() { | |
233 | char str1[] = "str1"; | |
234 | dfsan_set_label(i_label, &str1[3], 1); | |
235 | ||
236 | char *crv = strchr(str1, 'r'); | |
237 | assert(crv == &str1[2]); | |
238 | ASSERT_ZERO_LABEL(crv); | |
239 | ||
240 | crv = strchr(str1, '1'); | |
241 | assert(crv == &str1[3]); | |
242 | #ifdef STRICT_DATA_DEPENDENCIES | |
243 | ASSERT_ZERO_LABEL(crv); | |
244 | #else | |
245 | ASSERT_LABEL(crv, i_label); | |
246 | #endif | |
247 | ||
248 | crv = strchr(str1, 'x'); | |
249 | assert(!crv); | |
250 | #ifdef STRICT_DATA_DEPENDENCIES | |
251 | ASSERT_ZERO_LABEL(crv); | |
252 | #else | |
253 | ASSERT_LABEL(crv, i_label); | |
254 | #endif | |
255 | } | |
256 | ||
257 | void test_calloc() { | |
258 | // With any luck this sequence of calls will cause calloc to return the same | |
259 | // pointer both times. This is probably the best we can do to test this | |
260 | // function. | |
92a42be0 | 261 | char *crv = (char *) calloc(4096, 1); |
1a4d82fc JJ |
262 | ASSERT_ZERO_LABEL(crv[0]); |
263 | dfsan_set_label(i_label, crv, 100); | |
264 | free(crv); | |
265 | ||
92a42be0 | 266 | crv = (char *) calloc(4096, 1); |
1a4d82fc JJ |
267 | ASSERT_ZERO_LABEL(crv[0]); |
268 | free(crv); | |
269 | } | |
270 | ||
271 | void test_read() { | |
272 | char buf[16]; | |
273 | dfsan_set_label(i_label, buf, 1); | |
274 | dfsan_set_label(j_label, buf + 15, 1); | |
275 | ||
276 | ASSERT_LABEL(buf[0], i_label); | |
277 | ASSERT_LABEL(buf[15], j_label); | |
278 | ||
279 | int fd = open("/dev/zero", O_RDONLY); | |
280 | int rv = read(fd, buf, sizeof(buf)); | |
281 | assert(rv == sizeof(buf)); | |
282 | ASSERT_ZERO_LABEL(rv); | |
283 | ASSERT_ZERO_LABEL(buf[0]); | |
284 | ASSERT_ZERO_LABEL(buf[15]); | |
285 | close(fd); | |
286 | } | |
287 | ||
288 | void test_pread() { | |
289 | char buf[16]; | |
290 | dfsan_set_label(i_label, buf, 1); | |
291 | dfsan_set_label(j_label, buf + 15, 1); | |
292 | ||
293 | ASSERT_LABEL(buf[0], i_label); | |
294 | ASSERT_LABEL(buf[15], j_label); | |
295 | ||
296 | int fd = open("/bin/sh", O_RDONLY); | |
297 | int rv = pread(fd, buf, sizeof(buf), 0); | |
298 | assert(rv == sizeof(buf)); | |
299 | ASSERT_ZERO_LABEL(rv); | |
300 | ASSERT_ZERO_LABEL(buf[0]); | |
301 | ASSERT_ZERO_LABEL(buf[15]); | |
302 | close(fd); | |
303 | } | |
304 | ||
305 | void test_dlopen() { | |
306 | void *map = dlopen(NULL, RTLD_NOW); | |
307 | assert(map); | |
308 | ASSERT_ZERO_LABEL(map); | |
309 | dlclose(map); | |
310 | map = dlopen("/nonexistent", RTLD_NOW); | |
311 | assert(!map); | |
312 | ASSERT_ZERO_LABEL(map); | |
313 | } | |
314 | ||
315 | void test_clock_gettime() { | |
316 | struct timespec tp; | |
317 | dfsan_set_label(j_label, ((char *)&tp) + 3, 1); | |
318 | int t = clock_gettime(CLOCK_REALTIME, &tp); | |
319 | assert(t == 0); | |
320 | ASSERT_ZERO_LABEL(t); | |
321 | ASSERT_ZERO_LABEL(((char *)&tp)[3]); | |
322 | } | |
323 | ||
324 | void test_ctime_r() { | |
325 | char *buf = (char*) malloc(64); | |
326 | time_t t = 0; | |
327 | ||
328 | char *ret = ctime_r(&t, buf); | |
329 | ASSERT_ZERO_LABEL(ret); | |
330 | assert(buf == ret); | |
331 | ASSERT_READ_ZERO_LABEL(buf, strlen(buf) + 1); | |
332 | ||
333 | dfsan_set_label(i_label, &t, sizeof(t)); | |
334 | ret = ctime_r(&t, buf); | |
335 | ASSERT_ZERO_LABEL(ret); | |
336 | ASSERT_READ_LABEL(buf, strlen(buf) + 1, i_label); | |
337 | ||
338 | t = 0; | |
339 | dfsan_set_label(j_label, &buf, sizeof(&buf)); | |
340 | ret = ctime_r(&t, buf); | |
341 | ASSERT_LABEL(ret, j_label); | |
342 | ASSERT_READ_ZERO_LABEL(buf, strlen(buf) + 1); | |
343 | } | |
344 | ||
345 | static int write_callback_count = 0; | |
346 | static int last_fd; | |
92a42be0 | 347 | static const unsigned char *last_buf; |
1a4d82fc JJ |
348 | static size_t last_count; |
349 | ||
350 | void write_callback(int fd, const void *buf, size_t count) { | |
351 | write_callback_count++; | |
352 | ||
353 | last_fd = fd; | |
92a42be0 | 354 | last_buf = (const unsigned char*) buf; |
1a4d82fc JJ |
355 | last_count = count; |
356 | } | |
357 | ||
358 | void test_dfsan_set_write_callback() { | |
359 | char buf[] = "Sample chars"; | |
360 | int buf_len = strlen(buf); | |
361 | ||
362 | int fd = open("/dev/null", O_WRONLY); | |
363 | ||
364 | dfsan_set_write_callback(write_callback); | |
365 | ||
366 | write_callback_count = 0; | |
367 | ||
368 | // Callback should be invoked on every call to write(). | |
369 | int res = write(fd, buf, buf_len); | |
370 | assert(write_callback_count == 1); | |
371 | ASSERT_READ_ZERO_LABEL(&res, sizeof(res)); | |
372 | ASSERT_READ_ZERO_LABEL(&last_fd, sizeof(last_fd)); | |
373 | ASSERT_READ_ZERO_LABEL(last_buf, sizeof(last_buf)); | |
374 | ASSERT_READ_ZERO_LABEL(&last_count, sizeof(last_count)); | |
375 | ||
376 | // Add a label to write() arguments. Check that the labels are readable from | |
377 | // the values passed to the callback. | |
378 | dfsan_set_label(i_label, &fd, sizeof(fd)); | |
379 | dfsan_set_label(j_label, &(buf[3]), 1); | |
380 | dfsan_set_label(k_label, &buf_len, sizeof(buf_len)); | |
92a42be0 | 381 | |
1a4d82fc JJ |
382 | res = write(fd, buf, buf_len); |
383 | assert(write_callback_count == 2); | |
384 | ASSERT_READ_ZERO_LABEL(&res, sizeof(res)); | |
385 | ASSERT_READ_LABEL(&last_fd, sizeof(last_fd), i_label); | |
386 | ASSERT_READ_LABEL(&last_buf[3], sizeof(last_buf[3]), j_label); | |
387 | ASSERT_READ_LABEL(last_buf, sizeof(last_buf), j_label); | |
388 | ASSERT_READ_LABEL(&last_count, sizeof(last_count), k_label); | |
389 | ||
390 | dfsan_set_write_callback(NULL); | |
391 | } | |
392 | ||
393 | void test_fgets() { | |
394 | char *buf = (char*) malloc(128); | |
395 | FILE *f = fopen("/etc/passwd", "r"); | |
396 | dfsan_set_label(j_label, buf, 1); | |
397 | char *ret = fgets(buf, sizeof(buf), f); | |
398 | assert(ret == buf); | |
399 | ASSERT_ZERO_LABEL(ret); | |
400 | ASSERT_READ_ZERO_LABEL(buf, 128); | |
401 | dfsan_set_label(j_label, &buf, sizeof(&buf)); | |
402 | ret = fgets(buf, sizeof(buf), f); | |
403 | ASSERT_LABEL(ret, j_label); | |
404 | fclose(f); | |
405 | } | |
406 | ||
407 | void test_getcwd() { | |
408 | char buf[1024]; | |
409 | char *ptr = buf; | |
410 | dfsan_set_label(i_label, buf + 2, 2); | |
411 | char* ret = getcwd(buf, sizeof(buf)); | |
412 | assert(ret == buf); | |
413 | assert(ret[0] == '/'); | |
414 | ASSERT_READ_ZERO_LABEL(buf + 2, 2); | |
415 | dfsan_set_label(i_label, &ptr, sizeof(ptr)); | |
416 | ret = getcwd(ptr, sizeof(buf)); | |
417 | ASSERT_LABEL(ret, i_label); | |
418 | } | |
419 | ||
420 | void test_get_current_dir_name() { | |
421 | char* ret = get_current_dir_name(); | |
422 | assert(ret); | |
423 | assert(ret[0] == '/'); | |
424 | ASSERT_READ_ZERO_LABEL(ret, strlen(ret) + 1); | |
425 | } | |
426 | ||
427 | void test_gethostname() { | |
428 | char buf[1024]; | |
429 | dfsan_set_label(i_label, buf + 2, 2); | |
430 | assert(gethostname(buf, sizeof(buf)) == 0); | |
431 | ASSERT_READ_ZERO_LABEL(buf + 2, 2); | |
432 | } | |
433 | ||
434 | void test_getrlimit() { | |
435 | struct rlimit rlim; | |
436 | dfsan_set_label(i_label, &rlim, sizeof(rlim)); | |
437 | assert(getrlimit(RLIMIT_CPU, &rlim) == 0); | |
438 | ASSERT_READ_ZERO_LABEL(&rlim, sizeof(rlim)); | |
439 | } | |
440 | ||
441 | void test_getrusage() { | |
442 | struct rusage usage; | |
443 | dfsan_set_label(i_label, &usage, sizeof(usage)); | |
444 | assert(getrusage(RUSAGE_SELF, &usage) == 0); | |
445 | ASSERT_READ_ZERO_LABEL(&usage, sizeof(usage)); | |
446 | } | |
447 | ||
448 | void test_strcpy() { | |
449 | char src[] = "hello world"; | |
450 | char dst[sizeof(src) + 2]; | |
451 | dfsan_set_label(0, src, sizeof(src)); | |
452 | dfsan_set_label(0, dst, sizeof(dst)); | |
453 | dfsan_set_label(i_label, src + 2, 1); | |
454 | dfsan_set_label(j_label, src + 3, 1); | |
455 | dfsan_set_label(j_label, dst + 4, 1); | |
456 | dfsan_set_label(i_label, dst + 12, 1); | |
457 | char *ret = strcpy(dst, src); | |
458 | assert(ret == dst); | |
459 | assert(strcmp(src, dst) == 0); | |
460 | for (int i = 0; i < strlen(src) + 1; ++i) { | |
461 | assert(dfsan_get_label(dst[i]) == dfsan_get_label(src[i])); | |
462 | } | |
463 | // Note: if strlen(src) + 1 were used instead to compute the first untouched | |
464 | // byte of dest, the label would be I|J. This is because strlen() might | |
465 | // return a non-zero label, and because by default pointer labels are not | |
466 | // ignored on loads. | |
467 | ASSERT_LABEL(dst[12], i_label); | |
468 | } | |
469 | ||
470 | void test_strtol() { | |
471 | char buf[] = "1234578910"; | |
472 | char *endptr = NULL; | |
473 | dfsan_set_label(i_label, buf + 1, 1); | |
474 | dfsan_set_label(j_label, buf + 10, 1); | |
475 | long int ret = strtol(buf, &endptr, 10); | |
476 | assert(ret == 1234578910); | |
477 | assert(endptr == buf + 10); | |
478 | ASSERT_LABEL(ret, i_j_label); | |
479 | } | |
480 | ||
481 | void test_strtoll() { | |
482 | char buf[] = "1234578910 "; | |
483 | char *endptr = NULL; | |
484 | dfsan_set_label(i_label, buf + 1, 1); | |
485 | dfsan_set_label(j_label, buf + 2, 1); | |
486 | long long int ret = strtoll(buf, &endptr, 10); | |
487 | assert(ret == 1234578910); | |
488 | assert(endptr == buf + 10); | |
489 | ASSERT_LABEL(ret, i_j_label); | |
490 | } | |
491 | ||
492 | void test_strtoul() { | |
493 | char buf[] = "0xffffffffffffaa"; | |
494 | char *endptr = NULL; | |
495 | dfsan_set_label(i_label, buf + 1, 1); | |
496 | dfsan_set_label(j_label, buf + 2, 1); | |
497 | long unsigned int ret = strtol(buf, &endptr, 16); | |
498 | assert(ret == 72057594037927850); | |
499 | assert(endptr == buf + 16); | |
500 | ASSERT_LABEL(ret, i_j_label); | |
501 | } | |
502 | ||
503 | void test_strtoull() { | |
504 | char buf[] = "0xffffffffffffffaa"; | |
505 | char *endptr = NULL; | |
506 | dfsan_set_label(i_label, buf + 1, 1); | |
507 | dfsan_set_label(j_label, buf + 2, 1); | |
508 | long long unsigned int ret = strtoull(buf, &endptr, 16); | |
509 | assert(ret == 0xffffffffffffffaa); | |
510 | assert(endptr == buf + 18); | |
511 | ASSERT_LABEL(ret, i_j_label); | |
512 | } | |
513 | ||
514 | void test_strtod() { | |
515 | char buf[] = "12345.76 foo"; | |
516 | char *endptr = NULL; | |
517 | dfsan_set_label(i_label, buf + 1, 1); | |
518 | dfsan_set_label(j_label, buf + 6, 1); | |
519 | double ret = strtod(buf, &endptr); | |
520 | assert(ret == 12345.76); | |
521 | assert(endptr == buf + 8); | |
522 | ASSERT_LABEL(ret, i_j_label); | |
523 | } | |
524 | ||
525 | void test_time() { | |
526 | time_t t = 0; | |
527 | dfsan_set_label(i_label, &t, 1); | |
528 | time_t ret = time(&t); | |
529 | assert(ret == t); | |
530 | assert(ret > 0); | |
531 | ASSERT_ZERO_LABEL(t); | |
532 | } | |
533 | ||
534 | void test_inet_pton() { | |
535 | char addr4[] = "127.0.0.1"; | |
536 | dfsan_set_label(i_label, addr4 + 3, 1); | |
537 | struct in_addr in4; | |
538 | int ret4 = inet_pton(AF_INET, addr4, &in4); | |
539 | assert(ret4 == 1); | |
540 | ASSERT_READ_LABEL(&in4, sizeof(in4), i_label); | |
5bcae85e | 541 | assert(in4.s_addr == htonl(0x7f000001)); |
1a4d82fc JJ |
542 | |
543 | char addr6[] = "::1"; | |
544 | dfsan_set_label(j_label, addr6 + 3, 1); | |
545 | struct in6_addr in6; | |
546 | int ret6 = inet_pton(AF_INET6, addr6, &in6); | |
547 | assert(ret6 == 1); | |
548 | ASSERT_READ_LABEL(((char *) &in6) + sizeof(in6) - 1, 1, j_label); | |
549 | } | |
550 | ||
551 | void test_localtime_r() { | |
552 | time_t t0 = 1384800998; | |
553 | struct tm t1; | |
554 | dfsan_set_label(i_label, &t0, sizeof(t0)); | |
555 | struct tm* ret = localtime_r(&t0, &t1); | |
556 | assert(ret == &t1); | |
557 | assert(t1.tm_min == 56); | |
558 | ASSERT_LABEL(t1.tm_mon, i_label); | |
559 | } | |
560 | ||
561 | void test_getpwuid_r() { | |
562 | struct passwd pwd; | |
563 | char buf[1024]; | |
564 | struct passwd *result; | |
565 | ||
566 | dfsan_set_label(i_label, &pwd, 4); | |
567 | int ret = getpwuid_r(0, &pwd, buf, sizeof(buf), &result); | |
568 | assert(ret == 0); | |
569 | assert(strcmp(pwd.pw_name, "root") == 0); | |
570 | assert(result == &pwd); | |
571 | ASSERT_READ_ZERO_LABEL(&pwd, 4); | |
572 | } | |
573 | ||
574 | void test_poll() { | |
575 | struct pollfd fd; | |
576 | fd.fd = 0; | |
577 | fd.events = POLLIN; | |
578 | dfsan_set_label(i_label, &fd.revents, sizeof(fd.revents)); | |
579 | int ret = poll(&fd, 1, 1); | |
580 | ASSERT_ZERO_LABEL(fd.revents); | |
581 | assert(ret >= 0); | |
582 | } | |
583 | ||
584 | void test_select() { | |
585 | struct timeval t; | |
586 | fd_set fds; | |
587 | t.tv_sec = 2; | |
588 | FD_SET(0, &fds); | |
589 | dfsan_set_label(i_label, &fds, sizeof(fds)); | |
590 | dfsan_set_label(j_label, &t, sizeof(t)); | |
591 | int ret = select(1, &fds, NULL, NULL, &t); | |
592 | assert(ret >= 0); | |
593 | ASSERT_ZERO_LABEL(t.tv_sec); | |
594 | ASSERT_READ_ZERO_LABEL(&fds, sizeof(fds)); | |
595 | } | |
596 | ||
597 | void test_sched_getaffinity() { | |
598 | cpu_set_t mask; | |
599 | dfsan_set_label(j_label, &mask, 1); | |
600 | int ret = sched_getaffinity(0, sizeof(mask), &mask); | |
601 | assert(ret == 0); | |
602 | ASSERT_READ_ZERO_LABEL(&mask, sizeof(mask)); | |
603 | } | |
604 | ||
605 | void test_sigemptyset() { | |
606 | sigset_t set; | |
607 | dfsan_set_label(j_label, &set, 1); | |
608 | int ret = sigemptyset(&set); | |
609 | assert(ret == 0); | |
610 | ASSERT_READ_ZERO_LABEL(&set, sizeof(set)); | |
611 | } | |
612 | ||
613 | void test_sigaction() { | |
614 | struct sigaction oldact; | |
615 | dfsan_set_label(j_label, &oldact, 1); | |
616 | int ret = sigaction(SIGUSR1, NULL, &oldact); | |
617 | assert(ret == 0); | |
618 | ASSERT_READ_ZERO_LABEL(&oldact, sizeof(oldact)); | |
619 | } | |
620 | ||
621 | void test_gettimeofday() { | |
622 | struct timeval tv; | |
623 | struct timezone tz; | |
624 | dfsan_set_label(i_label, &tv, sizeof(tv)); | |
625 | dfsan_set_label(j_label, &tz, sizeof(tz)); | |
626 | int ret = gettimeofday(&tv, &tz); | |
627 | assert(ret == 0); | |
628 | ASSERT_READ_ZERO_LABEL(&tv, sizeof(tv)); | |
629 | ASSERT_READ_ZERO_LABEL(&tz, sizeof(tz)); | |
630 | } | |
631 | ||
632 | void *pthread_create_test_cb(void *p) { | |
633 | assert(p == (void *)1); | |
634 | ASSERT_ZERO_LABEL(p); | |
635 | return (void *)2; | |
636 | } | |
637 | ||
638 | void test_pthread_create() { | |
639 | pthread_t pt; | |
640 | pthread_create(&pt, 0, pthread_create_test_cb, (void *)1); | |
641 | void *cbrv; | |
642 | pthread_join(pt, &cbrv); | |
643 | assert(cbrv == (void *)2); | |
644 | } | |
645 | ||
646 | int dl_iterate_phdr_test_cb(struct dl_phdr_info *info, size_t size, | |
647 | void *data) { | |
648 | assert(data == (void *)3); | |
649 | ASSERT_ZERO_LABEL(info); | |
650 | ASSERT_ZERO_LABEL(size); | |
651 | ASSERT_ZERO_LABEL(data); | |
652 | return 0; | |
653 | } | |
654 | ||
655 | void test_dl_iterate_phdr() { | |
656 | dl_iterate_phdr(dl_iterate_phdr_test_cb, (void *)3); | |
657 | } | |
658 | ||
659 | void test_strrchr() { | |
660 | char str1[] = "str1str1"; | |
661 | dfsan_set_label(i_label, &str1[7], 1); | |
662 | ||
663 | char *rv = strrchr(str1, 'r'); | |
664 | assert(rv == &str1[6]); | |
665 | #ifdef STRICT_DATA_DEPENDENCIES | |
666 | ASSERT_ZERO_LABEL(rv); | |
667 | #else | |
668 | ASSERT_LABEL(rv, i_label); | |
669 | #endif | |
670 | } | |
671 | ||
672 | void test_strstr() { | |
673 | char str1[] = "str1str1"; | |
674 | dfsan_set_label(i_label, &str1[3], 1); | |
675 | dfsan_set_label(j_label, &str1[5], 1); | |
676 | ||
677 | char *rv = strstr(str1, "1s"); | |
678 | assert(rv == &str1[3]); | |
679 | #ifdef STRICT_DATA_DEPENDENCIES | |
680 | ASSERT_ZERO_LABEL(rv); | |
681 | #else | |
682 | ASSERT_LABEL(rv, i_label); | |
683 | #endif | |
684 | ||
685 | rv = strstr(str1, "2s"); | |
686 | assert(rv == NULL); | |
687 | #ifdef STRICT_DATA_DEPENDENCIES | |
688 | ASSERT_ZERO_LABEL(rv); | |
689 | #else | |
690 | ASSERT_LABEL(rv, i_j_label); | |
691 | #endif | |
692 | } | |
693 | ||
694 | void test_memchr() { | |
695 | char str1[] = "str1"; | |
696 | dfsan_set_label(i_label, &str1[3], 1); | |
697 | dfsan_set_label(j_label, &str1[4], 1); | |
698 | ||
92a42be0 | 699 | char *crv = (char *) memchr(str1, 'r', sizeof(str1)); |
1a4d82fc JJ |
700 | assert(crv == &str1[2]); |
701 | ASSERT_ZERO_LABEL(crv); | |
702 | ||
92a42be0 | 703 | crv = (char *) memchr(str1, '1', sizeof(str1)); |
1a4d82fc JJ |
704 | assert(crv == &str1[3]); |
705 | #ifdef STRICT_DATA_DEPENDENCIES | |
706 | ASSERT_ZERO_LABEL(crv); | |
707 | #else | |
708 | ASSERT_LABEL(crv, i_label); | |
709 | #endif | |
710 | ||
92a42be0 | 711 | crv = (char *) memchr(str1, 'x', sizeof(str1)); |
1a4d82fc JJ |
712 | assert(!crv); |
713 | #ifdef STRICT_DATA_DEPENDENCIES | |
714 | ASSERT_ZERO_LABEL(crv); | |
715 | #else | |
716 | ASSERT_LABEL(crv, i_j_label); | |
717 | #endif | |
718 | } | |
719 | ||
720 | void alarm_handler(int unused) { | |
721 | ; | |
722 | } | |
723 | ||
724 | void test_nanosleep() { | |
725 | struct timespec req, rem; | |
726 | req.tv_sec = 1; | |
727 | req.tv_nsec = 0; | |
728 | dfsan_set_label(i_label, &rem, sizeof(rem)); | |
729 | ||
730 | // non interrupted | |
731 | int rv = nanosleep(&req, &rem); | |
732 | assert(rv == 0); | |
733 | ASSERT_ZERO_LABEL(rv); | |
734 | ASSERT_READ_LABEL(&rem, 1, i_label); | |
735 | ||
736 | // interrupted by an alarm | |
737 | signal(SIGALRM, alarm_handler); | |
738 | req.tv_sec = 3; | |
739 | alarm(1); | |
740 | rv = nanosleep(&req, &rem); | |
741 | assert(rv == -1); | |
742 | ASSERT_ZERO_LABEL(rv); | |
743 | ASSERT_READ_ZERO_LABEL(&rem, sizeof(rem)); | |
744 | } | |
745 | ||
746 | void test_socketpair() { | |
747 | int fd[2]; | |
748 | ||
749 | dfsan_set_label(i_label, fd, sizeof(fd)); | |
750 | int rv = socketpair(PF_LOCAL, SOCK_STREAM, 0, fd); | |
751 | assert(rv == 0); | |
752 | ASSERT_ZERO_LABEL(rv); | |
753 | ASSERT_READ_ZERO_LABEL(fd, sizeof(fd)); | |
754 | } | |
755 | ||
756 | void test_write() { | |
757 | int fd = open("/dev/null", O_WRONLY); | |
758 | ||
759 | char buf[] = "a string"; | |
760 | int len = strlen(buf); | |
761 | ||
762 | // The result of a write always unlabeled. | |
763 | int res = write(fd, buf, len); | |
764 | assert(res > 0); | |
765 | ASSERT_ZERO_LABEL(res); | |
766 | ||
767 | // Label all arguments to write(). | |
768 | dfsan_set_label(i_label, &(buf[3]), 1); | |
769 | dfsan_set_label(j_label, &fd, sizeof(fd)); | |
770 | dfsan_set_label(i_label, &len, sizeof(len)); | |
771 | ||
772 | // The value returned by write() should have no label. | |
773 | res = write(fd, buf, len); | |
774 | ASSERT_ZERO_LABEL(res); | |
775 | ||
776 | close(fd); | |
777 | } | |
778 | ||
92a42be0 SL |
779 | template <class T> |
780 | void test_sprintf_chunk(const char* expected, const char* format, T arg) { | |
781 | char buf[512]; | |
782 | memset(buf, 'a', sizeof(buf)); | |
783 | ||
784 | char padded_expected[512]; | |
785 | strcpy(padded_expected, "foo "); | |
786 | strcat(padded_expected, expected); | |
787 | strcat(padded_expected, " bar"); | |
788 | ||
789 | char padded_format[512]; | |
790 | strcpy(padded_format, "foo "); | |
791 | strcat(padded_format, format); | |
792 | strcat(padded_format, " bar"); | |
793 | ||
794 | // Non labelled arg. | |
795 | assert(sprintf(buf, padded_format, arg) == strlen(padded_expected)); | |
796 | assert(strcmp(buf, padded_expected) == 0); | |
797 | ASSERT_READ_LABEL(buf, strlen(padded_expected), 0); | |
798 | memset(buf, 'a', sizeof(buf)); | |
799 | ||
800 | // Labelled arg. | |
801 | dfsan_set_label(i_label, &arg, sizeof(arg)); | |
802 | assert(sprintf(buf, padded_format, arg) == strlen(padded_expected)); | |
803 | assert(strcmp(buf, padded_expected) == 0); | |
804 | ASSERT_READ_LABEL(buf, 4, 0); | |
805 | ASSERT_READ_LABEL(buf + 4, strlen(padded_expected) - 8, i_label); | |
806 | ASSERT_READ_LABEL(buf + (strlen(padded_expected) - 4), 4, 0); | |
807 | } | |
808 | ||
809 | void test_sprintf() { | |
810 | char buf[2048]; | |
811 | memset(buf, 'a', sizeof(buf)); | |
812 | ||
813 | // Test formatting (no conversion specifier). | |
814 | assert(sprintf(buf, "Hello world!") == 12); | |
815 | assert(strcmp(buf, "Hello world!") == 0); | |
816 | ASSERT_READ_LABEL(buf, sizeof(buf), 0); | |
817 | ||
818 | // Test for extra arguments. | |
819 | assert(sprintf(buf, "Hello world!", 42, "hello") == 12); | |
820 | assert(strcmp(buf, "Hello world!") == 0); | |
821 | ASSERT_READ_LABEL(buf, sizeof(buf), 0); | |
822 | ||
823 | // Test formatting & label propagation (multiple conversion specifiers): %s, | |
824 | // %d, %n, %f, and %%. | |
825 | const char* s = "world"; | |
826 | int m = 8; | |
827 | int d = 27; | |
828 | dfsan_set_label(k_label, (void *) (s + 1), 2); | |
829 | dfsan_set_label(i_label, &m, sizeof(m)); | |
830 | dfsan_set_label(j_label, &d, sizeof(d)); | |
831 | int n; | |
832 | int r = sprintf(buf, "hello %s, %-d/%d/%d %f %% %n%d", s, 2014, m, d, | |
833 | 12345.6781234, &n, 1000); | |
834 | assert(r == 42); | |
835 | assert(strcmp(buf, "hello world, 2014/8/27 12345.678123 % 1000") == 0); | |
836 | ASSERT_READ_LABEL(buf, 7, 0); | |
837 | ASSERT_READ_LABEL(buf + 7, 2, k_label); | |
838 | ASSERT_READ_LABEL(buf + 9, 9, 0); | |
839 | ASSERT_READ_LABEL(buf + 18, 1, i_label); | |
840 | ASSERT_READ_LABEL(buf + 19, 1, 0); | |
841 | ASSERT_READ_LABEL(buf + 20, 2, j_label); | |
842 | ASSERT_READ_LABEL(buf + 22, 15, 0); | |
843 | ASSERT_LABEL(r, 0); | |
844 | assert(n == 38); | |
845 | ||
846 | // Test formatting & label propagation (single conversion specifier, with | |
847 | // additional length and precision modifiers). | |
848 | test_sprintf_chunk("-559038737", "%d", 0xdeadbeef); | |
849 | test_sprintf_chunk("3735928559", "%u", 0xdeadbeef); | |
850 | test_sprintf_chunk("12345", "%i", 12345); | |
851 | test_sprintf_chunk("751", "%o", 0751); | |
852 | test_sprintf_chunk("babe", "%x", 0xbabe); | |
853 | test_sprintf_chunk("0000BABE", "%.8X", 0xbabe); | |
854 | test_sprintf_chunk("-17", "%hhd", 0xdeadbeef); | |
855 | test_sprintf_chunk("-16657", "%hd", 0xdeadbeef); | |
856 | test_sprintf_chunk("deadbeefdeadbeef", "%lx", 0xdeadbeefdeadbeef); | |
857 | test_sprintf_chunk("0xdeadbeefdeadbeef", "%p", | |
858 | (void *) 0xdeadbeefdeadbeef); | |
859 | test_sprintf_chunk("18446744073709551615", "%ju", (intmax_t) -1); | |
860 | test_sprintf_chunk("18446744073709551615", "%zu", (size_t) -1); | |
861 | test_sprintf_chunk("18446744073709551615", "%tu", (size_t) -1); | |
862 | ||
863 | test_sprintf_chunk("0x1.f9acffa7eb6bfp-4", "%a", 0.123456); | |
864 | test_sprintf_chunk("0X1.F9ACFFA7EB6BFP-4", "%A", 0.123456); | |
865 | test_sprintf_chunk("0.12346", "%.5f", 0.123456); | |
866 | test_sprintf_chunk("0.123456", "%g", 0.123456); | |
867 | test_sprintf_chunk("1.234560e-01", "%e", 0.123456); | |
868 | test_sprintf_chunk("1.234560E-01", "%E", 0.123456); | |
869 | test_sprintf_chunk("0.1234567891234560", "%.16Lf", | |
870 | (long double) 0.123456789123456); | |
871 | ||
872 | test_sprintf_chunk("z", "%c", 'z'); | |
873 | ||
874 | // %n, %s, %d, %f, and %% already tested | |
875 | ||
876 | // Test formatting with width passed as an argument. | |
877 | r = sprintf(buf, "hi %*d my %*s friend %.*f", 3, 1, 6, "dear", 4, 3.14159265359); | |
878 | assert(r == 30); | |
879 | assert(strcmp(buf, "hi 1 my dear friend 3.1416") == 0); | |
880 | } | |
881 | ||
882 | void test_snprintf() { | |
883 | char buf[2048]; | |
884 | memset(buf, 'a', sizeof(buf)); | |
885 | dfsan_set_label(0, buf, sizeof(buf)); | |
886 | const char* s = "world"; | |
887 | int y = 2014; | |
888 | int m = 8; | |
889 | int d = 27; | |
890 | dfsan_set_label(k_label, (void *) (s + 1), 2); | |
891 | dfsan_set_label(i_label, &y, sizeof(y)); | |
892 | dfsan_set_label(j_label, &m, sizeof(m)); | |
893 | int r = snprintf(buf, 19, "hello %s, %-d/%d/%d %f", s, y, m, d, | |
894 | 12345.6781234); | |
895 | // The return value is the number of bytes that would have been written to | |
896 | // the final string if enough space had been available. | |
897 | assert(r == 35); | |
898 | assert(memcmp(buf, "hello world, 2014/", 19) == 0); | |
899 | ASSERT_READ_LABEL(buf, 7, 0); | |
900 | ASSERT_READ_LABEL(buf + 7, 2, k_label); | |
901 | ASSERT_READ_LABEL(buf + 9, 4, 0); | |
902 | ASSERT_READ_LABEL(buf + 13, 4, i_label); | |
903 | ASSERT_READ_LABEL(buf + 17, 2, 0); | |
904 | ASSERT_LABEL(r, 0); | |
905 | } | |
906 | ||
1a4d82fc JJ |
907 | int main(void) { |
908 | i_label = dfsan_create_label("i", 0); | |
909 | j_label = dfsan_create_label("j", 0); | |
910 | k_label = dfsan_create_label("k", 0); | |
911 | i_j_label = dfsan_union(i_label, j_label); | |
912 | ||
913 | test_calloc(); | |
914 | test_clock_gettime(); | |
915 | test_ctime_r(); | |
916 | test_dfsan_set_write_callback(); | |
917 | test_dl_iterate_phdr(); | |
918 | test_dlopen(); | |
919 | test_fgets(); | |
920 | test_fstat(); | |
921 | test_get_current_dir_name(); | |
922 | test_getcwd(); | |
923 | test_gethostname(); | |
924 | test_getpwuid_r(); | |
925 | test_getrlimit(); | |
926 | test_getrusage(); | |
927 | test_gettimeofday(); | |
928 | test_inet_pton(); | |
929 | test_localtime_r(); | |
930 | test_memchr(); | |
931 | test_memcmp(); | |
932 | test_memcpy(); | |
933 | test_memset(); | |
934 | test_nanosleep(); | |
935 | test_poll(); | |
936 | test_pread(); | |
937 | test_pthread_create(); | |
938 | test_read(); | |
939 | test_sched_getaffinity(); | |
940 | test_select(); | |
941 | test_sigaction(); | |
942 | test_sigemptyset(); | |
92a42be0 | 943 | test_snprintf(); |
1a4d82fc | 944 | test_socketpair(); |
92a42be0 | 945 | test_sprintf(); |
1a4d82fc JJ |
946 | test_stat(); |
947 | test_strcasecmp(); | |
948 | test_strchr(); | |
949 | test_strcmp(); | |
950 | test_strcpy(); | |
951 | test_strdup(); | |
952 | test_strlen(); | |
953 | test_strncasecmp(); | |
954 | test_strncmp(); | |
955 | test_strncpy(); | |
956 | test_strrchr(); | |
957 | test_strstr(); | |
958 | test_strtod(); | |
959 | test_strtol(); | |
960 | test_strtoll(); | |
961 | test_strtoul(); | |
962 | test_strtoull(); | |
963 | test_time(); | |
964 | test_write(); | |
965 | } |