| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: kern_entropy.c,v 1.48 2022/03/20 14:05:41 riastradh Exp $ */ | | 1 | /* $NetBSD: kern_entropy.c,v 1.49 2022/03/20 14:30:56 riastradh Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2019 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 2019 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Taylor R. Campbell. | | 8 | * by Taylor R. Campbell. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
| @@ -65,27 +65,27 @@ | | | @@ -65,27 +65,27 @@ |
65 | * * No entropy estimation based on the sample values, which is a | | 65 | * * No entropy estimation based on the sample values, which is a |
66 | * contradiction in terms and a potential source of side | | 66 | * contradiction in terms and a potential source of side |
67 | * channels. It is the responsibility of the driver author to | | 67 | * channels. It is the responsibility of the driver author to |
68 | * study how predictable the physical source of input can ever | | 68 | * study how predictable the physical source of input can ever |
69 | * be, and to furnish a lower bound on the amount of entropy it | | 69 | * be, and to furnish a lower bound on the amount of entropy it |
70 | * has. | | 70 | * has. |
71 | * | | 71 | * |
72 | * * Entropy depletion is available for testing (or if you're into | | 72 | * * Entropy depletion is available for testing (or if you're into |
73 | * that sort of thing), with sysctl -w kern.entropy.depletion=1; | | 73 | * that sort of thing), with sysctl -w kern.entropy.depletion=1; |
74 | * the logic to support it is small, to minimize chance of bugs. | | 74 | * the logic to support it is small, to minimize chance of bugs. |
75 | */ | | 75 | */ |
76 | | | 76 | |
77 | #include <sys/cdefs.h> | | 77 | #include <sys/cdefs.h> |
78 | __KERNEL_RCSID(0, "$NetBSD: kern_entropy.c,v 1.48 2022/03/20 14:05:41 riastradh Exp $"); | | 78 | __KERNEL_RCSID(0, "$NetBSD: kern_entropy.c,v 1.49 2022/03/20 14:30:56 riastradh Exp $"); |
79 | | | 79 | |
80 | #include <sys/param.h> | | 80 | #include <sys/param.h> |
81 | #include <sys/types.h> | | 81 | #include <sys/types.h> |
82 | #include <sys/atomic.h> | | 82 | #include <sys/atomic.h> |
83 | #include <sys/compat_stub.h> | | 83 | #include <sys/compat_stub.h> |
84 | #include <sys/condvar.h> | | 84 | #include <sys/condvar.h> |
85 | #include <sys/cpu.h> | | 85 | #include <sys/cpu.h> |
86 | #include <sys/entropy.h> | | 86 | #include <sys/entropy.h> |
87 | #include <sys/errno.h> | | 87 | #include <sys/errno.h> |
88 | #include <sys/evcnt.h> | | 88 | #include <sys/evcnt.h> |
89 | #include <sys/event.h> | | 89 | #include <sys/event.h> |
90 | #include <sys/file.h> | | 90 | #include <sys/file.h> |
91 | #include <sys/intr.h> | | 91 | #include <sys/intr.h> |
| @@ -250,27 +250,27 @@ static void entropy_account_cpu(struct e | | | @@ -250,27 +250,27 @@ static void entropy_account_cpu(struct e |
250 | static void entropy_enter(const void *, size_t, unsigned); | | 250 | static void entropy_enter(const void *, size_t, unsigned); |
251 | static bool entropy_enter_intr(const void *, size_t, unsigned); | | 251 | static bool entropy_enter_intr(const void *, size_t, unsigned); |
252 | static void entropy_softintr(void *); | | 252 | static void entropy_softintr(void *); |
253 | static void entropy_thread(void *); | | 253 | static void entropy_thread(void *); |
254 | static uint32_t entropy_pending(void); | | 254 | static uint32_t entropy_pending(void); |
255 | static void entropy_pending_cpu(void *, void *, struct cpu_info *); | | 255 | static void entropy_pending_cpu(void *, void *, struct cpu_info *); |
256 | static void entropy_do_consolidate(void); | | 256 | static void entropy_do_consolidate(void); |
257 | static void entropy_consolidate_xc(void *, void *); | | 257 | static void entropy_consolidate_xc(void *, void *); |
258 | static void entropy_notify(void); | | 258 | static void entropy_notify(void); |
259 | static int sysctl_entropy_consolidate(SYSCTLFN_ARGS); | | 259 | static int sysctl_entropy_consolidate(SYSCTLFN_ARGS); |
260 | static int sysctl_entropy_gather(SYSCTLFN_ARGS); | | 260 | static int sysctl_entropy_gather(SYSCTLFN_ARGS); |
261 | static void filt_entropy_read_detach(struct knote *); | | 261 | static void filt_entropy_read_detach(struct knote *); |
262 | static int filt_entropy_read_event(struct knote *, long); | | 262 | static int filt_entropy_read_event(struct knote *, long); |
263 | static void entropy_request(size_t); | | 263 | static int entropy_request(size_t, int); |
264 | static void rnd_add_data_1(struct krndsource *, const void *, uint32_t, | | 264 | static void rnd_add_data_1(struct krndsource *, const void *, uint32_t, |
265 | uint32_t, uint32_t); | | 265 | uint32_t, uint32_t); |
266 | static unsigned rndsource_entropybits(struct krndsource *); | | 266 | static unsigned rndsource_entropybits(struct krndsource *); |
267 | static void rndsource_entropybits_cpu(void *, void *, struct cpu_info *); | | 267 | static void rndsource_entropybits_cpu(void *, void *, struct cpu_info *); |
268 | static void rndsource_to_user(struct krndsource *, rndsource_t *); | | 268 | static void rndsource_to_user(struct krndsource *, rndsource_t *); |
269 | static void rndsource_to_user_est(struct krndsource *, rndsource_est_t *); | | 269 | static void rndsource_to_user_est(struct krndsource *, rndsource_est_t *); |
270 | static void rndsource_to_user_est_cpu(void *, void *, struct cpu_info *); | | 270 | static void rndsource_to_user_est_cpu(void *, void *, struct cpu_info *); |
271 | | | 271 | |
272 | /* | | 272 | /* |
273 | * entropy_timer() | | 273 | * entropy_timer() |
274 | * | | 274 | * |
275 | * Cycle counter, time counter, or anything that changes a wee bit | | 275 | * Cycle counter, time counter, or anything that changes a wee bit |
276 | * unpredictably. | | 276 | * unpredictably. |
| @@ -638,35 +638,37 @@ entropy_seed(rndsave_t *seed) | | | @@ -638,35 +638,37 @@ entropy_seed(rndsave_t *seed) |
638 | seed->entropy); | | 638 | seed->entropy); |
639 | explicit_memset(seed, 0, sizeof(*seed)); | | 639 | explicit_memset(seed, 0, sizeof(*seed)); |
640 | } | | 640 | } |
641 | | | 641 | |
642 | /* | | 642 | /* |
643 | * entropy_bootrequest() | | 643 | * entropy_bootrequest() |
644 | * | | 644 | * |
645 | * Request entropy from all sources at boot, once config is | | 645 | * Request entropy from all sources at boot, once config is |
646 | * complete and interrupts are running. | | 646 | * complete and interrupts are running. |
647 | */ | | 647 | */ |
648 | void | | 648 | void |
649 | entropy_bootrequest(void) | | 649 | entropy_bootrequest(void) |
650 | { | | 650 | { |
| | | 651 | int error; |
651 | | | 652 | |
652 | KASSERT(E->stage >= ENTROPY_WARM); | | 653 | KASSERT(E->stage >= ENTROPY_WARM); |
653 | | | 654 | |
654 | /* | | 655 | /* |
655 | * Request enough to satisfy the maximum entropy shortage. | | 656 | * Request enough to satisfy the maximum entropy shortage. |
656 | * This is harmless overkill if the bootloader provided a seed. | | 657 | * This is harmless overkill if the bootloader provided a seed. |
657 | */ | | 658 | */ |
658 | mutex_enter(&E->lock); | | 659 | mutex_enter(&E->lock); |
659 | entropy_request(ENTROPY_CAPACITY); | | 660 | error = entropy_request(ENTROPY_CAPACITY, ENTROPY_WAIT); |
| | | 661 | KASSERT(error == 0); |
660 | mutex_exit(&E->lock); | | 662 | mutex_exit(&E->lock); |
661 | } | | 663 | } |
662 | | | 664 | |
663 | /* | | 665 | /* |
664 | * entropy_epoch() | | 666 | * entropy_epoch() |
665 | * | | 667 | * |
666 | * Returns the current entropy epoch. If this changes, you should | | 668 | * Returns the current entropy epoch. If this changes, you should |
667 | * reseed. If -1, means system entropy has not yet reached full | | 669 | * reseed. If -1, means system entropy has not yet reached full |
668 | * entropy or been explicitly consolidated; never reverts back to | | 670 | * entropy or been explicitly consolidated; never reverts back to |
669 | * -1. Never zero, so you can always use zero as an uninitialized | | 671 | * -1. Never zero, so you can always use zero as an uninitialized |
670 | * sentinel value meaning `reseed ASAP'. | | 672 | * sentinel value meaning `reseed ASAP'. |
671 | * | | 673 | * |
672 | * Usage model: | | 674 | * Usage model: |
| @@ -1290,27 +1292,28 @@ sysctl_entropy_gather(SYSCTLFN_ARGS) | | | @@ -1290,27 +1292,28 @@ sysctl_entropy_gather(SYSCTLFN_ARGS) |
1290 | { | | 1292 | { |
1291 | struct sysctlnode node = *rnode; | | 1293 | struct sysctlnode node = *rnode; |
1292 | int arg; | | 1294 | int arg; |
1293 | int error; | | 1295 | int error; |
1294 | | | 1296 | |
1295 | KASSERT(E->stage == ENTROPY_HOT); | | 1297 | KASSERT(E->stage == ENTROPY_HOT); |
1296 | | | 1298 | |
1297 | node.sysctl_data = &arg; | | 1299 | node.sysctl_data = &arg; |
1298 | error = sysctl_lookup(SYSCTLFN_CALL(&node)); | | 1300 | error = sysctl_lookup(SYSCTLFN_CALL(&node)); |
1299 | if (error || newp == NULL) | | 1301 | if (error || newp == NULL) |
1300 | return error; | | 1302 | return error; |
1301 | if (arg) { | | 1303 | if (arg) { |
1302 | mutex_enter(&E->lock); | | 1304 | mutex_enter(&E->lock); |
1303 | entropy_request(ENTROPY_CAPACITY); | | 1305 | error = entropy_request(ENTROPY_CAPACITY, |
| | | 1306 | ENTROPY_WAIT|ENTROPY_SIG); |
1304 | mutex_exit(&E->lock); | | 1307 | mutex_exit(&E->lock); |
1305 | } | | 1308 | } |
1306 | | | 1309 | |
1307 | return 0; | | 1310 | return 0; |
1308 | } | | 1311 | } |
1309 | | | 1312 | |
1310 | /* | | 1313 | /* |
1311 | * entropy_extract(buf, len, flags) | | 1314 | * entropy_extract(buf, len, flags) |
1312 | * | | 1315 | * |
1313 | * Extract len bytes from the global entropy pool into buf. | | 1316 | * Extract len bytes from the global entropy pool into buf. |
1314 | * | | 1317 | * |
1315 | * Flags may have: | | 1318 | * Flags may have: |
1316 | * | | 1319 | * |
| @@ -1343,27 +1346,29 @@ entropy_extract(void *buf, size_t len, i | | | @@ -1343,27 +1346,29 @@ entropy_extract(void *buf, size_t len, i |
1343 | } | | 1346 | } |
1344 | | | 1347 | |
1345 | /* Refuse to operate in interrupt context. */ | | 1348 | /* Refuse to operate in interrupt context. */ |
1346 | KASSERT(!cpu_intr_p()); | | 1349 | KASSERT(!cpu_intr_p()); |
1347 | | | 1350 | |
1348 | /* Acquire the global lock to get at the global pool. */ | | 1351 | /* Acquire the global lock to get at the global pool. */ |
1349 | if (E->stage >= ENTROPY_WARM) | | 1352 | if (E->stage >= ENTROPY_WARM) |
1350 | mutex_enter(&E->lock); | | 1353 | mutex_enter(&E->lock); |
1351 | | | 1354 | |
1352 | /* Wait until there is enough entropy in the system. */ | | 1355 | /* Wait until there is enough entropy in the system. */ |
1353 | error = 0; | | 1356 | error = 0; |
1354 | while (E->needed) { | | 1357 | while (E->needed) { |
1355 | /* Ask for more, synchronously if possible. */ | | 1358 | /* Ask for more, synchronously if possible. */ |
1356 | entropy_request(len); | | 1359 | error = entropy_request(len, flags); |
| | | 1360 | if (error) |
| | | 1361 | break; |
1357 | | | 1362 | |
1358 | /* If we got enough, we're done. */ | | 1363 | /* If we got enough, we're done. */ |
1359 | if (E->needed == 0) { | | 1364 | if (E->needed == 0) { |
1360 | KASSERT(error == 0); | | 1365 | KASSERT(error == 0); |
1361 | break; | | 1366 | break; |
1362 | } | | 1367 | } |
1363 | | | 1368 | |
1364 | /* If not waiting, stop here. */ | | 1369 | /* If not waiting, stop here. */ |
1365 | if (!ISSET(flags, ENTROPY_WAIT)) { | | 1370 | if (!ISSET(flags, ENTROPY_WAIT)) { |
1366 | error = EWOULDBLOCK; | | 1371 | error = EWOULDBLOCK; |
1367 | break; | | 1372 | break; |
1368 | } | | 1373 | } |
1369 | | | 1374 | |
| @@ -1667,75 +1672,64 @@ rnd_detach_source(struct krndsource *rs) | | | @@ -1667,75 +1672,64 @@ rnd_detach_source(struct krndsource *rs) |
1667 | | | 1672 | |
1668 | /* Wait until the source list is not in use, and remove it. */ | | 1673 | /* Wait until the source list is not in use, and remove it. */ |
1669 | mutex_enter(&E->lock); | | 1674 | mutex_enter(&E->lock); |
1670 | while (E->sourcelock) | | 1675 | while (E->sourcelock) |
1671 | cv_wait(&E->sourcelock_cv, &E->lock); | | 1676 | cv_wait(&E->sourcelock_cv, &E->lock); |
1672 | LIST_REMOVE(rs, list); | | 1677 | LIST_REMOVE(rs, list); |
1673 | mutex_exit(&E->lock); | | 1678 | mutex_exit(&E->lock); |
1674 | | | 1679 | |
1675 | /* Free the per-CPU data. */ | | 1680 | /* Free the per-CPU data. */ |
1676 | percpu_free(rs->state, sizeof(struct rndsource_cpu)); | | 1681 | percpu_free(rs->state, sizeof(struct rndsource_cpu)); |
1677 | } | | 1682 | } |
1678 | | | 1683 | |
1679 | /* | | 1684 | /* |
1680 | * rnd_lock_sources() | | 1685 | * rnd_lock_sources(flags) |
| | | 1686 | * |
| | | 1687 | * Lock the list of entropy sources. Caller must hold the global |
| | | 1688 | * entropy lock. If successful, no rndsource will go away until |
| | | 1689 | * rnd_unlock_sources even while the caller releases the global |
| | | 1690 | * entropy lock. |
1681 | * | | 1691 | * |
1682 | * Prevent changes to the list of rndsources while we iterate it. | | 1692 | * If flags & ENTROPY_WAIT, wait for concurrent access to finish. |
1683 | * Interruptible. Caller must hold the global entropy lock. If | | 1693 | * If flags & ENTROPY_SIG, allow interruption by signal. |
1684 | * successful, no rndsource will go away until rnd_unlock_sources | | | |
1685 | * even while the caller releases the global entropy lock. | | | |
1686 | */ | | 1694 | */ |
1687 | static int | | 1695 | static int __attribute__((warn_unused_result)) |
1688 | rnd_lock_sources(void) | | 1696 | rnd_lock_sources(int flags) |
1689 | { | | 1697 | { |
1690 | int error; | | 1698 | int error; |
1691 | | | 1699 | |
1692 | KASSERT(mutex_owned(&E->lock)); | | 1700 | KASSERT(mutex_owned(&E->lock)); |
1693 | | | 1701 | |
1694 | while (E->sourcelock) { | | 1702 | while (E->sourcelock) { |
1695 | error = cv_wait_sig(&E->sourcelock_cv, &E->lock); | | 1703 | if (!ISSET(flags, ENTROPY_WAIT)) |
1696 | if (error) | | 1704 | return EWOULDBLOCK; |
1697 | return error; | | 1705 | if (ISSET(flags, ENTROPY_SIG)) { |
| | | 1706 | error = cv_wait_sig(&E->sourcelock_cv, &E->lock); |
| | | 1707 | if (error) |
| | | 1708 | return error; |
| | | 1709 | } else { |
| | | 1710 | cv_wait(&E->sourcelock_cv, &E->lock); |
| | | 1711 | } |
1698 | } | | 1712 | } |
1699 | | | 1713 | |
1700 | E->sourcelock = curlwp; | | 1714 | E->sourcelock = curlwp; |
1701 | return 0; | | 1715 | return 0; |
1702 | } | | 1716 | } |
1703 | | | 1717 | |
1704 | /* | | 1718 | /* |
1705 | * rnd_trylock_sources() | | | |
1706 | * | | | |
1707 | * Try to lock the list of sources, but if it's already locked, | | | |
1708 | * fail. Caller must hold the global entropy lock. If | | | |
1709 | * successful, no rndsource will go away until rnd_unlock_sources | | | |
1710 | * even while the caller releases the global entropy lock. | | | |
1711 | */ | | | |
1712 | static bool | | | |
1713 | rnd_trylock_sources(void) | | | |
1714 | { | | | |
1715 | | | | |
1716 | KASSERT(E->stage == ENTROPY_COLD || mutex_owned(&E->lock)); | | | |
1717 | | | | |
1718 | if (E->sourcelock) | | | |
1719 | return false; | | | |
1720 | E->sourcelock = curlwp; | | | |
1721 | return true; | | | |
1722 | } | | | |
1723 | | | | |
1724 | /* | | | |
1725 | * rnd_unlock_sources() | | 1719 | * rnd_unlock_sources() |
1726 | * | | 1720 | * |
1727 | * Unlock the list of sources after rnd_lock_sources or | | 1721 | * Unlock the list of sources after rnd_lock_sources. Caller must |
1728 | * rnd_trylock_sources. Caller must hold the global entropy lock. | | 1722 | * hold the global entropy lock. |
1729 | */ | | 1723 | */ |
1730 | static void | | 1724 | static void |
1731 | rnd_unlock_sources(void) | | 1725 | rnd_unlock_sources(void) |
1732 | { | | 1726 | { |
1733 | | | 1727 | |
1734 | KASSERT(E->stage == ENTROPY_COLD || mutex_owned(&E->lock)); | | 1728 | KASSERT(E->stage == ENTROPY_COLD || mutex_owned(&E->lock)); |
1735 | | | 1729 | |
1736 | KASSERTMSG(E->sourcelock == curlwp, "lwp %p releasing lock held by %p", | | 1730 | KASSERTMSG(E->sourcelock == curlwp, "lwp %p releasing lock held by %p", |
1737 | curlwp, E->sourcelock); | | 1731 | curlwp, E->sourcelock); |
1738 | E->sourcelock = NULL; | | 1732 | E->sourcelock = NULL; |
1739 | if (E->stage >= ENTROPY_WARM) | | 1733 | if (E->stage >= ENTROPY_WARM) |
1740 | cv_signal(&E->sourcelock_cv); | | 1734 | cv_signal(&E->sourcelock_cv); |
1741 | } | | 1735 | } |
| @@ -1744,74 +1738,82 @@ rnd_unlock_sources(void) | | | @@ -1744,74 +1738,82 @@ rnd_unlock_sources(void) |
1744 | * rnd_sources_locked() | | 1738 | * rnd_sources_locked() |
1745 | * | | 1739 | * |
1746 | * True if we hold the list of rndsources locked, for diagnostic | | 1740 | * True if we hold the list of rndsources locked, for diagnostic |
1747 | * assertions. | | 1741 | * assertions. |
1748 | */ | | 1742 | */ |
1749 | static bool __diagused | | 1743 | static bool __diagused |
1750 | rnd_sources_locked(void) | | 1744 | rnd_sources_locked(void) |
1751 | { | | 1745 | { |
1752 | | | 1746 | |
1753 | return E->sourcelock == curlwp; | | 1747 | return E->sourcelock == curlwp; |
1754 | } | | 1748 | } |
1755 | | | 1749 | |
1756 | /* | | 1750 | /* |
1757 | * entropy_request(nbytes) | | 1751 | * entropy_request(nbytes, flags) |
1758 | * | | 1752 | * |
1759 | * Request nbytes bytes of entropy from all sources in the system. | | 1753 | * Request nbytes bytes of entropy from all sources in the system. |
1760 | * OK if we overdo it. Caller must hold the global entropy lock; | | 1754 | * OK if we overdo it. Caller must hold the global entropy lock; |
1761 | * will release and re-acquire it. | | 1755 | * will release and re-acquire it. |
| | | 1756 | * |
| | | 1757 | * If flags & ENTROPY_WAIT, wait for concurrent access to finish. |
| | | 1758 | * If flags & ENTROPY_SIG, allow interruption by signal. |
1762 | */ | | 1759 | */ |
1763 | static void | | 1760 | static int |
1764 | entropy_request(size_t nbytes) | | 1761 | entropy_request(size_t nbytes, int flags) |
1765 | { | | 1762 | { |
1766 | struct krndsource *rs; | | 1763 | struct krndsource *rs; |
| | | 1764 | int error; |
1767 | | | 1765 | |
1768 | KASSERT(E->stage == ENTROPY_COLD || mutex_owned(&E->lock)); | | 1766 | KASSERT(E->stage == ENTROPY_COLD || mutex_owned(&E->lock)); |
| | | 1767 | if (flags & ENTROPY_WAIT) |
| | | 1768 | ASSERT_SLEEPABLE(); |
1769 | | | 1769 | |
1770 | /* | | 1770 | /* |
1771 | * If there is a request in progress, let it proceed. | | 1771 | * Lock the list of entropy sources to block rnd_detach_source |
1772 | * Otherwise, note that a request is in progress to avoid | | 1772 | * until we're done, and to serialize calls to the entropy |
1773 | * reentry and to block rnd_detach_source until we're done. | | 1773 | * callbacks as guaranteed to drivers. |
1774 | */ | | 1774 | */ |
1775 | if (!rnd_trylock_sources()) | | 1775 | error = rnd_lock_sources(flags); |
1776 | return; | | 1776 | if (error) |
| | | 1777 | return error; |
1777 | entropy_request_evcnt.ev_count++; | | 1778 | entropy_request_evcnt.ev_count++; |
1778 | | | 1779 | |
1779 | /* Clamp to the maximum reasonable request. */ | | 1780 | /* Clamp to the maximum reasonable request. */ |
1780 | nbytes = MIN(nbytes, ENTROPY_CAPACITY); | | 1781 | nbytes = MIN(nbytes, ENTROPY_CAPACITY); |
1781 | | | 1782 | |
1782 | /* Walk the list of sources. */ | | 1783 | /* Walk the list of sources. */ |
1783 | LIST_FOREACH(rs, &E->sources, list) { | | 1784 | LIST_FOREACH(rs, &E->sources, list) { |
1784 | /* Skip sources without callbacks. */ | | 1785 | /* Skip sources without callbacks. */ |
1785 | if (!ISSET(rs->flags, RND_FLAG_HASCB)) | | 1786 | if (!ISSET(rs->flags, RND_FLAG_HASCB)) |
1786 | continue; | | 1787 | continue; |
1787 | | | 1788 | |
1788 | /* | | 1789 | /* |
1789 | * Skip sources that are disabled altogether -- we | | 1790 | * Skip sources that are disabled altogether -- we |
1790 | * would just ignore their samples anyway. | | 1791 | * would just ignore their samples anyway. |
1791 | */ | | 1792 | */ |
1792 | if (ISSET(rs->flags, RND_FLAG_NO_COLLECT)) | | 1793 | if (ISSET(rs->flags, RND_FLAG_NO_COLLECT)) |
1793 | continue; | | 1794 | continue; |
1794 | | | 1795 | |
1795 | /* Drop the lock while we call the callback. */ | | 1796 | /* Drop the lock while we call the callback. */ |
1796 | if (E->stage >= ENTROPY_WARM) | | 1797 | if (E->stage >= ENTROPY_WARM) |
1797 | mutex_exit(&E->lock); | | 1798 | mutex_exit(&E->lock); |
1798 | (*rs->get)(nbytes, rs->getarg); | | 1799 | (*rs->get)(nbytes, rs->getarg); |
1799 | if (E->stage >= ENTROPY_WARM) | | 1800 | if (E->stage >= ENTROPY_WARM) |
1800 | mutex_enter(&E->lock); | | 1801 | mutex_enter(&E->lock); |
1801 | } | | 1802 | } |
1802 | | | 1803 | |
1803 | /* Notify rnd_detach_source that the request is done. */ | | 1804 | /* Request done; unlock the list of entropy sources. */ |
1804 | rnd_unlock_sources(); | | 1805 | rnd_unlock_sources(); |
| | | 1806 | return 0; |
1805 | } | | 1807 | } |
1806 | | | 1808 | |
1807 | /* | | 1809 | /* |
1808 | * rnd_add_uint32(rs, value) | | 1810 | * rnd_add_uint32(rs, value) |
1809 | * | | 1811 | * |
1810 | * Enter 32 bits of data from an entropy source into the pool. | | 1812 | * Enter 32 bits of data from an entropy source into the pool. |
1811 | * | | 1813 | * |
1812 | * If rs is NULL, may not be called from interrupt context. | | 1814 | * If rs is NULL, may not be called from interrupt context. |
1813 | * | | 1815 | * |
1814 | * If rs is non-NULL, may be called from any context. May drop | | 1816 | * If rs is non-NULL, may be called from any context. May drop |
1815 | * data if called from interrupt context. | | 1817 | * data if called from interrupt context. |
1816 | */ | | 1818 | */ |
1817 | void | | 1819 | void |
| @@ -2198,27 +2200,27 @@ entropy_ioctl(unsigned long cmd, void *d | | | @@ -2198,27 +2200,27 @@ entropy_ioctl(unsigned long cmd, void *d |
2198 | uint32_t start = 0, i = 0; | | 2200 | uint32_t start = 0, i = 0; |
2199 | | | 2201 | |
2200 | /* Skip if none requested; fail if too many requested. */ | | 2202 | /* Skip if none requested; fail if too many requested. */ |
2201 | if (stat->count == 0) | | 2203 | if (stat->count == 0) |
2202 | break; | | 2204 | break; |
2203 | if (stat->count > RND_MAXSTATCOUNT) | | 2205 | if (stat->count > RND_MAXSTATCOUNT) |
2204 | return EINVAL; | | 2206 | return EINVAL; |
2205 | | | 2207 | |
2206 | /* | | 2208 | /* |
2207 | * Under the lock, find the first one, copy out as many | | 2209 | * Under the lock, find the first one, copy out as many |
2208 | * as requested, and report how many we copied out. | | 2210 | * as requested, and report how many we copied out. |
2209 | */ | | 2211 | */ |
2210 | mutex_enter(&E->lock); | | 2212 | mutex_enter(&E->lock); |
2211 | error = rnd_lock_sources(); | | 2213 | error = rnd_lock_sources(ENTROPY_WAIT|ENTROPY_SIG); |
2212 | if (error) { | | 2214 | if (error) { |
2213 | mutex_exit(&E->lock); | | 2215 | mutex_exit(&E->lock); |
2214 | return error; | | 2216 | return error; |
2215 | } | | 2217 | } |
2216 | LIST_FOREACH(rs, &E->sources, list) { | | 2218 | LIST_FOREACH(rs, &E->sources, list) { |
2217 | if (start++ == stat->start) | | 2219 | if (start++ == stat->start) |
2218 | break; | | 2220 | break; |
2219 | } | | 2221 | } |
2220 | while (i < stat->count && rs != NULL) { | | 2222 | while (i < stat->count && rs != NULL) { |
2221 | mutex_exit(&E->lock); | | 2223 | mutex_exit(&E->lock); |
2222 | rndsource_to_user(rs, &stat->source[i++]); | | 2224 | rndsource_to_user(rs, &stat->source[i++]); |
2223 | mutex_enter(&E->lock); | | 2225 | mutex_enter(&E->lock); |
2224 | rs = LIST_NEXT(rs, list); | | 2226 | rs = LIST_NEXT(rs, list); |
| @@ -2234,27 +2236,27 @@ entropy_ioctl(unsigned long cmd, void *d | | | @@ -2234,27 +2236,27 @@ entropy_ioctl(unsigned long cmd, void *d |
2234 | uint32_t start = 0, i = 0; | | 2236 | uint32_t start = 0, i = 0; |
2235 | | | 2237 | |
2236 | /* Skip if none requested; fail if too many requested. */ | | 2238 | /* Skip if none requested; fail if too many requested. */ |
2237 | if (estat->count == 0) | | 2239 | if (estat->count == 0) |
2238 | break; | | 2240 | break; |
2239 | if (estat->count > RND_MAXSTATCOUNT) | | 2241 | if (estat->count > RND_MAXSTATCOUNT) |
2240 | return EINVAL; | | 2242 | return EINVAL; |
2241 | | | 2243 | |
2242 | /* | | 2244 | /* |
2243 | * Under the lock, find the first one, copy out as many | | 2245 | * Under the lock, find the first one, copy out as many |
2244 | * as requested, and report how many we copied out. | | 2246 | * as requested, and report how many we copied out. |
2245 | */ | | 2247 | */ |
2246 | mutex_enter(&E->lock); | | 2248 | mutex_enter(&E->lock); |
2247 | error = rnd_lock_sources(); | | 2249 | error = rnd_lock_sources(ENTROPY_WAIT|ENTROPY_SIG); |
2248 | if (error) { | | 2250 | if (error) { |
2249 | mutex_exit(&E->lock); | | 2251 | mutex_exit(&E->lock); |
2250 | return error; | | 2252 | return error; |
2251 | } | | 2253 | } |
2252 | LIST_FOREACH(rs, &E->sources, list) { | | 2254 | LIST_FOREACH(rs, &E->sources, list) { |
2253 | if (start++ == estat->start) | | 2255 | if (start++ == estat->start) |
2254 | break; | | 2256 | break; |
2255 | } | | 2257 | } |
2256 | while (i < estat->count && rs != NULL) { | | 2258 | while (i < estat->count && rs != NULL) { |
2257 | mutex_exit(&E->lock); | | 2259 | mutex_exit(&E->lock); |
2258 | rndsource_to_user_est(rs, &estat->source[i++]); | | 2260 | rndsource_to_user_est(rs, &estat->source[i++]); |
2259 | mutex_enter(&E->lock); | | 2261 | mutex_enter(&E->lock); |
2260 | rs = LIST_NEXT(rs, list); | | 2262 | rs = LIST_NEXT(rs, list); |
| @@ -2266,27 +2268,27 @@ entropy_ioctl(unsigned long cmd, void *d | | | @@ -2266,27 +2268,27 @@ entropy_ioctl(unsigned long cmd, void *d |
2266 | break; | | 2268 | break; |
2267 | } | | 2269 | } |
2268 | case RNDGETSRCNAME: { /* Get entropy sources by name. */ | | 2270 | case RNDGETSRCNAME: { /* Get entropy sources by name. */ |
2269 | rndstat_name_t *nstat = data; | | 2271 | rndstat_name_t *nstat = data; |
2270 | const size_t n = sizeof(rs->name); | | 2272 | const size_t n = sizeof(rs->name); |
2271 | | | 2273 | |
2272 | CTASSERT(sizeof(rs->name) == sizeof(nstat->name)); | | 2274 | CTASSERT(sizeof(rs->name) == sizeof(nstat->name)); |
2273 | | | 2275 | |
2274 | /* | | 2276 | /* |
2275 | * Under the lock, search by name. If found, copy it | | 2277 | * Under the lock, search by name. If found, copy it |
2276 | * out; if not found, fail with ENOENT. | | 2278 | * out; if not found, fail with ENOENT. |
2277 | */ | | 2279 | */ |
2278 | mutex_enter(&E->lock); | | 2280 | mutex_enter(&E->lock); |
2279 | error = rnd_lock_sources(); | | 2281 | error = rnd_lock_sources(ENTROPY_WAIT|ENTROPY_SIG); |
2280 | if (error) { | | 2282 | if (error) { |
2281 | mutex_exit(&E->lock); | | 2283 | mutex_exit(&E->lock); |
2282 | return error; | | 2284 | return error; |
2283 | } | | 2285 | } |
2284 | LIST_FOREACH(rs, &E->sources, list) { | | 2286 | LIST_FOREACH(rs, &E->sources, list) { |
2285 | if (strncmp(rs->name, nstat->name, n) == 0) | | 2287 | if (strncmp(rs->name, nstat->name, n) == 0) |
2286 | break; | | 2288 | break; |
2287 | } | | 2289 | } |
2288 | if (rs != NULL) { | | 2290 | if (rs != NULL) { |
2289 | mutex_exit(&E->lock); | | 2291 | mutex_exit(&E->lock); |
2290 | rndsource_to_user(rs, &nstat->source); | | 2292 | rndsource_to_user(rs, &nstat->source); |
2291 | mutex_enter(&E->lock); | | 2293 | mutex_enter(&E->lock); |
2292 | } else { | | 2294 | } else { |
| @@ -2297,27 +2299,27 @@ entropy_ioctl(unsigned long cmd, void *d | | | @@ -2297,27 +2299,27 @@ entropy_ioctl(unsigned long cmd, void *d |
2297 | break; | | 2299 | break; |
2298 | } | | 2300 | } |
2299 | case RNDGETESTNAME: { /* Get sources and estimates by name. */ | | 2301 | case RNDGETESTNAME: { /* Get sources and estimates by name. */ |
2300 | rndstat_est_name_t *enstat = data; | | 2302 | rndstat_est_name_t *enstat = data; |
2301 | const size_t n = sizeof(rs->name); | | 2303 | const size_t n = sizeof(rs->name); |
2302 | | | 2304 | |
2303 | CTASSERT(sizeof(rs->name) == sizeof(enstat->name)); | | 2305 | CTASSERT(sizeof(rs->name) == sizeof(enstat->name)); |
2304 | | | 2306 | |
2305 | /* | | 2307 | /* |
2306 | * Under the lock, search by name. If found, copy it | | 2308 | * Under the lock, search by name. If found, copy it |
2307 | * out; if not found, fail with ENOENT. | | 2309 | * out; if not found, fail with ENOENT. |
2308 | */ | | 2310 | */ |
2309 | mutex_enter(&E->lock); | | 2311 | mutex_enter(&E->lock); |
2310 | error = rnd_lock_sources(); | | 2312 | error = rnd_lock_sources(ENTROPY_WAIT|ENTROPY_SIG); |
2311 | if (error) { | | 2313 | if (error) { |
2312 | mutex_exit(&E->lock); | | 2314 | mutex_exit(&E->lock); |
2313 | return error; | | 2315 | return error; |
2314 | } | | 2316 | } |
2315 | LIST_FOREACH(rs, &E->sources, list) { | | 2317 | LIST_FOREACH(rs, &E->sources, list) { |
2316 | if (strncmp(rs->name, enstat->name, n) == 0) | | 2318 | if (strncmp(rs->name, enstat->name, n) == 0) |
2317 | break; | | 2319 | break; |
2318 | } | | 2320 | } |
2319 | if (rs != NULL) { | | 2321 | if (rs != NULL) { |
2320 | mutex_exit(&E->lock); | | 2322 | mutex_exit(&E->lock); |
2321 | rndsource_to_user_est(rs, &enstat->source); | | 2323 | rndsource_to_user_est(rs, &enstat->source); |
2322 | mutex_enter(&E->lock); | | 2324 | mutex_enter(&E->lock); |
2323 | } else { | | 2325 | } else { |
| @@ -2371,30 +2373,36 @@ entropy_ioctl(unsigned long cmd, void *d | | | @@ -2371,30 +2373,36 @@ entropy_ioctl(unsigned long cmd, void *d |
2371 | xc_broadcast(0, &entropy_reset_xc, NULL, NULL); | | 2373 | xc_broadcast(0, &entropy_reset_xc, NULL, NULL); |
2372 | mutex_enter(&E->lock); | | 2374 | mutex_enter(&E->lock); |
2373 | E->pending = 0; | | 2375 | E->pending = 0; |
2374 | atomic_store_relaxed(&E->needed, | | 2376 | atomic_store_relaxed(&E->needed, |
2375 | ENTROPY_CAPACITY*NBBY); | | 2377 | ENTROPY_CAPACITY*NBBY); |
2376 | mutex_exit(&E->lock); | | 2378 | mutex_exit(&E->lock); |
2377 | } | | 2379 | } |
2378 | | | 2380 | |
2379 | /* | | 2381 | /* |
2380 | * If we changed any of the estimation or collection | | 2382 | * If we changed any of the estimation or collection |
2381 | * flags, request new samples from everyone -- either | | 2383 | * flags, request new samples from everyone -- either |
2382 | * to make up for what we just lost, or to get new | | 2384 | * to make up for what we just lost, or to get new |
2383 | * samples from what we just added. | | 2385 | * samples from what we just added. |
| | | 2386 | * |
| | | 2387 | * Failing on signal, while waiting for another process |
| | | 2388 | * to finish requesting entropy, is OK here even though |
| | | 2389 | * we have committed side effects, because this ioctl |
| | | 2390 | * command is idempotent, so repeating it is safe. |
2384 | */ | | 2391 | */ |
2385 | if (request) { | | 2392 | if (request) { |
2386 | mutex_enter(&E->lock); | | 2393 | mutex_enter(&E->lock); |
2387 | entropy_request(ENTROPY_CAPACITY); | | 2394 | error = entropy_request(ENTROPY_CAPACITY, |
| | | 2395 | ENTROPY_WAIT|ENTROPY_SIG); |
2388 | mutex_exit(&E->lock); | | 2396 | mutex_exit(&E->lock); |
2389 | } | | 2397 | } |
2390 | break; | | 2398 | break; |
2391 | } | | 2399 | } |
2392 | case RNDADDDATA: { /* Enter seed into entropy pool. */ | | 2400 | case RNDADDDATA: { /* Enter seed into entropy pool. */ |
2393 | rnddata_t *rdata = data; | | 2401 | rnddata_t *rdata = data; |
2394 | unsigned entropybits = 0; | | 2402 | unsigned entropybits = 0; |
2395 | | | 2403 | |
2396 | if (!atomic_load_relaxed(&entropy_collection)) | | 2404 | if (!atomic_load_relaxed(&entropy_collection)) |
2397 | break; /* thanks but no thanks */ | | 2405 | break; /* thanks but no thanks */ |
2398 | if (rdata->len > MIN(sizeof(rdata->data), UINT32_MAX/NBBY)) | | 2406 | if (rdata->len > MIN(sizeof(rdata->data), UINT32_MAX/NBBY)) |
2399 | return EINVAL; | | 2407 | return EINVAL; |
2400 | | | 2408 | |