Sun Mar 20 14:30:57 2022 UTC ()
entropy(9): Fix premature optimization deadlock in entropy_request.

- For synchronous queries from /dev/random, which are waiting for
  entropy to be ready, wait for concurrent access -- e.g., concurrent
  rnd_detach_source -- to finish, and make sure to request entropy
  from all sources (unless we're interrupted by a signal).

- When invoked through softint context (e.g., cprng_fast_intr ->
  cprng_strong -> entropy_extract), don't wait, because we're
  forbidden from waiting anyway.

- For entropy_bootrequest, wait but don't bother failing on signal
  because this only happens in kthread context, not in userland
  process context, so there can't be signals.

Nix rnd_trylock_sources; use the same entropy_extract flags
(ENTROPY_WAIT, ENTROPY_SIG) for rnd_lock_sources.


(riastradh)
diff -r1.48 -r1.49 src/sys/kern/kern_entropy.c

cvs diff -r1.48 -r1.49 src/sys/kern/kern_entropy.c (expand / switch to unified diff)

--- src/sys/kern/kern_entropy.c 2022/03/20 14:05:41 1.48
+++ src/sys/kern/kern_entropy.c 2022/03/20 14:30:56 1.49
@@ -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
250static void entropy_enter(const void *, size_t, unsigned); 250static void entropy_enter(const void *, size_t, unsigned);
251static bool entropy_enter_intr(const void *, size_t, unsigned); 251static bool entropy_enter_intr(const void *, size_t, unsigned);
252static void entropy_softintr(void *); 252static void entropy_softintr(void *);
253static void entropy_thread(void *); 253static void entropy_thread(void *);
254static uint32_t entropy_pending(void); 254static uint32_t entropy_pending(void);
255static void entropy_pending_cpu(void *, void *, struct cpu_info *); 255static void entropy_pending_cpu(void *, void *, struct cpu_info *);
256static void entropy_do_consolidate(void); 256static void entropy_do_consolidate(void);
257static void entropy_consolidate_xc(void *, void *); 257static void entropy_consolidate_xc(void *, void *);
258static void entropy_notify(void); 258static void entropy_notify(void);
259static int sysctl_entropy_consolidate(SYSCTLFN_ARGS); 259static int sysctl_entropy_consolidate(SYSCTLFN_ARGS);
260static int sysctl_entropy_gather(SYSCTLFN_ARGS); 260static int sysctl_entropy_gather(SYSCTLFN_ARGS);
261static void filt_entropy_read_detach(struct knote *); 261static void filt_entropy_read_detach(struct knote *);
262static int filt_entropy_read_event(struct knote *, long); 262static int filt_entropy_read_event(struct knote *, long);
263static void entropy_request(size_t); 263static int entropy_request(size_t, int);
264static void rnd_add_data_1(struct krndsource *, const void *, uint32_t, 264static void rnd_add_data_1(struct krndsource *, const void *, uint32_t,
265 uint32_t, uint32_t); 265 uint32_t, uint32_t);
266static unsigned rndsource_entropybits(struct krndsource *); 266static unsigned rndsource_entropybits(struct krndsource *);
267static void rndsource_entropybits_cpu(void *, void *, struct cpu_info *); 267static void rndsource_entropybits_cpu(void *, void *, struct cpu_info *);
268static void rndsource_to_user(struct krndsource *, rndsource_t *); 268static void rndsource_to_user(struct krndsource *, rndsource_t *);
269static void rndsource_to_user_est(struct krndsource *, rndsource_est_t *); 269static void rndsource_to_user_est(struct krndsource *, rndsource_est_t *);
270static void rndsource_to_user_est_cpu(void *, void *, struct cpu_info *); 270static 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 */
648void 648void
649entropy_bootrequest(void) 649entropy_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 */
1687static int 1695static int __attribute__((warn_unused_result))
1688rnd_lock_sources(void) 1696rnd_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 */ 
1712static bool 
1713rnd_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 */
1730static void 1724static void
1731rnd_unlock_sources(void) 1725rnd_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 */
1749static bool __diagused 1743static bool __diagused
1750rnd_sources_locked(void) 1744rnd_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 */
1763static void 1760static int
1764entropy_request(size_t nbytes) 1761entropy_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 */
1817void 1819void
@@ -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