xref: /freebsd/sys/dev/random/randomdev.c (revision 095ed2c9f3c7ccbed16363d600ec6ad1c25a8804)
14db9ae91SMark Murray /*-
2f02e47dcSMark Murray  * Copyright (c) 2000-2013 Mark R V Murray
35711939bSDavid E. O'Brien  * Copyright (c) 2013 Arthur Mesh <arthurmesh@gmail.com>
44db9ae91SMark Murray  * All rights reserved.
54db9ae91SMark Murray  *
64db9ae91SMark Murray  * Redistribution and use in source and binary forms, with or without
74db9ae91SMark Murray  * modification, are permitted provided that the following conditions
84db9ae91SMark Murray  * are met:
94db9ae91SMark Murray  * 1. Redistributions of source code must retain the above copyright
104db9ae91SMark Murray  *    notice, this list of conditions and the following disclaimer
114db9ae91SMark Murray  *    in this position and unchanged.
124db9ae91SMark Murray  * 2. Redistributions in binary form must reproduce the above copyright
134db9ae91SMark Murray  *    notice, this list of conditions and the following disclaimer in the
144db9ae91SMark Murray  *    documentation and/or other materials provided with the distribution.
154db9ae91SMark Murray  *
164db9ae91SMark Murray  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
174db9ae91SMark Murray  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
184db9ae91SMark Murray  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
194db9ae91SMark Murray  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
204db9ae91SMark Murray  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
214db9ae91SMark Murray  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
224db9ae91SMark Murray  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
234db9ae91SMark Murray  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
244db9ae91SMark Murray  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
254db9ae91SMark Murray  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
264db9ae91SMark Murray  *
274db9ae91SMark Murray  */
284db9ae91SMark Murray 
29aad970f1SDavid E. O'Brien #include <sys/cdefs.h>
30aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$");
31aad970f1SDavid E. O'Brien 
324db9ae91SMark Murray #include <sys/param.h>
334db9ae91SMark Murray #include <sys/systm.h>
34fb919e4dSMark Murray #include <sys/bus.h>
354db9ae91SMark Murray #include <sys/conf.h>
364db9ae91SMark Murray #include <sys/fcntl.h>
37fb919e4dSMark Murray #include <sys/filio.h>
384db9ae91SMark Murray #include <sys/kernel.h>
3902c986abSMark Murray #include <sys/kthread.h>
40fb919e4dSMark Murray #include <sys/lock.h>
414db9ae91SMark Murray #include <sys/malloc.h>
4241ee9f1cSPoul-Henning Kamp #include <sys/module.h>
43fb919e4dSMark Murray #include <sys/mutex.h>
44a6278a2aSMark Murray #include <sys/poll.h>
45acd3428bSRobert Watson #include <sys/priv.h>
46b40ce416SJulian Elischer #include <sys/proc.h>
47f02e47dcSMark Murray #include <sys/random.h>
48fb919e4dSMark Murray #include <sys/selinfo.h>
49fb919e4dSMark Murray #include <sys/uio.h>
5002c986abSMark Murray #include <sys/unistd.h>
514db9ae91SMark Murray 
5202c986abSMark Murray #include <machine/bus.h>
5302c986abSMark Murray #include <machine/cpu.h>
5402c986abSMark Murray 
5502c986abSMark Murray #include <dev/random/randomdev.h>
56*095ed2c9SMark Murray #include <dev/random/randomdev_soft.h>
57*095ed2c9SMark Murray #include <dev/random/random_adaptors.h>
58*095ed2c9SMark Murray #include <dev/random/random_harvestq.h>
59*095ed2c9SMark Murray #include <dev/random/live_entropy_sources.h>
604db9ae91SMark Murray 
61e7806b4cSMark Murray #define RANDOM_MINOR	0
62e7806b4cSMark Murray 
63c9ec235cSMark Murray static d_read_t random_read;
64c9ec235cSMark Murray static d_write_t random_write;
654d87a031SMark Murray static d_ioctl_t random_ioctl;
66a6278a2aSMark Murray static d_poll_t random_poll;
674db9ae91SMark Murray 
684db9ae91SMark Murray static struct cdevsw random_cdevsw = {
69dc08ffecSPoul-Henning Kamp 	.d_version = D_VERSION,
707ac40f5fSPoul-Henning Kamp 	.d_read = random_read,
717ac40f5fSPoul-Henning Kamp 	.d_write = random_write,
727ac40f5fSPoul-Henning Kamp 	.d_ioctl = random_ioctl,
737ac40f5fSPoul-Henning Kamp 	.d_poll = random_poll,
747ac40f5fSPoul-Henning Kamp 	.d_name = "random",
754db9ae91SMark Murray };
764db9ae91SMark Murray 
77*095ed2c9SMark Murray MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers");
78*095ed2c9SMark Murray 
794db9ae91SMark Murray /* For use with make_dev(9)/destroy_dev(9). */
8089c9c53dSPoul-Henning Kamp static struct cdev *random_dev;
814db9ae91SMark Murray 
82e1199601SMark Murray /* ARGSUSED */
8350636159SMark Murray static int
8489c9c53dSPoul-Henning Kamp random_read(struct cdev *dev __unused, struct uio *uio, int flag)
854db9ae91SMark Murray {
86e7806b4cSMark Murray 	int c, error = 0;
87fa2d865bSMark Murray 	void *random_buf;
884db9ae91SMark Murray 
89e7806b4cSMark Murray 	/* Blocking logic */
905711939bSDavid E. O'Brien 	if (!random_adaptor->seeded)
915711939bSDavid E. O'Brien 		error = (*random_adaptor->block)(flag);
92e7806b4cSMark Murray 
93e7806b4cSMark Murray 	/* The actual read */
94e7806b4cSMark Murray 	if (!error) {
95fa2d865bSMark Murray 
96*095ed2c9SMark Murray 		random_buf = (void *)malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK);
97fa2d865bSMark Murray 
98e7806b4cSMark Murray 		while (uio->uio_resid > 0 && !error) {
99e7806b4cSMark Murray 			c = MIN(uio->uio_resid, PAGE_SIZE);
1005711939bSDavid E. O'Brien 			c = (*random_adaptor->read)(random_buf, c);
101e7806b4cSMark Murray 			error = uiomove(random_buf, c, uio);
1024db9ae91SMark Murray 		}
103f02e47dcSMark Murray 		/* Finished reading; let the source know so it can do some
104f02e47dcSMark Murray 		 * optional housekeeping */
105f02e47dcSMark Murray 		(*random_adaptor->read)(NULL, 0);
106fa2d865bSMark Murray 
107*095ed2c9SMark Murray 		free(random_buf, M_ENTROPY);
108fa2d865bSMark Murray 
109e7806b4cSMark Murray 	}
110f587c6bfSMark Murray 
111e7806b4cSMark Murray 	return (error);
1124db9ae91SMark Murray }
1134db9ae91SMark Murray 
114e1199601SMark Murray /* ARGSUSED */
1154db9ae91SMark Murray static int
11689c9c53dSPoul-Henning Kamp random_write(struct cdev *dev __unused, struct uio *uio, int flag __unused)
1174db9ae91SMark Murray {
118fa2d865bSMark Murray 
119f02e47dcSMark Murray 	/* We used to allow this to insert userland entropy.
120f02e47dcSMark Murray 	 * We don't any more because (1) this so-called entropy
121f02e47dcSMark Murray 	 * is usually lousy and (b) its vaguely possible to
122f02e47dcSMark Murray 	 * mess with entropy harvesting by overdoing a write.
123f02e47dcSMark Murray 	 * Now we just ignore input like /dev/null does.
124f02e47dcSMark Murray 	 */
125f02e47dcSMark Murray 	uio->uio_resid = 0;
1264db9ae91SMark Murray 
127f02e47dcSMark Murray 	return (0);
1284db9ae91SMark Murray }
1294db9ae91SMark Murray 
130e1199601SMark Murray /* ARGSUSED */
1314db9ae91SMark Murray static int
13289c9c53dSPoul-Henning Kamp random_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr __unused,
133e1199601SMark Murray     int flags __unused, struct thread *td __unused)
1344d87a031SMark Murray {
135e7806b4cSMark Murray 	int error = 0;
136e7806b4cSMark Murray 
13741bc9751SMark Murray 	switch (cmd) {
13841bc9751SMark Murray 		/* Really handled in upper layer */
13941bc9751SMark Murray 	case FIOASYNC:
14041bc9751SMark Murray 	case FIONBIO:
141e7806b4cSMark Murray 		break;
14241bc9751SMark Murray 	default:
143e7806b4cSMark Murray 		error = ENOTTY;
1444d87a031SMark Murray 	}
145e7806b4cSMark Murray 	return (error);
14641bc9751SMark Murray }
1474d87a031SMark Murray 
148e1199601SMark Murray /* ARGSUSED */
1494d87a031SMark Murray static int
15089c9c53dSPoul-Henning Kamp random_poll(struct cdev *dev __unused, int events, struct thread *td)
151a6278a2aSMark Murray {
152e7806b4cSMark Murray 	int revents = 0;
153a6278a2aSMark Murray 
154a6278a2aSMark Murray 	if (events & (POLLIN | POLLRDNORM)) {
1555711939bSDavid E. O'Brien 		if (random_adaptor->seeded)
156a6278a2aSMark Murray 			revents = events & (POLLIN | POLLRDNORM);
157a6278a2aSMark Murray 		else
1585711939bSDavid E. O'Brien 			revents = (*random_adaptor->poll)(events, td);
159a6278a2aSMark Murray 	}
160e7806b4cSMark Murray 	return (revents);
161a6278a2aSMark Murray }
162a6278a2aSMark Murray 
1635711939bSDavid E. O'Brien static void
1645711939bSDavid E. O'Brien random_initialize(void *p, struct random_adaptor *s)
1655711939bSDavid E. O'Brien {
166f02e47dcSMark Murray 	static int random_inited = 0;
167f02e47dcSMark Murray 
1685711939bSDavid E. O'Brien 	if (random_inited) {
1695711939bSDavid E. O'Brien 		printf("random: <%s> already initialized\n",
1705711939bSDavid E. O'Brien 		    random_adaptor->ident);
1715711939bSDavid E. O'Brien 		return;
1725711939bSDavid E. O'Brien 	}
1735711939bSDavid E. O'Brien 
1745711939bSDavid E. O'Brien 	random_adaptor = s;
1755711939bSDavid E. O'Brien 
1765711939bSDavid E. O'Brien 	(s->init)();
1775711939bSDavid E. O'Brien 
1785711939bSDavid E. O'Brien 	printf("random: <%s> initialized\n", s->ident);
1795711939bSDavid E. O'Brien 
180f02e47dcSMark Murray 	/* Use an appropriately evil mode for those who are concerned
181f02e47dcSMark Murray 	 * with daemons */
1825711939bSDavid E. O'Brien 	random_dev = make_dev_credf(MAKEDEV_ETERNAL_KLD, &random_cdevsw,
1835711939bSDavid E. O'Brien 	    RANDOM_MINOR, NULL, UID_ROOT, GID_WHEEL, 0666, "random");
1845711939bSDavid E. O'Brien 
1855711939bSDavid E. O'Brien 	/* mark random(4) as initialized, to avoid being called again */
1865711939bSDavid E. O'Brien 	random_inited = 1;
1875711939bSDavid E. O'Brien }
1885711939bSDavid E. O'Brien 
189e1199601SMark Murray /* ARGSUSED */
190a6278a2aSMark Murray static int
191e1199601SMark Murray random_modevent(module_t mod __unused, int type, void *data __unused)
1924db9ae91SMark Murray {
193f02e47dcSMark Murray 	static eventhandler_tag attach_tag = NULL;
194e7806b4cSMark Murray 	int error = 0;
1954d87a031SMark Murray 
1964db9ae91SMark Murray 	switch (type) {
1974db9ae91SMark Murray 	case MOD_LOAD:
198ddbfa6b1SMark Murray 		random_adaptor_choose(&random_adaptor);
199b79ad7e6SMark Murray 
2005711939bSDavid E. O'Brien 		if (random_adaptor == NULL) {
201f02e47dcSMark Murray 			printf("random: No random adaptor attached, "
202f02e47dcSMark Murray 			    "postponing initialization\n");
2035711939bSDavid E. O'Brien 			attach_tag = EVENTHANDLER_REGISTER(random_adaptor_attach,
2045711939bSDavid E. O'Brien 			    random_initialize, NULL, EVENTHANDLER_PRI_ANY);
205f02e47dcSMark Murray 		} else
2065711939bSDavid E. O'Brien 			random_initialize(NULL, random_adaptor);
207b79ad7e6SMark Murray 
208e7806b4cSMark Murray 		break;
2094db9ae91SMark Murray 
2104db9ae91SMark Murray 	case MOD_UNLOAD:
2115711939bSDavid E. O'Brien 		if (random_adaptor != NULL) {
2125711939bSDavid E. O'Brien 			(*random_adaptor->deinit)();
213c9ec235cSMark Murray 			destroy_dev(random_dev);
2145711939bSDavid E. O'Brien 		}
2155711939bSDavid E. O'Brien 		/* Unregister the event handler */
216f02e47dcSMark Murray 		if (attach_tag != NULL)
2175711939bSDavid E. O'Brien 			EVENTHANDLER_DEREGISTER(random_adaptor_attach,
2185711939bSDavid E. O'Brien 			    attach_tag);
219e7806b4cSMark Murray 
220e7806b4cSMark Murray 		break;
2214db9ae91SMark Murray 
2224db9ae91SMark Murray 	case MOD_SHUTDOWN:
223e7806b4cSMark Murray 		break;
2244db9ae91SMark Murray 
2253e019deaSPoul-Henning Kamp 	default:
2263e019deaSPoul-Henning Kamp 		error = EOPNOTSUPP;
2273e019deaSPoul-Henning Kamp 		break;
2283e019deaSPoul-Henning Kamp 
2294db9ae91SMark Murray 	}
230e7806b4cSMark Murray 	return (error);
2314db9ae91SMark Murray }
2324db9ae91SMark Murray 
2334db9ae91SMark Murray DEV_MODULE(random, random_modevent, NULL);
234ce46e205SMark Murray MODULE_VERSION(random, 1);
235