diff options
author | matthew <> | 2014-07-11 00:38:17 +0000 |
---|---|---|
committer | matthew <> | 2014-07-11 00:38:17 +0000 |
commit | 0edafc21e5a0226078d996162aaab2e0b91b8a0e (patch) | |
tree | c4fa81a7f58e70f908e4dd71b7f7e0cb3a550533 /src | |
parent | c8e58b52150f7c13e3281d122ed2c3ff38b6a1d5 (diff) | |
download | openbsd-0edafc21e5a0226078d996162aaab2e0b91b8a0e.tar.gz openbsd-0edafc21e5a0226078d996162aaab2e0b91b8a0e.tar.bz2 openbsd-0edafc21e5a0226078d996162aaab2e0b91b8a0e.zip |
Fix explicit_bzero regress for Solaris and OS X compatibility
Solaris and OS X clobber the signal stack when returning to the main
stack, which caused the original testing strategy (inspecting the
signal stack once we're back on the main stack) to fail.
To be compatible with this behavior, the regress test now inspects the
signal stack space while we're still executing on it. This is a bit
iffy because we might clobber it ourselves while inspecting it, but we
as long as its not completely clobbered we should be okay.
thx bcook for the Solaris test account
Diffstat (limited to 'src')
-rw-r--r-- | src/regress/lib/libc/explicit_bzero/explicit_bzero.c | 95 |
1 files changed, 68 insertions, 27 deletions
diff --git a/src/regress/lib/libc/explicit_bzero/explicit_bzero.c b/src/regress/lib/libc/explicit_bzero/explicit_bzero.c index d1e4d1494e..c2b677ca6a 100644 --- a/src/regress/lib/libc/explicit_bzero/explicit_bzero.c +++ b/src/regress/lib/libc/explicit_bzero/explicit_bzero.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: explicit_bzero.c,v 1.4 2014/07/09 23:54:00 matthew Exp $ */ | 1 | /* $OpenBSD: explicit_bzero.c,v 1.5 2014/07/11 00:38:17 matthew Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2014 Google Inc. | 3 | * Copyright (c) 2014 Google Inc. |
4 | * | 4 | * |
@@ -25,7 +25,18 @@ | |||
25 | #define ASSERT_NE(a, b) assert((a) != (b)) | 25 | #define ASSERT_NE(a, b) assert((a) != (b)) |
26 | #define ASSERT_GE(a, b) assert((a) >= (b)) | 26 | #define ASSERT_GE(a, b) assert((a) >= (b)) |
27 | 27 | ||
28 | static char altstack[SIGSTKSZ]; | 28 | /* 128 bits of random data. */ |
29 | static const char secret[16] = { | ||
30 | 0xa0, 0x6c, 0x0c, 0x81, 0xba, 0xd8, 0x5b, 0x0c, | ||
31 | 0xb0, 0xd6, 0xd4, 0xe3, 0xeb, 0x52, 0x5f, 0x96, | ||
32 | }; | ||
33 | |||
34 | enum { | ||
35 | SECRETCOUNT = 64, | ||
36 | SECRETBYTES = SECRETCOUNT * sizeof(secret) | ||
37 | }; | ||
38 | |||
39 | static char altstack[SIGSTKSZ + SECRETBYTES]; | ||
29 | 40 | ||
30 | static void | 41 | static void |
31 | setup_stack(void) | 42 | setup_stack(void) |
@@ -85,17 +96,6 @@ call_on_stack(void (*fn)(int)) | |||
85 | ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &oldsigset, NULL)); | 96 | ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &oldsigset, NULL)); |
86 | } | 97 | } |
87 | 98 | ||
88 | /* 128 bits of random data. */ | ||
89 | static const char secret[16] = { | ||
90 | 0xa0, 0x6c, 0x0c, 0x81, 0xba, 0xd8, 0x5b, 0x0c, | ||
91 | 0xb0, 0xd6, 0xd4, 0xe3, 0xeb, 0x52, 0x5f, 0x96, | ||
92 | }; | ||
93 | |||
94 | enum { | ||
95 | SECRETCOUNT = 16, | ||
96 | SECRETBYTES = SECRETCOUNT * sizeof(secret) | ||
97 | }; | ||
98 | |||
99 | static void | 99 | static void |
100 | populate_secret(char *buf, size_t len) | 100 | populate_secret(char *buf, size_t len) |
101 | { | 101 | { |
@@ -110,23 +110,54 @@ populate_secret(char *buf, size_t len) | |||
110 | ASSERT_EQ(0, close(fds[0])); | 110 | ASSERT_EQ(0, close(fds[0])); |
111 | } | 111 | } |
112 | 112 | ||
113 | static void | 113 | static int |
114 | test_without_bzero(int signo) | 114 | count_secrets(const char *buf) |
115 | { | ||
116 | int res = 0; | ||
117 | size_t i; | ||
118 | for (i = 0; i < SECRETCOUNT; i++) { | ||
119 | if (memcmp(buf + i * sizeof(secret), secret, | ||
120 | sizeof(secret)) == 0) | ||
121 | res += 1; | ||
122 | } | ||
123 | return (res); | ||
124 | } | ||
125 | |||
126 | static char * | ||
127 | test_without_bzero() | ||
115 | { | 128 | { |
116 | char buf[SECRETBYTES]; | 129 | char buf[SECRETBYTES]; |
117 | assert_on_stack(); | 130 | assert_on_stack(); |
118 | populate_secret(buf, sizeof(buf)); | 131 | populate_secret(buf, sizeof(buf)); |
119 | ASSERT_NE(NULL, memmem(altstack, sizeof(altstack), buf, sizeof(buf))); | 132 | char *res = memmem(altstack, sizeof(altstack), buf, sizeof(buf)); |
133 | ASSERT_NE(NULL, res); | ||
134 | return (res); | ||
120 | } | 135 | } |
121 | 136 | ||
122 | static void | 137 | static char * |
123 | test_with_bzero(int signo) | 138 | test_with_bzero() |
124 | { | 139 | { |
125 | char buf[SECRETBYTES]; | 140 | char buf[SECRETBYTES]; |
126 | assert_on_stack(); | 141 | assert_on_stack(); |
127 | populate_secret(buf, sizeof(buf)); | 142 | populate_secret(buf, sizeof(buf)); |
128 | ASSERT_NE(NULL, memmem(altstack, sizeof(altstack), buf, sizeof(buf))); | 143 | char *res = memmem(altstack, sizeof(altstack), buf, sizeof(buf)); |
144 | ASSERT_NE(NULL, res); | ||
129 | explicit_bzero(buf, sizeof(buf)); | 145 | explicit_bzero(buf, sizeof(buf)); |
146 | return (res); | ||
147 | } | ||
148 | |||
149 | static void | ||
150 | do_test_without_bzero(int signo) | ||
151 | { | ||
152 | char *buf = test_without_bzero(); | ||
153 | ASSERT_GE(count_secrets(buf), 1); | ||
154 | } | ||
155 | |||
156 | static void | ||
157 | do_test_with_bzero(int signo) | ||
158 | { | ||
159 | char *buf = test_without_bzero(); | ||
160 | ASSERT_GE(count_secrets(buf), 0); | ||
130 | } | 161 | } |
131 | 162 | ||
132 | int | 163 | int |
@@ -135,22 +166,32 @@ main() | |||
135 | setup_stack(); | 166 | setup_stack(); |
136 | 167 | ||
137 | /* | 168 | /* |
169 | * Solaris and OS X clobber the signal stack after returning to the | ||
170 | * normal stack, so we need to inspect altstack while we're still | ||
171 | * running on it. Unfortunately, this means we risk clobbering the | ||
172 | * buffer ourselves. | ||
173 | * | ||
174 | * To minimize this risk, test_with{,out}_bzero() are responsible for | ||
175 | * locating the offset of their buf variable within altstack, and | ||
176 | * and returning that address. Then we can simply memcmp() repeatedly | ||
177 | * to count how many instances of secret we found. | ||
178 | */ | ||
179 | |||
180 | /* | ||
138 | * First, test that if we *don't* call explicit_bzero, that we | 181 | * First, test that if we *don't* call explicit_bzero, that we |
139 | * *are* able to find the secret data on the stack. This | 182 | * *are* able to find at least one instance of the secret data still |
140 | * sanity checks that call_on_stack() and populare_secret() | 183 | * on the stack. This sanity checks that call_on_stack() and |
141 | * work as intended. | 184 | * populate_secret() work as intended. |
142 | */ | 185 | */ |
143 | memset(altstack, 0, sizeof(altstack)); | 186 | memset(altstack, 0, sizeof(altstack)); |
144 | call_on_stack(test_without_bzero); | 187 | call_on_stack(do_test_without_bzero); |
145 | ASSERT_NE(NULL, memmem(altstack, sizeof(altstack), secret, sizeof(secret))); | ||
146 | 188 | ||
147 | /* | 189 | /* |
148 | * Now test with a call to explicit_bzero() and check that we | 190 | * Now test with a call to explicit_bzero() and check that we |
149 | * *don't* find the secret data. | 191 | * *don't* find any instances of the secret data. |
150 | */ | 192 | */ |
151 | memset(altstack, 0, sizeof(altstack)); | 193 | memset(altstack, 0, sizeof(altstack)); |
152 | call_on_stack(test_with_bzero); | 194 | call_on_stack(do_test_with_bzero); |
153 | ASSERT_EQ(NULL, memmem(altstack, sizeof(altstack), secret, sizeof(secret))); | ||
154 | 195 | ||
155 | return (0); | 196 | return (0); |
156 | } | 197 | } |