Login
Log in using an SSO provider:
Fedora Account System
Red Hat Associate
Red Hat Customer
Login using a Red Hat Bugzilla account
Forgot Password
Create an Account
Red Hat Bugzilla – Attachment 100157 Details for
Bug 117218
Entropy pool not updated (/dev/random blocks)
Home
New
Search
Simple Search
Advanced Search
My Links
Browse
Requests
Reports
Current State
Search
Tabular reports
Graphical reports
Duplicates
Other Reports
User Changes
Plotly Reports
Bug Status
Bug Severity
Non-Defaults
Product Dashboard
Help
Page Help!
Bug Writing Guidelines
What's new
Browser Support Policy
5.0.4.rh92 Release notes
FAQ
Guides index
User guide
Web Services
Contact
Legal
[?]
This site requires JavaScript to be enabled to function correctly, please enable it.
[patch]
/dev/random driver fixes committed in RHEL3 U3
random.patch (text/plain), 15.44 KB, created by
Ernie Petrides
on 2004-05-11 18:40:05 UTC
(
hide
)
Description:
/dev/random driver fixes committed in RHEL3 U3
Filename:
MIME Type:
Creator:
Ernie Petrides
Created:
2004-05-11 18:40:05 UTC
Size:
15.44 KB
patch
obsolete
>--- linux-2.4.21/drivers/char/random.c.orig >+++ linux-2.4.21/drivers/char/random.c >@@ -175,7 +175,7 @@ > * chmod 600 $random_seed > * poolfile=/proc/sys/kernel/random/poolsize > * [ -r $poolfile ] && bytes=`cat $poolfile` || bytes=512 >- * dd if=/dev/urandom of=$random_seed count=1 bs=bytes >+ * dd if=/dev/urandom of=$random_seed count=1 bs=$bytes > * > * and the following lines in an appropriate script which is run as > * the system is shutdown: >@@ -188,7 +188,7 @@ > * chmod 600 $random_seed > * poolfile=/proc/sys/kernel/random/poolsize > * [ -r $poolfile ] && bytes=`cat $poolfile` || bytes=512 >- * dd if=/dev/urandom of=$random_seed count=1 bs=bytes >+ * dd if=/dev/urandom of=$random_seed count=1 bs=$bytes > * > * For example, on most modern systems using the System V init > * scripts, such code fragments would be found in >@@ -269,9 +269,9 @@ > > /* > * The minimum number of bits of entropy before we wake up a read on >- * /dev/random. Should always be at least 8, or at least 1 byte. >+ * /dev/random. Should be enough to do a significant reseed. > */ >-static int random_read_wakeup_thresh = 8; >+static int random_read_wakeup_thresh = 64; > > /* > * If the entropy count falls under this number of bits, then we >@@ -483,9 +483,9 @@ struct entropy_store { > unsigned add_ptr; > int entropy_count; > int input_rotate; >- int extract_count; > struct poolinfo poolinfo; > __u32 *pool; >+ spinlock_t lock; > }; > > /* >@@ -524,6 +524,7 @@ static int create_entropy_store(int size > return -ENOMEM; > } > memset(r->pool, 0, POOLBYTES); >+ r->lock = SPIN_LOCK_UNLOCKED; > *ret_bucket = r; > return 0; > } >@@ -534,7 +535,6 @@ static void clear_entropy_store(struct e > r->add_ptr = 0; > r->entropy_count = 0; > r->input_rotate = 0; >- r->extract_count = 0; > memset(r->pool, 0, r->poolinfo.POOLBYTES); > } > >@@ -565,6 +565,9 @@ static void add_entropy_words(struct ent > int new_rotate; > int wordmask = r->poolinfo.poolwords - 1; > __u32 w; >+ unsigned long flags; >+ >+ spin_lock_irqsave(&r->lock, flags); > > while (nwords--) { > w = rotate_left(r->input_rotate, *in++); >@@ -589,6 +592,8 @@ static void add_entropy_words(struct ent > w ^= r->pool[i]; > r->pool[i] = (w >> 3) ^ twist_table[w & 7]; > } >+ >+ spin_unlock_irqrestore(&r->lock, flags); > } > > /* >@@ -596,6 +601,10 @@ static void add_entropy_words(struct ent > */ > static void credit_entropy_store(struct entropy_store *r, int nbits) > { >+ unsigned long flags; >+ >+ spin_lock_irqsave(&r->lock, flags); >+ > if (r->entropy_count + nbits < 0) { > DEBUG_ENT("negative entropy/overflow (%d+%d)\n", > r->entropy_count, nbits); >@@ -605,11 +614,15 @@ static void credit_entropy_store(struct > } else { > r->entropy_count += nbits; > if (nbits) >- DEBUG_ENT("%s added %d bits, now %d\n", >+ DEBUG_ENT("%04d %04d : added %d bits to %s\n", >+ random_state->entropy_count, >+ sec_random_state->entropy_count, >+ nbits, > r == sec_random_state ? "secondary" : >- r == random_state ? "primary" : "unknown", >- nbits, r->entropy_count); >+ r == random_state ? "primary" : "unknown"); > } >+ >+ spin_unlock_irqrestore(&r->lock, flags); > } > > /********************************************************************** >@@ -620,21 +633,27 @@ static void credit_entropy_store(struct > * > **********************************************************************/ > >-static __u32 *batch_entropy_pool; >-static int *batch_entropy_credit; >-static int batch_max; >+struct sample { >+ __u32 data[2]; >+ int credit; >+}; >+ >+static struct sample *batch_entropy_pool, *batch_entropy_copy; > static int batch_head, batch_tail; >+static spinlock_t batch_lock = SPIN_LOCK_UNLOCKED; >+ >+static int batch_max; > static struct tq_struct batch_tqueue; > static void batch_entropy_process(void *private_); > > /* note: the size must be a power of 2 */ > static int __init batch_entropy_init(int size, struct entropy_store *r) > { >- batch_entropy_pool = kmalloc(2*size*sizeof(__u32), GFP_KERNEL); >+ batch_entropy_pool = kmalloc(size*sizeof(struct sample), GFP_KERNEL); > if (!batch_entropy_pool) > return -1; >- batch_entropy_credit =kmalloc(size*sizeof(int), GFP_KERNEL); >- if (!batch_entropy_credit) { >+ batch_entropy_copy = kmalloc(size*sizeof(struct sample), GFP_KERNEL); >+ if (!batch_entropy_copy) { > kfree(batch_entropy_pool); > return -1; > } >@@ -654,21 +673,32 @@ static int __init batch_entropy_init(int > void batch_entropy_store(u32 a, u32 b, int num) > { > int new; >+ unsigned long flags; > > if (!batch_max) > return; > >- batch_entropy_pool[2*batch_head] = a; >- batch_entropy_pool[(2*batch_head) + 1] = b; >- batch_entropy_credit[batch_head] = num; >+ spin_lock_irqsave(&batch_lock, flags); > >- new = (batch_head+1) & (batch_max-1); >- if (new != batch_tail) { >+ batch_entropy_pool[batch_head].data[0] = a; >+ batch_entropy_pool[batch_head].data[1] = b; >+ batch_entropy_pool[batch_head].credit = num; >+ >+ if (((batch_head - batch_tail) & (batch_max-1)) >= (batch_max / 2)) { >+ /* >+ * Schedule it for the next timer tick: >+ */ > queue_task(&batch_tqueue, &tq_timer); >- batch_head = new; >- } else { >+ } >+ >+ new = (batch_head+1) & (batch_max-1); >+ if (new == batch_tail) { > DEBUG_ENT("batch entropy buffer full\n"); >+ } else { >+ batch_head = new; > } >+ >+ spin_unlock_irqrestore(&batch_lock, flags); > } > > /* >@@ -680,20 +710,34 @@ static void batch_entropy_process(void * > { > struct entropy_store *r = (struct entropy_store *) private_, *p; > int max_entropy = r->poolinfo.POOLBITS; >+ unsigned head, tail; > >- if (!batch_max) >- return; >+ /* Mixing into the pool is expensive, so copy over the batch >+ * data and release the batch lock. The pool is at least half >+ * full, so don't worry too much about copying only the used >+ * part. >+ */ >+ spin_lock_irq(&batch_lock); >+ >+ memcpy(batch_entropy_copy, batch_entropy_pool, >+ batch_max*sizeof(struct sample)); >+ >+ head = batch_head; >+ tail = batch_tail; >+ batch_tail = batch_head; >+ >+ spin_unlock_irq(&batch_lock); > > p = r; >- while (batch_head != batch_tail) { >+ while (head != tail) { > if (r->entropy_count >= max_entropy) { > r = (r == sec_random_state) ? random_state : > sec_random_state; > max_entropy = r->poolinfo.POOLBITS; > } >- add_entropy_words(r, batch_entropy_pool + 2*batch_tail, 2); >- credit_entropy_store(r, batch_entropy_credit[batch_tail]); >- batch_tail = (batch_tail+1) & (batch_max-1); >+ add_entropy_words(r, batch_entropy_copy[tail].data, 2); >+ credit_entropy_store(r, batch_entropy_copy[tail].credit); >+ tail = (tail+1) & (batch_max-1); > } > if (p->entropy_count >= random_read_wakeup_thresh) > wake_up_interruptible(&random_read_wait); >@@ -736,7 +780,7 @@ static void add_timer_randomness(struct > __s32 delta, delta2, delta3; > int entropy = 0; > >-#if defined (__i386__) >+#if defined (__i386__) || defined (__x86_64__) > if (cpu_has_tsc) { > __u32 high; > rdtsc(time, high); >@@ -744,10 +788,8 @@ static void add_timer_randomness(struct > } else { > time = jiffies; > } >-#elif defined (__x86_64__) >- __u32 high; >- rdtsc(time, high); >- num ^= high; >+#elif defined (__powerpc64__) >+ time = mftb(); > #else > time = jiffies; > #endif >@@ -1223,6 +1265,7 @@ static void MD5Transform(__u32 buf[HASH_ > > #define EXTRACT_ENTROPY_USER 1 > #define EXTRACT_ENTROPY_SECONDARY 2 >+#define EXTRACT_ENTROPY_LIMIT 4 > #define TMP_BUF_SIZE (HASH_BUFFER_SIZE + HASH_EXTRA_SIZE) > #define SEC_XFER_SIZE (TMP_BUF_SIZE*4) > >@@ -1231,36 +1274,28 @@ static ssize_t extract_entropy(struct en > > /* > * This utility inline function is responsible for transfering entropy >- * from the primary pool to the secondary extraction pool. We pull >- * randomness under two conditions; one is if there isn't enough entropy >- * in the secondary pool. The other is after we have extracted 1024 bytes, >- * at which point we do a "catastrophic reseeding". >+ * from the primary pool to the secondary extraction pool. We make >+ * sure we pull enough for a 'catastrophic reseed'. > */ > static inline void xfer_secondary_pool(struct entropy_store *r, > size_t nbytes, __u32 *tmp) > { > if (r->entropy_count < nbytes * 8 && > r->entropy_count < r->poolinfo.POOLBITS) { >- int nwords = min_t(int, >- r->poolinfo.poolwords - r->entropy_count/32, >- sizeof(tmp) / 4); >+ int bytes = max_t(int, random_read_wakeup_thresh / 8, >+ min_t(int, nbytes, TMP_BUF_SIZE)); > >- DEBUG_ENT("xfer %d from primary to %s (have %d, need %d)\n", >- nwords * 32, >+ DEBUG_ENT("%04d %04d : going to reseed %s with %d bits " >+ "(%d of %d requested)\n", >+ random_state->entropy_count, >+ sec_random_state->entropy_count, > r == sec_random_state ? "secondary" : "unknown", >- r->entropy_count, nbytes * 8); >+ bytes * 8, nbytes * 8, r->entropy_count); > >- extract_entropy(random_state, tmp, nwords * 4, 0); >- add_entropy_words(r, tmp, nwords); >- credit_entropy_store(r, nwords * 32); >- } >- if (r->extract_count > 1024) { >- DEBUG_ENT("reseeding %s with %d from primary\n", >- r == sec_random_state ? "secondary" : "unknown", >- sizeof(tmp) * 8); >- extract_entropy(random_state, tmp, sizeof(tmp), 0); >- add_entropy_words(r, tmp, sizeof(tmp) / 4); >- r->extract_count = 0; >+ bytes=extract_entropy(random_state, tmp, bytes, >+ EXTRACT_ENTROPY_LIMIT); >+ add_entropy_words(r, tmp, bytes); >+ credit_entropy_store(r, bytes*8); > } > } > >@@ -1283,8 +1318,7 @@ static ssize_t extract_entropy(struct en > ssize_t ret, i; > __u32 tmp[TMP_BUF_SIZE]; > __u32 x; >- >- add_timer_randomness(&extract_timer_state, nbytes); >+ unsigned long cpuflags; > > /* Redundant, but just in case... */ > if (r->entropy_count > r->poolinfo.POOLBITS) >@@ -1293,10 +1327,18 @@ static ssize_t extract_entropy(struct en > if (flags & EXTRACT_ENTROPY_SECONDARY) > xfer_secondary_pool(r, nbytes, tmp); > >- DEBUG_ENT("%s has %d bits, want %d bits\n", >+ /* Hold lock while accounting */ >+ spin_lock_irqsave(&r->lock, cpuflags); >+ >+ DEBUG_ENT("%04d %04d : trying to extract %d bits from %s\n", >+ random_state->entropy_count, >+ sec_random_state->entropy_count, >+ nbytes * 8, > r == sec_random_state ? "secondary" : >- r == random_state ? "primary" : "unknown", >- r->entropy_count, nbytes * 8); >+ r == random_state ? "primary" : "unknown"); >+ >+ if (flags & EXTRACT_ENTROPY_LIMIT && nbytes >= r->entropy_count / 8) >+ nbytes = r->entropy_count / 8; > > if (r->entropy_count / 8 >= nbytes) > r->entropy_count -= nbytes*8; >@@ -1306,20 +1348,36 @@ static ssize_t extract_entropy(struct en > if (r->entropy_count < random_write_wakeup_thresh) > wake_up_interruptible(&random_write_wait); > >- r->extract_count += nbytes; >- >+ DEBUG_ENT("%04d %04d : debiting %d bits from %s%s\n", >+ random_state->entropy_count, >+ sec_random_state->entropy_count, >+ nbytes * 8, >+ r == sec_random_state ? "secondary" : >+ r == random_state ? "primary" : "unknown", >+ flags & EXTRACT_ENTROPY_LIMIT ? "" : " (unlimited)"); >+ >+ spin_unlock_irqrestore(&r->lock, cpuflags); >+ > ret = 0; > while (nbytes) { > /* > * Check if we need to break out or reschedule.... > */ >- if ((flags & EXTRACT_ENTROPY_USER) && current->need_resched) { >+ if ((flags & EXTRACT_ENTROPY_USER) && need_resched()) { > if (signal_pending(current)) { > if (ret == 0) > ret = -ERESTARTSYS; > break; > } >+ DEBUG_ENT("%04d %04d : extract feeling sleepy (%d bytes left)\n", >+ random_state->entropy_count, >+ sec_random_state->entropy_count, nbytes); >+ > schedule(); >+ >+ DEBUG_ENT("%04d %04d : extract woke up\n", >+ random_state->entropy_count, >+ sec_random_state->entropy_count); > } > > /* Hash the pool to get the output */ >@@ -1368,7 +1426,6 @@ static ssize_t extract_entropy(struct en > nbytes -= i; > buf += i; > ret += i; >- add_timer_randomness(&extract_timer_state, nbytes); > } > > /* Wipe data just returned from memory */ >@@ -1447,8 +1504,7 @@ void __init rand_initialize(void) > #endif > for (i = 0; i < NR_IRQS; i++) > irq_timer_state[i] = NULL; >- for (i = 0; i < MAX_BLKDEV; i++) >- blkdev_timer_state[i] = NULL; >+ > memset(&keyboard_timer_state, 0, sizeof(struct timer_rand_state)); > memset(&mouse_timer_state, 0, sizeof(struct timer_rand_state)); > memset(&extract_timer_state, 0, sizeof(struct timer_rand_state)); >@@ -1501,15 +1557,27 @@ random_read(struct file * file, char * b > if (nbytes == 0) > return 0; > >- add_wait_queue(&random_read_wait, &wait); > while (nbytes > 0) { >- set_current_state(TASK_INTERRUPTIBLE); >- > n = nbytes; > if (n > SEC_XFER_SIZE) > n = SEC_XFER_SIZE; >- if (n > random_state->entropy_count / 8) >- n = random_state->entropy_count / 8; >+ >+ DEBUG_ENT("%04d %04d : reading %d bits, p: %d s: %d\n", >+ random_state->entropy_count, >+ sec_random_state->entropy_count, >+ n*8, random_state->entropy_count, >+ sec_random_state->entropy_count); >+ >+ n = extract_entropy(sec_random_state, buf, n, >+ EXTRACT_ENTROPY_USER | >+ EXTRACT_ENTROPY_LIMIT | >+ EXTRACT_ENTROPY_SECONDARY); >+ >+ DEBUG_ENT("%04d %04d : read got %d bits (%d still needed)\n", >+ random_state->entropy_count, >+ sec_random_state->entropy_count, >+ n*8, (nbytes-n)*8); >+ > if (n == 0) { > if (file->f_flags & O_NONBLOCK) { > retval = -EAGAIN; >@@ -1519,12 +1587,27 @@ random_read(struct file * file, char * b > retval = -ERESTARTSYS; > break; > } >- schedule(); >+ >+ DEBUG_ENT("%04d %04d : sleeping?\n", >+ random_state->entropy_count, >+ sec_random_state->entropy_count); >+ >+ set_current_state(TASK_INTERRUPTIBLE); >+ add_wait_queue(&random_read_wait, &wait); >+ >+ if (sec_random_state->entropy_count / 8 == 0) >+ schedule(); >+ >+ set_current_state(TASK_RUNNING); >+ remove_wait_queue(&random_read_wait, &wait); >+ >+ DEBUG_ENT("%04d %04d : waking up\n", >+ random_state->entropy_count, >+ sec_random_state->entropy_count); >+ > continue; > } >- n = extract_entropy(sec_random_state, buf, n, >- EXTRACT_ENTROPY_USER | >- EXTRACT_ENTROPY_SECONDARY); >+ > if (n < 0) { > retval = n; > break; >@@ -1535,15 +1618,12 @@ random_read(struct file * file, char * b > break; /* This break makes the device work */ > /* like a named pipe */ > } >- current->state = TASK_RUNNING; >- remove_wait_queue(&random_read_wait, &wait); > > /* > * If we gave the user some bytes, update the access time. > */ >- if (count != 0) { >+ if (count) > UPDATE_ATIME(file->f_dentry->d_inode); >- } > > return (count ? count : retval); > } >@@ -1608,8 +1688,9 @@ static int > random_ioctl(struct inode * inode, struct file * file, > unsigned int cmd, unsigned long arg) > { >- int *p, size, ent_count; >+ int *p, *tmp, size, ent_count; > int retval; >+ unsigned long flags; > > switch (cmd) { > case RNDGETENTCNT: >@@ -1634,17 +1715,36 @@ random_ioctl(struct inode * inode, struc > if (!capable(CAP_SYS_ADMIN)) > return -EPERM; > p = (int *) arg; >- ent_count = random_state->entropy_count; >- if (put_user(ent_count, p++) || >- get_user(size, p) || >+ if (get_user(size, p) || > put_user(random_state->poolinfo.poolwords, p++)) > return -EFAULT; > if (size < 0) >- return -EINVAL; >+ return -EFAULT; > if (size > random_state->poolinfo.poolwords) > size = random_state->poolinfo.poolwords; >- if (copy_to_user(p, random_state->pool, size * sizeof(__u32))) >+ >+ /* prepare to atomically snapshot pool */ >+ >+ tmp = kmalloc(size * sizeof(__u32), GFP_KERNEL); >+ >+ if (!tmp) >+ return -ENOMEM; >+ >+ spin_lock_irqsave(&random_state->lock, flags); >+ ent_count = random_state->entropy_count; >+ memcpy(tmp, random_state->pool, size * sizeof(__u32)); >+ spin_unlock_irqrestore(&random_state->lock, flags); >+ >+ if (!copy_to_user(p, tmp, size * sizeof(__u32))) { >+ kfree(tmp); > return -EFAULT; >+ } >+ >+ kfree(tmp); >+ >+ if(put_user(ent_count, p++)) >+ return -EFAULT; >+ > return 0; > case RNDADDENTROPY: > if (!capable(CAP_SYS_ADMIN))
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 117218
: 100157