xref: /freebsd/sys/dev/random/randomdev.c (revision a6278a2a42fc77094f356a290336a0fc395feb05)
14db9ae91SMark Murray /*-
2c9ec235cSMark Murray  * Copyright (c) 2000 Mark R V Murray
34db9ae91SMark Murray  * All rights reserved.
44db9ae91SMark Murray  *
54db9ae91SMark Murray  * Redistribution and use in source and binary forms, with or without
64db9ae91SMark Murray  * modification, are permitted provided that the following conditions
74db9ae91SMark Murray  * are met:
84db9ae91SMark Murray  * 1. Redistributions of source code must retain the above copyright
94db9ae91SMark Murray  *    notice, this list of conditions and the following disclaimer
104db9ae91SMark Murray  *    in this position and unchanged.
114db9ae91SMark Murray  * 2. Redistributions in binary form must reproduce the above copyright
124db9ae91SMark Murray  *    notice, this list of conditions and the following disclaimer in the
134db9ae91SMark Murray  *    documentation and/or other materials provided with the distribution.
144db9ae91SMark Murray  *
154db9ae91SMark Murray  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
164db9ae91SMark Murray  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
174db9ae91SMark Murray  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
184db9ae91SMark Murray  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
194db9ae91SMark Murray  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
204db9ae91SMark Murray  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
214db9ae91SMark Murray  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
224db9ae91SMark Murray  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
234db9ae91SMark Murray  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
244db9ae91SMark Murray  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
254db9ae91SMark Murray  *
264db9ae91SMark Murray  * $FreeBSD$
274db9ae91SMark Murray  */
284db9ae91SMark Murray 
294db9ae91SMark Murray #include <sys/param.h>
30c9ec235cSMark Murray #include <sys/queue.h>
314db9ae91SMark Murray #include <sys/systm.h>
324db9ae91SMark Murray #include <sys/conf.h>
334db9ae91SMark Murray #include <sys/fcntl.h>
344db9ae91SMark Murray #include <sys/uio.h>
354db9ae91SMark Murray #include <sys/kernel.h>
364db9ae91SMark Murray #include <sys/malloc.h>
374db9ae91SMark Murray #include <sys/module.h>
384db9ae91SMark Murray #include <sys/bus.h>
39a6278a2aSMark Murray #include <sys/poll.h>
40c4ff4a84SRobert Watson #include <sys/proc.h>
41a6278a2aSMark Murray #include <sys/select.h>
424db9ae91SMark Murray #include <sys/random.h>
43a6278a2aSMark Murray #include <sys/vnode.h>
444db9ae91SMark Murray #include <machine/bus.h>
454db9ae91SMark Murray #include <machine/resource.h>
464db9ae91SMark Murray #include <sys/sysctl.h>
474db9ae91SMark Murray #include <crypto/blowfish/blowfish.h>
484db9ae91SMark Murray 
49a6278a2aSMark Murray #include <dev/random/hash.h>
50a6278a2aSMark Murray #include <dev/random/yarrow.h>
514db9ae91SMark Murray 
527aa4389aSMark Murray static d_open_t random_open;
53c9ec235cSMark Murray static d_read_t random_read;
54c9ec235cSMark Murray static d_write_t random_write;
554d87a031SMark Murray static d_ioctl_t random_ioctl;
56a6278a2aSMark Murray static d_poll_t random_poll;
574db9ae91SMark Murray 
584db9ae91SMark Murray #define CDEV_MAJOR	2
594db9ae91SMark Murray #define RANDOM_MINOR	3
601f67cd87SMark Murray #define URANDOM_MINOR	4
614db9ae91SMark Murray 
624db9ae91SMark Murray static struct cdevsw random_cdevsw = {
637aa4389aSMark Murray 	/* open */	random_open,
644db9ae91SMark Murray 	/* close */	(d_close_t *)nullop,
65c9ec235cSMark Murray 	/* read */	random_read,
66c9ec235cSMark Murray 	/* write */	random_write,
674d87a031SMark Murray 	/* ioctl */	random_ioctl,
68a6278a2aSMark Murray 	/* poll */	random_poll,
694db9ae91SMark Murray 	/* mmap */	nommap,
704db9ae91SMark Murray 	/* strategy */	nostrategy,
714db9ae91SMark Murray 	/* name */	"random",
724db9ae91SMark Murray 	/* maj */	CDEV_MAJOR,
734db9ae91SMark Murray 	/* dump */	nodump,
744db9ae91SMark Murray 	/* psize */	nopsize,
754db9ae91SMark Murray 	/* flags */	0,
764db9ae91SMark Murray 	/* bmaj */	-1
774db9ae91SMark Murray };
784db9ae91SMark Murray 
794db9ae91SMark Murray /* For use with make_dev(9)/destroy_dev(9). */
80c9ec235cSMark Murray static dev_t random_dev;
814d87a031SMark Murray static dev_t urandom_dev; /* XXX Temporary */
824db9ae91SMark Murray 
834db9ae91SMark Murray SYSCTL_NODE(_kern, OID_AUTO, random, CTLFLAG_RW, 0, "Random Number Generator");
844db9ae91SMark Murray SYSCTL_NODE(_kern_random, OID_AUTO, yarrow, CTLFLAG_RW, 0, "Yarrow Parameters");
85769afb04SMark Murray SYSCTL_INT(_kern_random_yarrow, OID_AUTO, gengateinterval, CTLFLAG_RW,
86769afb04SMark Murray 	&random_state.gengateinterval, 10, "Generator Gate Interval");
87769afb04SMark Murray SYSCTL_INT(_kern_random_yarrow, OID_AUTO, bins, CTLFLAG_RW,
88769afb04SMark Murray 	&random_state.bins, 10, "Execution time tuner");
89769afb04SMark Murray SYSCTL_INT(_kern_random_yarrow, OID_AUTO, fastthresh, CTLFLAG_RW,
90769afb04SMark Murray 	&random_state.pool[0].thresh, 100, "Fast pool reseed threshhold");
91769afb04SMark Murray SYSCTL_INT(_kern_random_yarrow, OID_AUTO, slowthresh, CTLFLAG_RW,
927aa4389aSMark Murray 	&random_state.pool[1].thresh, 160, "Slow pool reseed threshhold");
93769afb04SMark Murray SYSCTL_INT(_kern_random_yarrow, OID_AUTO, slowoverthresh, CTLFLAG_RW,
94769afb04SMark Murray 	&random_state.slowoverthresh, 2, "Slow pool over-threshhold reseed");
954db9ae91SMark Murray 
964db9ae91SMark Murray static int
977aa4389aSMark Murray random_open(dev_t dev, int flags, int fmt, struct proc *p)
987aa4389aSMark Murray {
997aa4389aSMark Murray 	if ((flags & FWRITE) && (securelevel > 0 || suser(p)))
1007aa4389aSMark Murray 		return EPERM;
1017aa4389aSMark Murray 	else
1027aa4389aSMark Murray 		return 0;
1037aa4389aSMark Murray }
1047aa4389aSMark Murray 
1057aa4389aSMark Murray static int
106c9ec235cSMark Murray random_read(dev_t dev, struct uio *uio, int flag)
1074db9ae91SMark Murray {
1084db9ae91SMark Murray 	u_int c, ret;
1094db9ae91SMark Murray 	int error = 0;
110769afb04SMark Murray 	void *random_buf;
1114db9ae91SMark Murray 
112a6278a2aSMark Murray 	if (flag & IO_NDELAY && !random_state.seeded) {
113a6278a2aSMark Murray 		error =  EWOULDBLOCK;
114a6278a2aSMark Murray 	}
115a6278a2aSMark Murray 	else {
116a6278a2aSMark Murray 		if (random_state.seeded) {
1174db9ae91SMark Murray 			c = min(uio->uio_resid, PAGE_SIZE);
118c9ec235cSMark Murray 			random_buf = (void *)malloc(c, M_TEMP, M_WAITOK);
1194db9ae91SMark Murray 			while (uio->uio_resid > 0 && error == 0) {
120a6278a2aSMark Murray 				ret = read_random_real(random_buf, c);
121c9ec235cSMark Murray 				error = uiomove(random_buf, ret, uio);
1224db9ae91SMark Murray 			}
123c9ec235cSMark Murray 			free(random_buf, M_TEMP);
124a6278a2aSMark Murray 		}
125a6278a2aSMark Murray 		else
126a6278a2aSMark Murray 			error = tsleep(&random_state, 0, "rndblk", 0);
127a6278a2aSMark Murray 	}
1284db9ae91SMark Murray 	return error;
1294db9ae91SMark Murray }
1304db9ae91SMark Murray 
1314db9ae91SMark Murray static int
132c9ec235cSMark Murray random_write(dev_t dev, struct uio *uio, int flag)
1334db9ae91SMark Murray {
1344db9ae91SMark Murray 	u_int c;
1354db9ae91SMark Murray 	int error = 0;
136769afb04SMark Murray 	void *random_buf;
1374db9ae91SMark Murray 
138c9ec235cSMark Murray 	random_buf = (void *)malloc(PAGE_SIZE, M_TEMP, M_WAITOK);
1394db9ae91SMark Murray 	while (uio->uio_resid > 0) {
1404db9ae91SMark Murray 		c = min(uio->uio_resid, PAGE_SIZE);
141c9ec235cSMark Murray 		error = uiomove(random_buf, c, uio);
1424db9ae91SMark Murray 		if (error)
1434db9ae91SMark Murray 			break;
144720a3741SMark Murray 		write_random(random_buf, c);
1454db9ae91SMark Murray 	}
146c9ec235cSMark Murray 	free(random_buf, M_TEMP);
1474db9ae91SMark Murray 	return error;
1484db9ae91SMark Murray }
1494db9ae91SMark Murray 
1504db9ae91SMark Murray static int
1514d87a031SMark Murray random_ioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
1524d87a031SMark Murray {
1534d87a031SMark Murray 	return ENOTTY;
1544d87a031SMark Murray }
1554d87a031SMark Murray 
1564d87a031SMark Murray static int
157a6278a2aSMark Murray random_poll(dev_t dev, int events, struct proc *p)
158a6278a2aSMark Murray {
159a6278a2aSMark Murray 	int revents;
160a6278a2aSMark Murray 
161a6278a2aSMark Murray 	revents = 0;
162a6278a2aSMark Murray 	if (events & (POLLIN | POLLRDNORM)) {
163a6278a2aSMark Murray 		if (random_state.seeded)
164a6278a2aSMark Murray 			revents = events & (POLLIN | POLLRDNORM);
165a6278a2aSMark Murray 		else
166a6278a2aSMark Murray 			selrecord(p, &random_state.rsel);
167a6278a2aSMark Murray 	}
168a6278a2aSMark Murray 	return revents;
169a6278a2aSMark Murray }
170a6278a2aSMark Murray 
171a6278a2aSMark Murray static int
1724db9ae91SMark Murray random_modevent(module_t mod, int type, void *data)
1734db9ae91SMark Murray {
1744d87a031SMark Murray 	int error;
1754d87a031SMark Murray 
1764db9ae91SMark Murray 	switch(type) {
1774db9ae91SMark Murray 	case MOD_LOAD:
1784d87a031SMark Murray 		error = random_init();
1794d87a031SMark Murray 		if (error != 0)
1804d87a031SMark Murray 			return error;
1814db9ae91SMark Murray 		if (bootverbose)
1824db9ae91SMark Murray 			printf("random: <entropy source>\n");
183c9ec235cSMark Murray 		random_dev = make_dev(&random_cdevsw, RANDOM_MINOR, UID_ROOT,
1841f67cd87SMark Murray 			GID_WHEEL, 0666, "random");
185c9ec235cSMark Murray 		urandom_dev = make_dev(&random_cdevsw, URANDOM_MINOR, UID_ROOT,
1864d87a031SMark Murray 			GID_WHEEL, 0666, "urandom"); /* XXX Temporary */
1874db9ae91SMark Murray 		return 0;
1884db9ae91SMark Murray 
1894db9ae91SMark Murray 	case MOD_UNLOAD:
190c9ec235cSMark Murray 		random_deinit();
191c9ec235cSMark Murray 		destroy_dev(random_dev);
1924d87a031SMark Murray 		destroy_dev(urandom_dev); /* XXX Temporary */
1934db9ae91SMark Murray 		return 0;
1944db9ae91SMark Murray 
1954db9ae91SMark Murray 	case MOD_SHUTDOWN:
1964db9ae91SMark Murray 		return 0;
1974db9ae91SMark Murray 
1984db9ae91SMark Murray 	default:
1994db9ae91SMark Murray 		return EOPNOTSUPP;
2004db9ae91SMark Murray 	}
2014db9ae91SMark Murray }
2024db9ae91SMark Murray 
2034db9ae91SMark Murray DEV_MODULE(random, random_modevent, NULL);
204