Print this page
1667 pkcs11 may deadlock when multi-threaded consumers fork
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/lib/libcryptoutil/common/random.c
+++ new/usr/src/lib/libcryptoutil/common/random.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
|
↓ open down ↓ |
13 lines elided |
↑ open up ↑ |
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24 + * Copyright 2014, OmniTI Computer Consulting, Inc. All rights reserved.
24 25 */
25 26
26 27 #include <stdio.h>
27 28 #include <unistd.h>
28 29 #include <errno.h>
29 30 #include <string.h>
30 31 #include <fcntl.h>
31 32 #include <locale.h>
32 33 #include <stdarg.h>
33 34 #include <cryptoutil.h>
34 35 #include <pthread.h>
35 36
37 +#pragma init(pkcs11_random_init)
36 38
37 39 static pthread_mutex_t random_mutex = PTHREAD_MUTEX_INITIALIZER;
38 40 static pthread_mutex_t urandom_mutex = PTHREAD_MUTEX_INITIALIZER;
39 41
40 42 static pthread_mutex_t random_seed_mutex = PTHREAD_MUTEX_INITIALIZER;
41 43 static pthread_mutex_t urandom_seed_mutex = PTHREAD_MUTEX_INITIALIZER;
42 44
43 45 #define RANDOM_DEVICE "/dev/random" /* random device name */
44 46 #define URANDOM_DEVICE "/dev/urandom" /* urandom device name */
45 47
46 48 static int random_fd = -1;
47 49 static int urandom_fd = -1;
48 50
49 51 static int random_seed_fd = -1;
50 52 static int urandom_seed_fd = -1;
51 53
52 54
53 55 /*
54 56 * Equivalent of open(2) insulated from EINTR.
55 57 * Also sets close-on-exec.
56 58 */
57 59 int
58 60 open_nointr(const char *path, int oflag, ...)
59 61 {
60 62 int fd;
61 63 mode_t pmode;
62 64 va_list alist;
63 65
64 66 va_start(alist, oflag);
65 67 pmode = va_arg(alist, mode_t);
66 68 va_end(alist);
67 69
68 70 do {
69 71 if ((fd = open(path, oflag, pmode)) >= 0) {
70 72 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
71 73 break;
72 74 }
73 75 /* errno definitely set by failed open() */
74 76 } while (errno == EINTR);
75 77 return (fd);
76 78 }
77 79
78 80 /*
79 81 * Equivalent of read(2) insulated from EINTR.
80 82 */
81 83 ssize_t
82 84 readn_nointr(int fd, void *dbuf, size_t dlen)
83 85 {
84 86 char *marker = dbuf;
85 87 size_t left = dlen;
86 88 ssize_t nread = 0, err;
87 89
88 90 for (err = 0; left > 0 && nread != -1; marker += nread, left -= nread) {
89 91 if ((nread = read(fd, marker, left)) < 0) {
90 92 if (errno == EINTR) { /* keep trying */
91 93 nread = 0;
92 94 continue;
93 95 }
94 96 err = nread; /* hard error */
95 97 break;
96 98 } else if (nread == 0) {
97 99 break;
98 100 }
99 101 }
100 102 return (err != 0 ? err : dlen - left);
101 103 }
102 104
103 105 /*
104 106 * Equivalent of write(2) insulated from EINTR.
105 107 */
106 108 ssize_t
107 109 writen_nointr(int fd, void *dbuf, size_t dlen)
108 110 {
109 111 char *marker = dbuf;
110 112 size_t left = dlen;
111 113 ssize_t nwrite = 0, err;
112 114
113 115 for (err = 0; left > 0 && nwrite != -1; marker += nwrite,
114 116 left -= nwrite) {
115 117 if ((nwrite = write(fd, marker, left)) < 0) {
116 118 if (errno == EINTR) { /* keep trying */
117 119 nwrite = 0;
118 120 continue;
119 121 }
120 122 err = nwrite; /* hard error */
121 123 break;
122 124 } else if (nwrite == 0) {
123 125 break;
124 126 }
125 127 }
126 128 return (err != 0 ? err : dlen - left);
127 129 }
128 130
129 131 /*
130 132 * Opens the random number generator devices if not already open.
131 133 * Always returns the opened fd of the device, or error.
132 134 */
133 135 static int
134 136 pkcs11_open_common(int *fd, pthread_mutex_t *mtx, const char *dev, int oflag)
135 137 {
136 138 (void) pthread_mutex_lock(mtx);
137 139 if (*fd < 0)
138 140 *fd = open_nointr(dev, oflag);
139 141 (void) pthread_mutex_unlock(mtx);
140 142
141 143 return (*fd);
142 144 }
143 145
144 146 static int
145 147 pkcs11_open_random(void)
146 148 {
147 149 return (pkcs11_open_common(&random_fd, &random_mutex,
148 150 RANDOM_DEVICE, O_RDONLY));
149 151 }
150 152
151 153 static int
152 154 pkcs11_open_urandom(void)
153 155 {
154 156 return (pkcs11_open_common(&urandom_fd, &urandom_mutex,
155 157 URANDOM_DEVICE, O_RDONLY));
156 158 }
157 159
158 160 static int
159 161 pkcs11_open_random_seed(void)
160 162 {
161 163 return (pkcs11_open_common(&random_seed_fd, &random_seed_mutex,
162 164 RANDOM_DEVICE, O_WRONLY));
163 165 }
164 166
165 167 static int
166 168 pkcs11_open_urandom_seed(void)
167 169 {
168 170 return (pkcs11_open_common(&urandom_seed_fd, &urandom_seed_mutex,
169 171 URANDOM_DEVICE, O_WRONLY));
170 172 }
171 173
172 174 /*
173 175 * Close the random number generator devices if already open.
|
↓ open down ↓ |
128 lines elided |
↑ open up ↑ |
174 176 */
175 177 static void
176 178 pkcs11_close_common(int *fd, pthread_mutex_t *mtx)
177 179 {
178 180 (void) pthread_mutex_lock(mtx);
179 181 (void) close(*fd);
180 182 *fd = -1;
181 183 (void) pthread_mutex_unlock(mtx);
182 184 }
183 185
184 -void
186 +static void
185 187 pkcs11_close_random(void)
186 188 {
187 189 pkcs11_close_common(&random_fd, &random_mutex);
188 190 }
189 191
190 -void
192 +static void
191 193 pkcs11_close_urandom(void)
192 194 {
193 195 pkcs11_close_common(&urandom_fd, &urandom_mutex);
194 196 }
195 197
196 198 static void
197 199 pkcs11_close_random_seed(void)
198 200 {
199 201 pkcs11_close_common(&random_seed_fd, &random_seed_mutex);
200 202 }
201 203
202 -void
204 +static void
203 205 pkcs11_close_urandom_seed(void)
204 206 {
205 207 pkcs11_close_common(&urandom_seed_fd, &urandom_seed_mutex);
206 208 }
207 209
208 210 /*
209 211 * Read from the random number generator devices.
210 212 */
211 213 static size_t
212 214 pkcs11_read_common(int *fd, pthread_mutex_t *mtx, void *dbuf, size_t dlen)
213 215 {
214 216 size_t n;
215 217
216 218 (void) pthread_mutex_lock(mtx);
217 219 n = readn_nointr(*fd, dbuf, dlen);
218 220 (void) pthread_mutex_unlock(mtx);
219 221
220 222 return (n);
221 223 }
222 224
223 225 static size_t
224 226 pkcs11_read_random(void *dbuf, size_t dlen)
225 227 {
226 228 return (pkcs11_read_common(&random_fd, &random_mutex, dbuf, dlen));
227 229 }
228 230
229 231 static size_t
230 232 pkcs11_read_urandom(void *dbuf, size_t dlen)
231 233 {
232 234 return (pkcs11_read_common(&urandom_fd, &urandom_mutex, dbuf, dlen));
233 235 }
234 236
235 237 /*
236 238 * Write to the random number generator devices.
237 239 */
238 240 static size_t
239 241 pkcs11_write_common(int *fd, pthread_mutex_t *mtx, void *dbuf, size_t dlen)
240 242 {
241 243 size_t n;
242 244
243 245 (void) pthread_mutex_lock(mtx);
244 246 n = writen_nointr(*fd, dbuf, dlen);
245 247 (void) pthread_mutex_unlock(mtx);
246 248
247 249 return (n);
248 250 }
249 251
250 252 static size_t
251 253 pkcs11_write_random_seed(void *dbuf, size_t dlen)
252 254 {
253 255 return (pkcs11_write_common(&random_seed_fd, &random_seed_mutex,
254 256 dbuf, dlen));
255 257 }
256 258
257 259 static size_t
258 260 pkcs11_write_urandom_seed(void *dbuf, size_t dlen)
259 261 {
260 262 return (pkcs11_write_common(&urandom_seed_fd, &urandom_seed_mutex,
261 263 dbuf, dlen));
262 264 }
263 265
264 266 /*
265 267 * Seed /dev/random with the data in the buffer.
266 268 */
267 269 int
268 270 pkcs11_seed_random(void *sbuf, size_t slen)
269 271 {
270 272 int rv;
271 273
272 274 if (sbuf == NULL || slen == 0)
273 275 return (0);
274 276
275 277 /* Seeding error could mean it's not supported (errno = EACCES) */
276 278 if (pkcs11_open_random_seed() < 0)
277 279 return (-1);
278 280
279 281 rv = -1;
280 282 if (pkcs11_write_random_seed(sbuf, slen) == slen)
281 283 rv = 0;
282 284
283 285 pkcs11_close_random_seed();
284 286 return (rv);
285 287 }
286 288
287 289 /*
288 290 * Seed /dev/urandom with the data in the buffer.
289 291 */
290 292 int
291 293 pkcs11_seed_urandom(void *sbuf, size_t slen)
292 294 {
293 295 int rv;
294 296
295 297 if (sbuf == NULL || slen == 0)
296 298 return (0);
297 299
298 300 /* Seeding error could mean it's not supported (errno = EACCES) */
299 301 if (pkcs11_open_urandom_seed() < 0)
300 302 return (-1);
301 303
302 304 rv = -1;
303 305 if (pkcs11_write_urandom_seed(sbuf, slen) == slen)
304 306 rv = 0;
305 307
306 308 pkcs11_close_urandom_seed();
307 309 return (rv);
308 310 }
309 311
310 312 /*
311 313 * Put the requested amount of random data into a preallocated buffer.
312 314 * Good for token key data, persistent objects.
313 315 */
314 316 int
315 317 pkcs11_get_random(void *dbuf, size_t dlen)
316 318 {
317 319 if (dbuf == NULL || dlen == 0)
318 320 return (0);
319 321
320 322 /* Read random data directly from /dev/random */
321 323 if (pkcs11_open_random() < 0)
322 324 return (-1);
323 325
324 326 if (pkcs11_read_random(dbuf, dlen) == dlen)
325 327 return (0);
326 328 return (-1);
327 329 }
328 330
329 331 /*
330 332 * Put the requested amount of random data into a preallocated buffer.
331 333 * Good for passphrase salts, initialization vectors.
332 334 */
333 335 int
334 336 pkcs11_get_urandom(void *dbuf, size_t dlen)
335 337 {
336 338 if (dbuf == NULL || dlen == 0)
337 339 return (0);
338 340
339 341 /* Read random data directly from /dev/urandom */
340 342 if (pkcs11_open_urandom() < 0)
341 343 return (-1);
342 344
343 345 if (pkcs11_read_urandom(dbuf, dlen) == dlen)
344 346 return (0);
345 347 return (-1);
346 348 }
347 349
348 350 /*
349 351 * Same as pkcs11_get_urandom but ensures non zero data.
350 352 */
351 353 int
352 354 pkcs11_get_nzero_urandom(void *dbuf, size_t dlen)
353 355 {
354 356 char extrarand[32];
355 357 size_t bytesleft = 0;
356 358 size_t i = 0;
357 359
358 360 /* Start with some random data */
359 361 if (pkcs11_get_urandom(dbuf, dlen) < 0)
360 362 return (-1);
361 363
362 364 /* Walk through data replacing any 0 bytes with more random data */
363 365 while (i < dlen) {
364 366 if (((char *)dbuf)[i] != 0) {
365 367 i++;
366 368 continue;
367 369 }
368 370
|
↓ open down ↓ |
156 lines elided |
↑ open up ↑ |
369 371 if (bytesleft == 0) {
370 372 bytesleft = sizeof (extrarand);
371 373 if (pkcs11_get_urandom(extrarand, bytesleft) < 0)
372 374 return (-1);
373 375 }
374 376 bytesleft--;
375 377
376 378 ((char *)dbuf)[i] = extrarand[bytesleft];
377 379 }
378 380 return (0);
381 +}
382 +
383 +static void
384 +pkcs11_random_prepare(void)
385 +{
386 + /*
387 + * NOTE - None of these are acquired more than one at a time.
388 + * I can therefore acquire all four without fear of deadlock.
389 + */
390 + (void) pthread_mutex_lock(&random_mutex);
391 + (void) pthread_mutex_lock(&urandom_mutex);
392 + (void) pthread_mutex_lock(&random_seed_mutex);
393 + (void) pthread_mutex_lock(&urandom_seed_mutex);
394 +}
395 +
396 +static void
397 +pkcs11_random_parent_post(void)
398 +{
399 + /* Drop the mutexes and get back to work! */
400 + (void) pthread_mutex_unlock(&urandom_seed_mutex);
401 + (void) pthread_mutex_unlock(&random_seed_mutex);
402 + (void) pthread_mutex_unlock(&urandom_mutex);
403 + (void) pthread_mutex_unlock(&random_mutex);
404 +}
405 +
406 +static void
407 +pkcs11_random_child_post(void)
408 +{
409 + pkcs11_random_parent_post();
410 +
411 + /* Also, close the FDs, just in case. */
412 + pkcs11_close_random();
413 + pkcs11_close_urandom();
414 + pkcs11_close_random_seed();
415 + pkcs11_close_urandom_seed();
416 +}
417 +
418 +static void
419 +pkcs11_random_init(void)
420 +{
421 + (void) pthread_atfork(pkcs11_random_prepare, pkcs11_random_parent_post,
422 + pkcs11_random_child_post);
379 423 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX