1 /* Test rejection of ill-formed password hashes.
2 Copyright (C) 2012-2018 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
18
19 #include "crypt-port.h"
20 #undef yescrypt
21
22 #include <errno.h>
23 #include <setjmp.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <signal.h>
27 #include <sys/mman.h>
28
29 /* If VERBOSE is true, passing testcases will be printed out as well
30 as failing ones. */
31 static bool verbose = false;
32
33 /* All hashes are hashes of this passphrase, an infamous error message
34 used for some forgotten can't-happen condition in Unix V6; see
35 <https://wiki.tuhs.org/doku.php?id=anecdotes:values_of_beta>. */
36 static const char phrase[] = "values of β will give rise to dom!";
37
38 /* Correct setting strings, from which we derive incorrect ones by
39 replacing one character at a time with a character that cannot
40 appear in a valid passphrase (namely ':') and/or truncating the
41 string. */
42 struct valid_setting;
43
44 /* Type of functions to use in is_valid_trunc. */
45 typedef bool (*valid_trunc_p)(const struct valid_setting *original,
46 const char *truncated);
47
48 struct valid_setting
49 {
50 /* Human-readable name for this test */
51 const char *tag;
52
53 /* The setting string */
54 const char *setting;
55
56 /* Length of the actual setting, within the setting string. This is
57 usually equal to strlen(setting), but a couple of the strings are
58 padded on the right for hash-specific reasons. */
59 size_t setting_len;
60
61 /* Given a truncation of a valid setting string, decide whether the
62 truncation is also valid. */
63 valid_trunc_p is_valid_trunc;
64
65 /* Numeric parameter for is_valid_trunc; usually the length of a
66 subfield of the setting. */
67 uint16_t is_valid_trunc_param;
68
69 /* Whether support for this hash was compiled into the library. */
70 bool enabled;
71
72 };
73
74 /* is_valid_trunc functions -- forward declarations */
75
76 static bool vt_never(const struct valid_setting *, const char *);
77 static bool vt_varsuffix(const struct valid_setting *, const char *);
78 static bool vt_sunmd5(const struct valid_setting *, const char *);
79 static bool vt_sha2gnu(const struct valid_setting *, const char *);
80 static bool vt_yescrypt(const struct valid_setting *, const char *);
81
82 /* shorthands for use in valid_cases */
83
84 #define V_( hash, setting, vt, vp) \
85 { #hash, setting, sizeof setting - 1, vt, vp, INCLUDE_##hash }
86 #define Vp_( hash, setting, vt, vp) \
87 { #hash, setting, vp, vt, vp, INCLUDE_##hash }
88 #define Vt_( hash, tag, setting, vt, vp) \
89 { #hash " (" #tag ")", setting, sizeof setting - 1, vt, vp, INCLUDE_##hash }
90 #define Vtp_(hash, tag, setting, vt, vp) \
91 { #hash " (" #tag ")", setting, vp, vt, vp, INCLUDE_##hash }
92
93 #define V( hash, setting) V_( hash, setting, vt_never, 0)
94 #define Vn( hash, vt, setting) V_( hash, setting, vt_##vt, 0)
95 #define Vp( hash, sl, setting) Vp_( hash, setting, vt_varsuffix, sl)
96 #define Vv( hash, sl, setting) V_( hash, setting, vt_varsuffix, sl)
97 #define Vt( hash, tag, setting) Vt_( hash, tag, setting, vt_never, 0)
98 #define Vtn(hash, tag, vt, setting) Vt_( hash, tag, setting, vt_##vt, 0)
99 #define Vtp(hash, tag, sl, setting) Vtp_(hash, tag, setting, vt_varsuffix, sl)
100 #define Vtv(hash, tag, sl, setting) Vt_( hash, tag, setting, vt_varsuffix, sl)
101
102 /* Each of these is a valid setting string for some algorithm,
103 from which we will derive many invalid setting strings.
104 This is an expensive test, so where possible, the number of
105 "rounds" of the hash function has been set abnormally low. */
106 static const struct valid_setting valid_cases[] =
107 {
108 V (descrypt, "Mp" ),
109 /* bigcrypt is extra special:
110 this salt is a valid descrypt salt when bigcrypt isn't enabled
111 but descrypt is;
112 truncations down to 2 are valid when descrypt is enabled, but
113 if *only* bigcrypt is enabled, then truncations can only
114 go down to 14. */
115 {
116 INCLUDE_bigcrypt ? "bigcrypt" : "descrypt (padded)",
117 "Mp............", 2, vt_varsuffix,
118 INCLUDE_descrypt ? 2 : 14,
119 INCLUDE_descrypt || INCLUDE_bigcrypt
120 },
121 V (bsdicrypt, "_J9..MJHn" ),
122 Vv (md5crypt, 3, "$1$MJHnaAke$" ),
123 Vtn(sunmd5, plain, sunmd5, "$md5$1xMeE.at$" ),
124 Vtn(sunmd5, rounds, sunmd5, "$md5,rounds=123$1xMeE.at$" ),
125 Vt (nt, plain, "$3$" ),
126 Vtp(nt, fake salt, 3, "$3$__not_used__c809a450df09a3" ),
127 Vv (sha1crypt, 11, "$sha1$123$GGXpNqoJvglVTkGU$" ),
128 Vtn(sha256crypt, plain, sha2gnu, "$5$MJHnaAkegEVYHsFK$" ),
129 Vtn(sha256crypt, rounds, sha2gnu, "$5$rounds=1000$MJHnaAkegEVYHsFK$" ),
130 Vtn(sha512crypt, plain, sha2gnu, "$6$MJHnaAkegEVYHsFK$" ),
131 Vtn(sha512crypt, rounds, sha2gnu, "$6$rounds=1000$MJHnaAkegEVYHsFK$" ),
132 V (bcrypt, "$2b$04$UBVLHeMpJ/QQCv3XqJx8zO" ),
133 V (bcrypt_a, "$2a$04$UBVLHeMpJ/QQCv3XqJx8zO" ),
134 V (bcrypt_x, "$2x$04$UBVLHeMpJ/QQCv3XqJx8zO" ),
135 V (bcrypt_y, "$2y$04$UBVLHeMpJ/QQCv3XqJx8zO" ),
136 Vv (scrypt, 14, "$7$C6..../....SodiumChloride$" ),
137 Vn (yescrypt, yescrypt, "$y$j9T$PKXc3hCOSyMqdaEQArI62/$" ),
138 Vn (gost_yescrypt, yescrypt, "$gy$j9T$PKXc3hCOSyMqdaEQArI62/$" ),
139 };
140
141 #undef V_
142 #undef Vp_
143 #undef Vt_
144 #undef Vtp_
145
146 #undef V
147 #undef Vn
148 #undef Vp
149 #undef Vv
150 #undef Vt
151 #undef Vtn
152 #undef Vtp
153 #undef Vtv
154
155 /* Additional tests of manually constructed, invalid setting
156 strings. */
157 struct invalid_setting
158 {
159 const char *tag;
160 const char *setting;
161 };
162 static const struct invalid_setting invalid_cases[] =
163 {
164 /* These strings are invalid regardless of the algorithm. */
165 { "too short 1", "/" },
166 { "too short 2", "M" },
167 { "too short 3", "$" },
168 { "too short 4", "_" },
169 { "too short 5", "." },
170 { "invalid char :", ":" },
171 { "invalid char ;", ";" },
172 { "invalid char *", "*" },
173 { "invalid char !", "!" },
174 { "invalid char \\", "\\" },
175 { "invalid char SPC", " " },
176 { "invalid char TAB", "\t" },
177 { "invalid char ^M", "\r" },
178 { "invalid char ^J", "\n" },
179 { "invalid char ^L", "\f" },
180 { "invalid char ^A", "\001" },
181 { "invalid char DEL", "\177" },
182 { "failure token 1", "*0" },
183 { "failure token 2", "*1" },
184 { "unsupported algorithm", "$un$upp0rt3d$" },
185 { "empty string", "" },
186
187 /* These strings are invalid for specific algorithms, in ways
188 that the generic error generator cannot produce. */
189 { "sunmd5 absent rounds", "$md5,rounds=$1xMeE.at$" },
190 { "sunmd5 low rounds", "$md5,rounds=0$1xMeE.at$" },
191 { "sunmd5 octal rounds", "$md5,rounds=012$1xMeE.at$" },
192 { "sunmd5 high rounds", "$md5,rounds=4294967296$1xMeE.at$" },
193 { "sha256 absent rounds", "$5$rounds=$MJHnaAkegEVYHsFK$" },
194 { "sha256 low rounds", "$5$rounds=0$MJHnaAkegEVYHsFK$" },
195 { "sha256 octal rounds", "$5$rounds=0100$MJHnaAkegEVYHsFK$" },
196 { "sha256 high rounds", "$5$rounds=4294967295$MJHnaAkegEVYHsFK$" },
197 { "sha512 absent rounds", "$6$rounds=$MJHnaAkegEVYHsFK$" },
198 { "sha512 low rounds", "$6$rounds=0$MJHnaAkegEVYHsFK$" },
199 { "sha512 octal rounds", "$6$rounds=0100$MJHnaAkegEVYHsFK$" },
200 { "sha512 high rounds", "$6$rounds=4294967295$MJHnaAkegEVYHsFK$" },
201 { "bcrypt no subtype", "$2$04$UBVLHeMpJ/QQCv3XqJx8zO" },
202 { "bcrypt_b low rounds", "$2b$03$UBVLHeMpJ/QQCv3XqJx8zO" },
203 { "bcrypt_b high rounds", "$2b$32$UBVLHeMpJ/QQCv3XqJx8zO" },
204 { "bcrypt_a low rounds", "$2a$03$UBVLHeMpJ/QQCv3XqJx8zO" },
205 { "bcrypt_a high rounds", "$2a$32$UBVLHeMpJ/QQCv3XqJx8zO" },
206 { "bcrypt_x low rounds", "$2x$03$UBVLHeMpJ/QQCv3XqJx8zO" },
207 { "bcrypt_x high rounds", "$2x$32$UBVLHeMpJ/QQCv3XqJx8zO" },
208 { "bcrypt_y low rounds", "$2y$03$UBVLHeMpJ/QQCv3XqJx8zO" },
209 { "bcrypt_y low rounds", "$2y$32$UBVLHeMpJ/QQCv3XqJx8zO" },
210 { "yescrypt short params", "$y$j9$PKXc3hCOSyMqdaEQArI62/$" },
211 { "gost-yescrypt short params", "$gy$j9$PKXc3hCOSyMqdaEQArI62/$" },
212 };
213
214 /* is_valid_trunc functions -- definitions.
215 Note: these only need to be correct for the patterns we actually test. */
216
217 /* All truncations of this setting string are invalid. */
218 static bool
219 vt_never(const struct valid_setting * ARG_UNUSED(original),
220 const char * ARG_UNUSED(truncated))
221 {
222 return false;
223 }
224
225 /* This setting string has a variable-length suffix; truncations are
226 valid as long as the result has at least `is_valid_trunc_param'
227 characters. */
228 static bool
229 vt_varsuffix(const struct valid_setting *original,
230 const char *truncated)
231 {
232 return strlen(truncated) >= original->is_valid_trunc_param;
233 }
234
235 /* Special validity rule for sunmd5, sha256crypt, and sha512crypt: ... */
236 static bool
237 vt_roundseq(const char *truncated, size_t minlen, size_t roundslen,
238 const char *roundstag1, const char *roundstag2)
239 {
240 /* ... the setting cannot be valid if it's shorter than 'minlen'
241 characters ... */
242 if (strlen(truncated) < minlen)
243 return false;
244
245 /* ... if it begins with roundstag1 or roundstag2 then a sequence of
246 digits must follow, then a dollar sign; roundstag2 may be null;
247 ... */
248 if (!strncmp(truncated, roundstag1, roundslen)
249 || (roundstag2 && !strncmp(truncated, roundstag2, roundslen)))
250 {
251 size_t i = roundslen;
252 while (truncated[i] >= '0' && truncated[i] <= '9')
253 i++;
254 if (truncated[i] != '$')
255 return false;
256 }
257
258 /* ... otherwise it's ok. */
259 return true;
260 }
261
262 /* Special validity rule for sunmd5. */
263 static bool
264 vt_sunmd5(const struct valid_setting *ARG_UNUSED(original),
265 const char *truncated)
266 {
267 return vt_roundseq(truncated, strlen("$md5$"), strlen("$md5,rounds="),
268 "$md5,rounds=", 0);
269 }
270
271 /* Special validity rule for sha256crypt and sha512crypt. */
272 static bool
273 vt_sha2gnu(const struct valid_setting *ARG_UNUSED(original),
274 const char *truncated)
275 {
276 return vt_roundseq(truncated, strlen("$5$"), strlen("$5$rounds="),
277 "$5$rounds=", "$6$rounds=");
278 }
279
280 /* Special validity rule for yescrypt and gost_yescrypt: ... */
281 static bool
282 vt_yescrypt(const struct valid_setting *ARG_UNUSED(original),
283 const char *truncated)
284 {
285 /* ... the setting string must begin with "$y$j9T$" or "$gy$j9T$"
286 (other introductory sequences are possible but those are the
287 only ones we use); ... */
288 size_t y_intro_len = strlen("$y$j9T$");
289 size_t gy_intro_len = strlen("$gy$j9T$");
290 size_t intro_len;
291 if (!strncmp(truncated, "$y$j9T$", y_intro_len))
292 intro_len = y_intro_len;
293 else if (!strncmp(truncated, "$gy$j9T$", gy_intro_len))
294 intro_len = gy_intro_len;
295 else
296 return false;
297
298 /* ... and the remainder must be one of these lengths. (I do not
299 see a pattern.) */
300 switch (strlen(truncated) - intro_len)
301 {
302 case 0:
303 case 4:
304 case 7:
305 case 8:
306 case 12:
307 case 16:
308 case 20:
309 case 22:
310 case 23:
311 return true;
312 default:
313 return false;
314 }
315 }
316
317
318 /* Some of the test setting strings contain unprintable characters,
319 which we print as hex escapes. For readability, whenever we print
320 out a setting string we pad it on the right with spaces to the
321 length of the longest setting string we have. (There is always
322 something after that on the line.) */
323 static size_t longest_setting;
324
325 static void
326 print_setting (const char *setting, bool pad)
327 {
328 size_t n = 0;
329 for (; *setting; setting++)
330 {
331 unsigned int c = (unsigned int)(unsigned char) *setting;
332 if (0x20 <= c && c <= 0x7e)
333 {
334 putchar ((int)c);
335 n += 1;
336 }
337 else
338 {
339 printf ("\\x%02x", c);
340 n += 4;
341 }
342 }
343 if (!pad)
344 return;
345 while (n < longest_setting)
346 {
347 putchar (' ');
348 n += 1;
349 }
350 }
351
352 static size_t
353 measure_setting (const char *setting)
354 {
355 size_t n = 0;
356 for (; *setting; setting++)
357 {
358 unsigned int c = (unsigned int)(unsigned char) *setting;
359 if (0x20 <= c && c <= 0x7e)
360 n += 1;
361 else
362 n += 4;
363 }
364 return n;
365 }
366
367 static void
368 measure_settings (void)
369 {
370 size_t ls = 0;
371 for (size_t i = 0; i < ARRAY_SIZE (valid_cases); i++)
372 ls = MAX (ls, measure_setting(valid_cases[i].setting));
373
374 for (size_t i = 0; i < ARRAY_SIZE (invalid_cases); i++)
375 ls = MAX (ls, measure_setting(invalid_cases[i].setting));
376
377 longest_setting = ls;
378 }
379
380 static void
381 print_result (const char *result, const char *setting,
382 const char *tag, bool expected_valid)
383 {
384 printf ("%s: ", result);
385 print_setting (setting, true);
386 printf (" (%s, %s)", tag, expected_valid ? "valid" : "invalid");
387 }
388
389 /* Part of what we're testing, is whether any of the hashing methods
390 can read past the end of a properly terminated C string that
391 happens to contain an invalid setting. We do this by placing the
392 invalid setting right next to a page of inaccessible memory and
393 trapping the fault. */
394 static volatile sig_atomic_t signal_loop = 0;
395 static sigjmp_buf env;
396 static void
397 segv_handler (int sig)
398 {
399 if (signal_loop == 0)
400 {
401 signal_loop = 1;
402 siglongjmp (env, sig);
403 }
404 else
405 {
406 signal (sig, SIG_DFL);
407 raise (sig);
408 }
409 }
410
411 /* We use only crypt_rn in this test, because it only exercises the
412 error handling logic within the hashing methods, not the
413 higher-level error handling logic that varies slightly among the
414 entry points (that's all taken care of in crypt-badargs.c). We use
415 crypt_rn instead of crypt_r so that this test does not need to vary
416 any of its logic based on --enable-failure-tokens. */
417 static bool
418 test_one_setting (const char *setting, size_t l_setting,
419 const char *tag, bool expected_valid,
420 struct crypt_data *cd)
421 {
422 volatile bool fail = false;
423 signal_loop = 0;
424 int sig = sigsetjmp (env, 1);
425 if (!sig)
426 {
427 char *retval = crypt_rn (phrase, setting, cd, (int) sizeof *cd);
428 if (expected_valid)
429 {
430 if (!retval)
431 {
432 fail = true;
433 print_result ("FAIL", setting, tag, expected_valid);
434 puts(": returned NULL");
435 }
436 else if (retval != cd->output)
437 {
438 fail = true;
439 print_result ("FAIL", setting, tag, expected_valid);
440 printf(": returned %p, should be %p\n",
441 (const void *)retval, (const void *)cd->output);
442 }
443 else if (strncmp (retval, setting, l_setting))
444 {
445 fail = true;
446 print_result("FAIL", setting, tag, expected_valid);
447 fputs(": got non-matching ", stdout);
448 print_setting(retval, false);
449 putchar('\n');
450 }
451 }
452 else
453 {
454 if (retval)
455 {
456 fail = true;
457 print_result ("FAIL", setting, tag, expected_valid);
458 fputs(": expected NULL, got ", stdout);
459 print_setting (retval, false);
460 putchar('\n');
461 }
462 }
463 }
464 else
465 {
466 fail = true;
467 print_result("FAIL", setting, tag, expected_valid);
468 printf(": %s\n", strsignal (sig));
469 }
470
471 if (verbose && !fail)
472 {
473 print_result("PASS", setting, tag, expected_valid);
474 putchar('\n');
475 }
476
477 return fail;
478 }
479
480 static bool
481 test_one_valid(const struct valid_setting *tc,
482 char *page, size_t pagesize, struct crypt_data *cd)
483 {
484 /* Caution: tc->setting_len is _not_ always equal to strlen(tc->setting).
485 Sometimes it is smaller. */
486 size_t l_setting = strlen(tc->setting) + 1;
487 char *setting = page + pagesize - l_setting;
488 memcpy(setting, tc->setting, l_setting);
489
490 /* crypt_rn() using this setting, unmodified, is expected to
491 succeed, unless the hash function is disabled. */
492 if (test_one_setting (setting, tc->setting_len, tc->tag, tc->enabled, cd))
493 return true;
494
495 /* Rechecking the hash with the full output should also succeed.
496 In this subtest we expect to get the same _complete hash_
497 back out, not just the same setting. */
498 if (tc->enabled)
499 {
500 size_t l_hash = strlen (cd->output);
501 char *p = page + pagesize - (l_hash + 1);
502 assert (l_hash + 1 <= CRYPT_OUTPUT_SIZE);
503 memcpy (p, cd->output, l_hash + 1);
504
505 if (test_one_setting (p, l_hash, tc->tag, true, cd))
506 return true;
507
508 /* When crypt() is called with a complete hashed passphrase as the
509 setting string, the hashing method must not look at the hash
510 component of the setting _at all_. We test this by supplying a
511 string with one extra character, an A, which _could_ be part of
512 the hash component for all supported methods, but which is much
513 too short by itself. This should produce the same complete hash
514 as the previous test. (It has to be a character which _could_
515 appear, because the generic crypt() machinery rejects setting
516 strings containing invalid characters in any position.)
517
518 Super special case: Don't do this subtest for sunmd5,
519 because, due to a bug in its original implementation, the
520 first character after the end of the salt _does_ affect the
521 hash output. We have to preserve this bug for compatibility
522 with existing sunmd5 hashed passphrases. */
523 if (!INCLUDE_sunmd5 || strncmp(tc->setting, "$md5", 4))
524 {
525 p = page + pagesize - (l_hash + 1 + l_setting + 1);
526 memcpy (p, cd->output, l_hash + 1);
527
528 char *settingA = page + pagesize - (l_setting + 1);
529 memcpy(settingA, tc->setting, l_setting - 1);
530 settingA[l_setting - 1] = 'A';
531 settingA[l_setting - 0] = '\0';
532 if (test_one_setting (settingA, tc->setting_len, tc->tag, true, cd))
533 return true;
534 if (strcmp (cd->output, p))
535 {
536 print_result ("FAIL", settingA, tc->tag, true);
537 /* Since cd->output and p are both hashed passphrases, not
538 handcrafted invalid setting strings, we can safely print
539 them with %s. */
540 printf (": expected %s, got %s\n", p, cd->output);
541 return true;
542 }
543 else if (verbose)
544 {
545 print_result ("PASS", settingA, tc->tag, true);
546 printf (": got %s, as expected\n", cd->output);
547 }
548 }
549
550 /* Restore the original data at 'setting', as expected by code
551 below. */
552 memcpy(setting, tc->setting, l_setting);
553 }
554
555 /* The rest of the subtests in this function are logically independent. */
556 bool failed = false;
557
558 /* Replacing any one character of this setting with a ':', leaving
559 the rest of the string intact, should cause crypt_rn to fail. */
560 for (size_t i = 0; i < l_setting - 1; i++)
561 {
562 char saved = setting[i];
563 setting[i] = ':';
564 failed |= test_one_setting(setting, tc->setting_len, tc->tag, false, cd);
565 setting[i] = saved;
566 }
567
568 /* Chop off the last character of the setting string and test that.
569 Then, replace the new last character of the setting string with a
570 colon, and test that. (This is different from the earlier test
571 where we replaced each character in turn with a colon but kept
572 the rest of the string intact, because the hashing method might
573 be calling strlen() on the setting string.) Repeat these two
574 steps until we have just one character left, then stop.
575
576 For instance, if the original setting string is
577 $1$MJHnaAke$
578 then we test
579 $1$MJHnaAke
580 $1$MJHnaAk:
581 $1$MJHnaAk
582 $1$MJHnaA:
583 $1$MJHnaA
584 ...
585 $1
586 $:
587
588 ($1$MJHnaAke: would have been tested by the loop above. All the
589 single-character strings that can be a prefix of a setting string
590 from valid_cases---"$", "_", "M"---are tested by invalid_cases,
591 is ":".)
592
593 Up till this point l_setting has been _one more than_
594 strlen(setting), but in this loop it is more convenient to have
595 it be equal to strlen(setting). */
596 l_setting -= 1;
597
598 while (l_setting > 2)
599 {
600 memmove(setting + 1, setting, l_setting - 1);
601 setting += 1;
602 l_setting -= 1;
603 failed |= test_one_setting(setting, MIN (l_setting, tc->setting_len),
604 tc->tag,
605 tc->enabled
606 && tc->is_valid_trunc(tc, setting),
607 cd);
608 page[pagesize - 2] = ':';
609 failed |= test_one_setting(setting, l_setting, tc->tag, false, cd);
610 }
611
612 return failed;
613 }
614
615 static bool
616 test_one_invalid(const struct invalid_setting *tc,
617 char *page, size_t pagesize, struct crypt_data *cd)
618 {
619 size_t l_setting = strlen(tc->setting) + 1;
620 char *setting = page + pagesize - l_setting;
621 memcpy(setting, tc->setting, l_setting);
622 return test_one_setting(setting, l_setting - 1, tc->tag, false, cd);
623 }
624
625 static bool
626 do_tests(char *page, size_t pagesize)
627 {
628 bool failed = false;
629
630 struct crypt_data cd;
631 memset (&cd, 0, sizeof cd);
632
633 for (size_t i = 0; i < ARRAY_SIZE (valid_cases); i++)
634 failed |= test_one_valid (&valid_cases[i], page, pagesize, &cd);
635
636 for (size_t i = 0; i < ARRAY_SIZE (invalid_cases); i++)
637 failed |= test_one_invalid (&invalid_cases[i], page, pagesize, &cd);
638
639 return failed;
640 }
641
642 int
643 main (int argc, char **argv)
644 {
645 if (argc <= 1)
646 ;
647 else if (argc == 2
648 && (!strcmp(argv[1], "-v")
649 || !strcmp(argv[1], "--verbose")))
650 verbose = true;
651 else
652 {
653 fprintf(stderr, "usage: %s [-v | --verbose]\n", argv[0]);
654 return 99;
655 }
656
657 if (setvbuf(stdout, 0, _IOLBF, 0) || setvbuf(stderr, 0, _IOLBF, 0))
658 {
659 perror ("setvbuf");
660 return 99;
661 }
662
663 /* Set up a two-page region whose first page is read-write and
664 whose second page is inaccessible. */
665 long pagesize_l = sysconf (_SC_PAGESIZE);
666 if (pagesize_l < (long) CRYPT_OUTPUT_SIZE)
667 {
668 printf ("ERROR: pagesize of %ld is too small\n", pagesize_l);
669 return 99;
670 }
671
672 size_t pagesize = (size_t) pagesize_l;
673 char *page = mmap (0, pagesize * 2, PROT_READ|PROT_WRITE,
674 MAP_PRIVATE|MAP_ANON, -1, 0);
675 if (page == MAP_FAILED)
676 {
677 perror ("mmap");
678 return 99;
679 }
680 memset (page, 'x', pagesize * 2);
681 if (mprotect (page + pagesize, pagesize, PROT_NONE))
682 {
683 perror ("mprotect");
684 return 99;
685 }
686
687 struct sigaction sa, os, ob;
688 sigfillset (&sa.sa_mask);
689 sa.sa_flags = SA_RESTART;
690 sa.sa_handler = segv_handler;
691 if (sigaction (SIGBUS, &sa, &ob) || sigaction (SIGSEGV, &sa, &os))
692 {
693 perror ("sigaction");
694 return 1;
695 }
696
697 measure_settings();
698 bool failed = do_tests (page, pagesize);
699
700 sigaction (SIGBUS, &ob, 0);
701 sigaction (SIGSEGV, &os, 0);
702
703 return failed;
704 }