Print this page
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/common/io/random.c
+++ new/usr/src/uts/common/io/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
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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
22 22 * Use is subject to license terms.
23 23 *
24 24 * Copyright 2016 Joyent, Inc.
25 25 */
26 26
27 27
28 28 /*
29 29 * Random number generator pseudo-driver
30 30 *
31 31 * This is a lightweight driver which calls in to the Kernel Cryptographic
32 32 * Framework to do the real work. Kernel modules should NOT depend on this
33 33 * driver for /dev/random kernel API.
34 34 *
35 35 * Applications may ask for 2 types of random bits:
36 36 * . High quality random by reading from /dev/random. The output is extracted
37 37 * only when a minimum amount of entropy is available.
38 38 * . Pseudo-random, by reading from /dev/urandom, that can be generated any
39 39 * time.
40 40 */
41 41
42 42 #include <sys/types.h>
43 43 #include <sys/errno.h>
44 44 #include <sys/stat.h>
45 45
46 46 #include <sys/file.h>
47 47 #include <sys/open.h>
48 48 #include <sys/poll.h>
49 49 #include <sys/uio.h>
50 50 #include <sys/cred.h>
51 51 #include <sys/modctl.h>
52 52 #include <sys/conf.h>
53 53 #include <sys/ddi.h>
54 54 #include <sys/sunddi.h>
55 55 #include <sys/random.h>
56 56 #include <sys/crypto/impl.h>
57 57
58 58 #define DEVRANDOM 0
59 59 #define DEVURANDOM 1
60 60
61 61 #define HASHSIZE 20 /* Assuming a SHA1 hash algorithm */
62 62 #define WRITEBUFSIZE 512 /* Size of buffer for write request */
63 63 #define MAXRETBYTES 1040 /* Max bytes returned per read. */
64 64 /* Must be a multiple of HASHSIZE */
65 65 static dev_info_t *rnd_dip;
66 66
67 67 static int rnd_open(dev_t *, int, int, cred_t *);
68 68 static int rnd_close(dev_t, int, int, cred_t *);
69 69 static int rnd_read(dev_t, struct uio *, cred_t *);
70 70 static int rnd_write(dev_t, struct uio *, cred_t *);
71 71 static int rnd_chpoll(dev_t, short, int, short *, struct pollhead **);
72 72 static int rnd_attach(dev_info_t *, ddi_attach_cmd_t);
73 73 static int rnd_detach(dev_info_t *, ddi_detach_cmd_t);
74 74 static int rnd_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
75 75
76 76 /* DDI declarations */
77 77 static struct cb_ops rnd_cb_ops = {
78 78 rnd_open, /* open */
79 79 rnd_close, /* close */
80 80 nodev, /* strategy */
81 81 nodev, /* print */
82 82 nodev, /* dump */
83 83 rnd_read, /* read */
84 84 rnd_write, /* write */
85 85 nodev, /* ioctl */
86 86 nodev, /* devmap */
87 87 nodev, /* mmap */
88 88 nodev, /* segmap */
89 89 rnd_chpoll, /* chpoll */
90 90 ddi_prop_op, /* prop_op */
91 91 NULL, /* streamtab */
92 92 (D_NEW | D_MP), /* cb_flag */
93 93 CB_REV, /* cb_rev */
94 94 nodev, /* aread */
95 95 nodev /* awrite */
96 96 };
97 97
98 98 static struct dev_ops rnd_ops = {
99 99 DEVO_REV, /* devo_rev, */
100 100 0, /* refcnt */
101 101 rnd_getinfo, /* get_dev_info */
102 102 nulldev, /* identify */
103 103 nulldev, /* probe */
104 104 rnd_attach, /* attach */
105 105 rnd_detach, /* detach */
106 106 nodev, /* reset */
107 107 &rnd_cb_ops, /* driver operations */
108 108 NULL, /* bus operations */
109 109 NULL, /* power */
110 110 ddi_quiesce_not_needed, /* quiesce */
111 111 };
112 112
113 113 /* Modlinkage */
114 114 static struct modldrv modldrv = {
115 115 &mod_driverops,
116 116 "random number device",
117 117 &rnd_ops
118 118 };
119 119
120 120 static struct modlinkage modlinkage = { MODREV_1, { &modldrv, NULL } };
121 121
122 122
123 123 /* DDI glue */
124 124
125 125 int
126 126 _init(void)
127 127 {
128 128 return (mod_install(&modlinkage));
129 129 }
130 130
131 131 int
132 132 _fini(void)
133 133 {
134 134 return (mod_remove(&modlinkage));
135 135 }
136 136
137 137 int
138 138 _info(struct modinfo *modinfop)
139 139 {
140 140 return (mod_info(&modlinkage, modinfop));
141 141 }
142 142
143 143 static int
144 144 rnd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
145 145 {
146 146 if (cmd != DDI_ATTACH)
147 147 return (DDI_FAILURE);
148 148
149 149 if (ddi_create_minor_node(dip, "random", S_IFCHR, DEVRANDOM,
150 150 DDI_PSEUDO, 0) == DDI_FAILURE) {
151 151 ddi_remove_minor_node(dip, NULL);
152 152 return (DDI_FAILURE);
153 153 }
154 154 if (ddi_create_minor_node(dip, "urandom", S_IFCHR, DEVURANDOM,
155 155 DDI_PSEUDO, 0) == DDI_FAILURE) {
156 156 ddi_remove_minor_node(dip, NULL);
157 157 return (DDI_FAILURE);
158 158 }
159 159
160 160 rnd_dip = dip;
161 161
162 162 return (DDI_SUCCESS);
163 163 }
164 164
165 165 static int
166 166 rnd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
167 167 {
168 168 if (cmd != DDI_DETACH)
169 169 return (DDI_FAILURE);
170 170
171 171 rnd_dip = NULL;
172 172 ddi_remove_minor_node(dip, NULL);
173 173
174 174 return (DDI_SUCCESS);
175 175 }
176 176
177 177 /*ARGSUSED*/
178 178 static int
179 179 rnd_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
180 180 {
181 181 int error;
182 182
183 183 switch (infocmd) {
184 184 case DDI_INFO_DEVT2DEVINFO:
185 185 *result = rnd_dip;
186 186 error = DDI_SUCCESS;
187 187 break;
188 188 case DDI_INFO_DEVT2INSTANCE:
189 189 *result = (void *)0;
190 190 error = DDI_SUCCESS;
191 191 break;
192 192 default:
193 193 error = DDI_FAILURE;
194 194 }
195 195 return (error);
196 196 }
197 197
198 198 /*ARGSUSED3*/
199 199 static int
200 200 rnd_open(dev_t *devp, int flag, int otyp, cred_t *credp)
201 201 {
202 202 switch (getminor(*devp)) {
203 203 case DEVRANDOM:
204 204 if (!kcf_rngprov_check())
205 205 return (ENXIO);
206 206 break;
207 207 case DEVURANDOM:
208 208 break;
209 209 default:
210 210 return (ENXIO);
211 211 }
212 212 if (otyp != OTYP_CHR)
213 213 return (EINVAL);
214 214
215 215 if (flag & FEXCL)
216 216 return (EINVAL);
217 217 return (0);
218 218 }
219 219
220 220 /*ARGSUSED*/
221 221 static int
222 222 rnd_close(dev_t dev, int flag, int otyp, cred_t *credp)
223 223 {
224 224 return (0);
225 225 }
226 226
227 227 /*ARGSUSED2*/
228 228 static int
229 229 rnd_read(dev_t dev, struct uio *uiop, cred_t *credp)
230 230 {
231 231 size_t len;
232 232 minor_t devno;
233 233 int error = 0;
234 234 int nbytes = 0;
235 235 uint8_t random_bytes[2 * HASHSIZE];
236 236
237 237 devno = getminor(dev);
238 238
239 239 while (error == 0 && uiop->uio_resid > 0) {
240 240 len = min(sizeof (random_bytes), uiop->uio_resid);
241 241 switch (devno) {
242 242 case DEVRANDOM:
243 243 error = kcf_rnd_get_bytes(random_bytes, len,
244 244 uiop->uio_fmode & (FNDELAY|FNONBLOCK));
245 245 break;
246 246 case DEVURANDOM:
247 247 error = kcf_rnd_get_pseudo_bytes(random_bytes, len);
248 248 break;
249 249 default:
250 250 return (ENXIO);
251 251 }
252 252
253 253 if (error == 0) {
254 254 /*
255 255 * /dev/[u]random is not a seekable device. To prevent
256 256 * uio offset from growing and eventually exceeding
257 257 * the maximum, reset the offset here for every call.
258 258 */
259 259 uiop->uio_loffset = 0;
260 260 error = uiomove(random_bytes, len, UIO_READ, uiop);
261 261
262 262 nbytes += len;
263 263
264 264 if (devno == DEVRANDOM && nbytes >= MAXRETBYTES)
265 265 break;
266 266
267 267 } else if ((error == EAGAIN) && (nbytes > 0)) {
268 268 error = 0;
269 269 break;
270 270 }
271 271 }
272 272 return (error);
273 273 }
274 274
275 275 /*ARGSUSED*/
276 276 static int
277 277 rnd_write(dev_t dev, struct uio *uiop, cred_t *credp)
278 278 {
279 279 int error;
280 280 uint8_t buf[WRITEBUFSIZE];
281 281 size_t bytes;
282 282 minor_t devno;
283 283
284 284 devno = getminor(dev);
285 285
286 286 while (uiop->uio_resid > 0) {
287 287 bytes = min(sizeof (buf), uiop->uio_resid);
288 288
289 289 /* See comments in rnd_read() */
290 290 uiop->uio_loffset = 0;
291 291 if ((error = uiomove(buf, bytes, UIO_WRITE, uiop)) != 0)
292 292 return (error);
293 293
294 294 if (crgetzone(credp) != global_zone)
295 295 continue;
296 296
297 297 switch (devno) {
298 298 case DEVRANDOM:
299 299 if ((error = random_add_entropy(buf, bytes, 0)) != 0)
300 300 return (error);
301 301 break;
302 302 case DEVURANDOM:
303 303 if ((error = random_add_pseudo_entropy(buf, bytes,
304 304 0)) != 0)
305 305 return (error);
306 306 break;
307 307 default:
308 308 return (ENXIO);
309 309 }
310 310 }
311 311
312 312 return (0);
313 313 }
314 314
315 315 static struct pollhead urnd_pollhd;
316 316
317 317 /*
318 318 * poll(2) is supported as follows:
319 319 * . Only POLLIN, POLLOUT, and POLLRDNORM events are supported.
320 320 * . POLLOUT always succeeds.
321 321 * . POLLIN and POLLRDNORM from /dev/urandom always succeeds.
322 322 * . POLLIN and POLLRDNORM from /dev/random will block until a
323 323 * minimum amount of entropy is available.
324 324 */
325 325 static int
326 326 rnd_chpoll(dev_t dev, short events, int anyyet, short *reventsp,
327 327 struct pollhead **phpp)
328 328 {
329 329 switch (getminor(dev)) {
330 330 case DEVURANDOM:
331 331 *reventsp = events & (POLLOUT | POLLIN | POLLRDNORM);
332 332
333 333 /*
334 334 * A non NULL pollhead pointer should be returned in case
335 335 * user polls for 0 events.
336 336 */
337 337 if (*reventsp == 0 && !anyyet)
338 338 *phpp = &urnd_pollhd;
339 339
340 340 break;
341 341 case DEVRANDOM:
342 342 kcf_rnd_chpoll(events, anyyet, reventsp, phpp);
343 343 break;
344 344 default:
345 345 return (ENXIO);
346 346 }
347 347
348 348 return (0);
349 349 }
|
↓ open down ↓ |
349 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX