xref: /xnu-11215/bsd/dev/random/randomdev.c (revision e7776783)
18149afccSApple OSS Distributions /*
23ca3bd55SApple OSS Distributions  * Copyright (c) 1999-2009 Apple, Inc. All rights reserved.
38149afccSApple OSS Distributions  *
4e13b1fa5SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
58149afccSApple OSS Distributions  *
6e13b1fa5SApple OSS Distributions  * This file contains Original Code and/or Modifications of Original Code
7e13b1fa5SApple OSS Distributions  * as defined in and that are subject to the Apple Public Source License
8e13b1fa5SApple OSS Distributions  * Version 2.0 (the 'License'). You may not use this file except in
9e13b1fa5SApple OSS Distributions  * compliance with the License. The rights granted to you under the License
10e13b1fa5SApple OSS Distributions  * may not be used to create, or enable the creation or redistribution of,
11e13b1fa5SApple OSS Distributions  * unlawful or unlicensed copies of an Apple operating system, or to
12e13b1fa5SApple OSS Distributions  * circumvent, violate, or enable the circumvention or violation of, any
13e13b1fa5SApple OSS Distributions  * terms of an Apple operating system software license agreement.
148149afccSApple OSS Distributions  *
15e13b1fa5SApple OSS Distributions  * Please obtain a copy of the License at
16e13b1fa5SApple OSS Distributions  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17e13b1fa5SApple OSS Distributions  *
18e13b1fa5SApple OSS Distributions  * The Original Code and all software distributed under the License are
19e13b1fa5SApple OSS Distributions  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
208149afccSApple OSS Distributions  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
218149afccSApple OSS Distributions  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22e13b1fa5SApple OSS Distributions  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23e13b1fa5SApple OSS Distributions  * Please see the License for the specific language governing rights and
24e13b1fa5SApple OSS Distributions  * limitations under the License.
258149afccSApple OSS Distributions  *
26e13b1fa5SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
278149afccSApple OSS Distributions  */
288149afccSApple OSS Distributions 
293ca3bd55SApple OSS Distributions 
308149afccSApple OSS Distributions #include <sys/param.h>
318149afccSApple OSS Distributions #include <sys/systm.h>
328149afccSApple OSS Distributions #include <sys/proc.h>
338149afccSApple OSS Distributions #include <sys/errno.h>
348149afccSApple OSS Distributions #include <sys/ioctl.h>
358149afccSApple OSS Distributions #include <sys/conf.h>
368149afccSApple OSS Distributions #include <sys/fcntl.h>
37e13b1fa5SApple OSS Distributions #include <string.h>
388149afccSApple OSS Distributions #include <miscfs/devfs/devfs.h>
39a3bb9fccSApple OSS Distributions #include <kern/locks.h>
40e13b1fa5SApple OSS Distributions #include <kern/clock.h>
418149afccSApple OSS Distributions #include <sys/time.h>
428149afccSApple OSS Distributions #include <sys/malloc.h>
4388cc0b97SApple OSS Distributions #include <sys/sysproto.h>
4414e3d835SApple OSS Distributions #include <sys/uio_internal.h>
458149afccSApple OSS Distributions 
468149afccSApple OSS Distributions #include <dev/random/randomdev.h>
473ca3bd55SApple OSS Distributions 
483ca3bd55SApple OSS Distributions #include <libkern/OSByteOrder.h>
49186b8fceSApple OSS Distributions #include <libkern/OSAtomic.h>
50e13b1fa5SApple OSS Distributions 
51e13b1fa5SApple OSS Distributions #include <mach/mach_time.h>
523ca3bd55SApple OSS Distributions 
538149afccSApple OSS Distributions #define RANDOM_MAJOR  -1 /* let the kernel pick the device number */
54a3bb9fccSApple OSS Distributions #define RANDOM_MINOR   0
55a3bb9fccSApple OSS Distributions #define URANDOM_MINOR  1
568149afccSApple OSS Distributions 
57368ad365SApple OSS Distributions d_ioctl_t       random_ioctl;
58368ad365SApple OSS Distributions 
59*e7776783SApple OSS Distributions static int
random_stop(__unused struct tty * tp,__unused int rw)60*e7776783SApple OSS Distributions random_stop(__unused struct tty *tp, __unused int rw)
61*e7776783SApple OSS Distributions {
62*e7776783SApple OSS Distributions 	return 0;
63*e7776783SApple OSS Distributions }
64*e7776783SApple OSS Distributions 
65*e7776783SApple OSS Distributions static int
random_reset(__unused int uban)66*e7776783SApple OSS Distributions random_reset(__unused int uban)
67*e7776783SApple OSS Distributions {
68*e7776783SApple OSS Distributions 	return 0;
69*e7776783SApple OSS Distributions }
70*e7776783SApple OSS Distributions 
71*e7776783SApple OSS Distributions static int
random_select(__unused dev_t dev,__unused int which,__unused void * wql,__unused struct proc * p)72*e7776783SApple OSS Distributions random_select(__unused dev_t dev, __unused int which, __unused void *wql,
73*e7776783SApple OSS Distributions     __unused struct proc *p)
74*e7776783SApple OSS Distributions {
75*e7776783SApple OSS Distributions 	return ENODEV;
76*e7776783SApple OSS Distributions }
77*e7776783SApple OSS Distributions 
78bb611c8fSApple OSS Distributions static const struct cdevsw random_cdevsw =
798149afccSApple OSS Distributions {
80bb611c8fSApple OSS Distributions 	.d_open = random_open,
81bb611c8fSApple OSS Distributions 	.d_close = random_close,
82bb611c8fSApple OSS Distributions 	.d_read = random_read,
83bb611c8fSApple OSS Distributions 	.d_write = random_write,
84bb611c8fSApple OSS Distributions 	.d_ioctl = random_ioctl,
85*e7776783SApple OSS Distributions 	.d_stop = random_stop,
86*e7776783SApple OSS Distributions 	.d_reset = random_reset,
87*e7776783SApple OSS Distributions 	.d_select = random_select,
88bb611c8fSApple OSS Distributions 	.d_mmap = eno_mmap,
89bb611c8fSApple OSS Distributions 	.d_strategy = eno_strat,
90bb611c8fSApple OSS Distributions 	.d_reserved_1 = eno_getc,
91bb611c8fSApple OSS Distributions 	.d_reserved_2 = eno_putc,
928149afccSApple OSS Distributions };
938149afccSApple OSS Distributions 
94855239e5SApple OSS Distributions 
95855239e5SApple OSS Distributions /*
968149afccSApple OSS Distributions  * Called to initialize our device,
978149afccSApple OSS Distributions  * and to register ourselves with devfs
988149afccSApple OSS Distributions  */
998149afccSApple OSS Distributions void
random_init(void)10014e3d835SApple OSS Distributions random_init(void)
1018149afccSApple OSS Distributions {
1028149afccSApple OSS Distributions 	int ret;
1038149afccSApple OSS Distributions 
1048149afccSApple OSS Distributions 	ret = cdevsw_add(RANDOM_MAJOR, &random_cdevsw);
1058149afccSApple OSS Distributions 	if (ret < 0) {
106a3bb9fccSApple OSS Distributions 		panic("random_init: failed to allocate a major number!");
1078149afccSApple OSS Distributions 	}
1088149afccSApple OSS Distributions 
109a3bb9fccSApple OSS Distributions 	devfs_make_node(makedev(ret, RANDOM_MINOR), DEVFS_CHAR,
110*e7776783SApple OSS Distributions 	    UID_ROOT, GID_WHEEL, 0666, "random");
1118149afccSApple OSS Distributions 
1128149afccSApple OSS Distributions 	/*
1138149afccSApple OSS Distributions 	 * also make urandom
1148149afccSApple OSS Distributions 	 * (which is exactly the same thing in our context)
1158149afccSApple OSS Distributions 	 */
116a3bb9fccSApple OSS Distributions 	devfs_make_node(makedev(ret, URANDOM_MINOR), DEVFS_CHAR,
117*e7776783SApple OSS Distributions 	    UID_ROOT, GID_WHEEL, 0666, "urandom");
118368ad365SApple OSS Distributions }
119368ad365SApple OSS Distributions 
120368ad365SApple OSS Distributions int
random_ioctl(__unused dev_t dev,u_long cmd,__unused caddr_t data,__unused int flag,__unused struct proc * p)12114e3d835SApple OSS Distributions random_ioctl(   __unused dev_t dev, u_long cmd, __unused caddr_t data,
12214e3d835SApple OSS Distributions     __unused int flag, __unused struct proc *p  )
123368ad365SApple OSS Distributions {
124368ad365SApple OSS Distributions 	switch (cmd) {
125368ad365SApple OSS Distributions 	case FIONBIO:
126368ad365SApple OSS Distributions 	case FIOASYNC:
127368ad365SApple OSS Distributions 		break;
128368ad365SApple OSS Distributions 	default:
129368ad365SApple OSS Distributions 		return ENODEV;
130368ad365SApple OSS Distributions 	}
131368ad365SApple OSS Distributions 
132a5e72196SApple OSS Distributions 	return 0;
1338149afccSApple OSS Distributions }
1348149afccSApple OSS Distributions 
1358149afccSApple OSS Distributions /*
1368149afccSApple OSS Distributions  * Open the device.  Make sure init happened, and make sure the caller is
1378149afccSApple OSS Distributions  * authorized.
1388149afccSApple OSS Distributions  */
1398149afccSApple OSS Distributions 
1408149afccSApple OSS Distributions int
random_open(__unused dev_t dev,int flags,__unused int devtype,__unused struct proc * p)14114e3d835SApple OSS Distributions random_open(__unused dev_t dev, int flags, __unused int devtype, __unused struct proc *p)
1428149afccSApple OSS Distributions {
1438149afccSApple OSS Distributions 	/*
1448149afccSApple OSS Distributions 	 * if we are being opened for write,
1458149afccSApple OSS Distributions 	 * make sure that we have privledges do so
1468149afccSApple OSS Distributions 	 */
1478149afccSApple OSS Distributions 	if (flags & FWRITE) {
148a5e72196SApple OSS Distributions 		if (securelevel >= 2) {
149a5e72196SApple OSS Distributions 			return EPERM;
150a5e72196SApple OSS Distributions 		}
151368ad365SApple OSS Distributions #ifndef __APPLE__
152a5e72196SApple OSS Distributions 		if ((securelevel >= 1) && proc_suser(p)) {
153a5e72196SApple OSS Distributions 			return EPERM;
154a5e72196SApple OSS Distributions 		}
155368ad365SApple OSS Distributions #endif  /* !__APPLE__ */
1568149afccSApple OSS Distributions 	}
1578149afccSApple OSS Distributions 
158a5e72196SApple OSS Distributions 	return 0;
1598149afccSApple OSS Distributions }
1608149afccSApple OSS Distributions 
1618149afccSApple OSS Distributions 
1628149afccSApple OSS Distributions /*
1638149afccSApple OSS Distributions  * close the device.
1648149afccSApple OSS Distributions  */
1658149afccSApple OSS Distributions 
1668149afccSApple OSS Distributions int
random_close(__unused dev_t dev,__unused int flags,__unused int mode,__unused struct proc * p)16714e3d835SApple OSS Distributions random_close(__unused dev_t dev, __unused int flags, __unused int mode, __unused struct proc *p)
1688149afccSApple OSS Distributions {
169a5e72196SApple OSS Distributions 	return 0;
1708149afccSApple OSS Distributions }
1718149afccSApple OSS Distributions 
1728149afccSApple OSS Distributions 
1738149afccSApple OSS Distributions /*
1748149afccSApple OSS Distributions  * Get entropic data from the Security Server, and use it to reseed the
1758149afccSApple OSS Distributions  * prng.
1768149afccSApple OSS Distributions  */
1778149afccSApple OSS Distributions int
random_write(dev_t dev,struct uio * uio,__unused int ioflag)178a3bb9fccSApple OSS Distributions random_write(dev_t dev, struct uio *uio, __unused int ioflag)
1798149afccSApple OSS Distributions {
1808149afccSApple OSS Distributions 	int retCode = 0;
1818149afccSApple OSS Distributions 	char rdBuffer[256];
1828149afccSApple OSS Distributions 
183a5e72196SApple OSS Distributions 	if (minor(dev) != RANDOM_MINOR) {
184a3bb9fccSApple OSS Distributions 		return EPERM;
185a5e72196SApple OSS Distributions 	}
1868149afccSApple OSS Distributions 
1878149afccSApple OSS Distributions 	/* Security server is sending us entropy */
1888149afccSApple OSS Distributions 
189bb611c8fSApple OSS Distributions 	while ((size_t)uio_resid(uio) > 0 && retCode == 0) {
1908149afccSApple OSS Distributions 		/* get the user's data */
191bb611c8fSApple OSS Distributions 		size_t bytesToInput = MIN((size_t)uio_resid(uio), sizeof(rdBuffer));
192bb611c8fSApple OSS Distributions 		retCode = uiomove(rdBuffer, (int)bytesToInput, uio);
193a5e72196SApple OSS Distributions 		if (retCode != 0) {
194a3bb9fccSApple OSS Distributions 			break;
195a5e72196SApple OSS Distributions 		}
196bb611c8fSApple OSS Distributions 		retCode = write_random(rdBuffer, (u_int)bytesToInput);
197a5e72196SApple OSS Distributions 		if (retCode != 0) {
198a3bb9fccSApple OSS Distributions 			break;
1998149afccSApple OSS Distributions 		}
200a5e72196SApple OSS Distributions 	}
2018149afccSApple OSS Distributions 
202a3bb9fccSApple OSS Distributions 	return retCode;
2038149afccSApple OSS Distributions }
2048149afccSApple OSS Distributions 
2058149afccSApple OSS Distributions /*
206186b8fceSApple OSS Distributions  * return data to the caller.  Results unpredictable.
207186b8fceSApple OSS Distributions  */
208186b8fceSApple OSS Distributions int
random_read(__unused dev_t dev,struct uio * uio,__unused int ioflag)209186b8fceSApple OSS Distributions random_read(__unused dev_t dev, struct uio *uio, __unused int ioflag)
210186b8fceSApple OSS Distributions {
211186b8fceSApple OSS Distributions 	int retCode = 0;
212a3bb9fccSApple OSS Distributions 	char buffer[512];
213186b8fceSApple OSS Distributions 
214bb611c8fSApple OSS Distributions 	size_t bytes_remaining = (size_t)uio_resid(uio);
215186b8fceSApple OSS Distributions 	while (bytes_remaining > 0 && retCode == 0) {
216bb611c8fSApple OSS Distributions 		size_t bytesToRead = MIN(bytes_remaining, sizeof(buffer));
217bb611c8fSApple OSS Distributions 		read_random(buffer, (u_int)bytesToRead);
218186b8fceSApple OSS Distributions 
219bb611c8fSApple OSS Distributions 		retCode = uiomove(buffer, (int)bytesToRead, uio);
220a5e72196SApple OSS Distributions 		if (retCode != 0) {
221a3bb9fccSApple OSS Distributions 			break;
222a5e72196SApple OSS Distributions 		}
223186b8fceSApple OSS Distributions 
224bb611c8fSApple OSS Distributions 		bytes_remaining = (size_t)uio_resid(uio);
225186b8fceSApple OSS Distributions 	}
226186b8fceSApple OSS Distributions 
227186b8fceSApple OSS Distributions 	return retCode;
228186b8fceSApple OSS Distributions }
229a3bb9fccSApple OSS Distributions 
230186b8fceSApple OSS Distributions /*
2313ca3bd55SApple OSS Distributions  * Return an u_int32_t pseudo-random number.
2328149afccSApple OSS Distributions  */
2333ca3bd55SApple OSS Distributions u_int32_t
RandomULong(void)23414e3d835SApple OSS Distributions RandomULong(void)
2358149afccSApple OSS Distributions {
2363ca3bd55SApple OSS Distributions 	u_int32_t buf;
2378149afccSApple OSS Distributions 	read_random(&buf, sizeof(buf));
238a5e72196SApple OSS Distributions 	return buf;
2398149afccSApple OSS Distributions }
240855239e5SApple OSS Distributions 
24188cc0b97SApple OSS Distributions 
24288cc0b97SApple OSS Distributions int
getentropy(__unused struct proc * p,struct getentropy_args * gap,__unused int * ret)243a5e72196SApple OSS Distributions getentropy(__unused struct proc * p, struct getentropy_args *gap, __unused int * ret)
244a5e72196SApple OSS Distributions {
24588cc0b97SApple OSS Distributions 	user_addr_t user_addr;
246bb611c8fSApple OSS Distributions 	user_size_t user_size;
24788cc0b97SApple OSS Distributions 	char buffer[256];
24888cc0b97SApple OSS Distributions 
249bb611c8fSApple OSS Distributions 	user_addr = (user_addr_t)gap->buffer;
25088cc0b97SApple OSS Distributions 	user_size = gap->size;
25188cc0b97SApple OSS Distributions 	/* Can't request more than 256 random bytes
25288cc0b97SApple OSS Distributions 	 * at once. Complying with openbsd getentropy()
25388cc0b97SApple OSS Distributions 	 */
25488cc0b97SApple OSS Distributions 	if (user_size > sizeof(buffer)) {
25588cc0b97SApple OSS Distributions 		return EINVAL;
25688cc0b97SApple OSS Distributions 	}
257bb611c8fSApple OSS Distributions 	read_random(buffer, (u_int)user_size);
25888cc0b97SApple OSS Distributions 	return copyout(buffer, user_addr, user_size);
25988cc0b97SApple OSS Distributions }
260