| From 7f397dcdb78d699a20d96bfcfb595a2411a5bbd2 Mon Sep 17 00:00:00 2001 |
| From: Matt Mackall <mpm@selenic.com> |
| Date: Tue, 29 May 2007 21:58:10 -0500 |
| Subject: random: fix seeding with zero entropy (CVE-2007-2453 2 of 2) |
| |
| Add data from zero-entropy random_writes directly to output pools to |
| avoid accounting difficulties on machines without entropy sources. |
| |
| Tested on lguest with all entropy sources disabled. |
| |
| Signed-off-by: Matt Mackall <mpm@selenic.com> |
| Acked-by: "Theodore Ts'o" <tytso@mit.edu> |
| Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> |
| Signed-off-by: Chris Wright <chrisw@sous-sol.org> |
| --- |
| drivers/char/random.c | 55 ++++++++++++++++++++++++++++---------------------- |
| 1 file changed, 31 insertions(+), 24 deletions(-) |
| |
| --- linux-2.6.21.3.orig/drivers/char/random.c |
| +++ linux-2.6.21.3/drivers/char/random.c |
| @@ -1024,37 +1024,44 @@ random_poll(struct file *file, poll_tabl |
| return mask; |
| } |
| |
| -static ssize_t |
| -random_write(struct file * file, const char __user * buffer, |
| - size_t count, loff_t *ppos) |
| +static int |
| +write_pool(struct entropy_store *r, const char __user *buffer, size_t count) |
| { |
| - int ret = 0; |
| size_t bytes; |
| __u32 buf[16]; |
| const char __user *p = buffer; |
| - size_t c = count; |
| |
| - while (c > 0) { |
| - bytes = min(c, sizeof(buf)); |
| + while (count > 0) { |
| + bytes = min(count, sizeof(buf)); |
| + if (copy_from_user(&buf, p, bytes)) |
| + return -EFAULT; |
| |
| - bytes -= copy_from_user(&buf, p, bytes); |
| - if (!bytes) { |
| - ret = -EFAULT; |
| - break; |
| - } |
| - c -= bytes; |
| + count -= bytes; |
| p += bytes; |
| |
| - add_entropy_words(&input_pool, buf, (bytes + 3) / 4); |
| - } |
| - if (p == buffer) { |
| - return (ssize_t)ret; |
| - } else { |
| - struct inode *inode = file->f_path.dentry->d_inode; |
| - inode->i_mtime = current_fs_time(inode->i_sb); |
| - mark_inode_dirty(inode); |
| - return (ssize_t)(p - buffer); |
| + add_entropy_words(r, buf, (bytes + 3) / 4); |
| } |
| + |
| + return 0; |
| +} |
| + |
| +static ssize_t |
| +random_write(struct file * file, const char __user * buffer, |
| + size_t count, loff_t *ppos) |
| +{ |
| + size_t ret; |
| + struct inode *inode = file->f_path.dentry->d_inode; |
| + |
| + ret = write_pool(&blocking_pool, buffer, count); |
| + if (ret) |
| + return ret; |
| + ret = write_pool(&nonblocking_pool, buffer, count); |
| + if (ret) |
| + return ret; |
| + |
| + inode->i_mtime = current_fs_time(inode->i_sb); |
| + mark_inode_dirty(inode); |
| + return (ssize_t)count; |
| } |
| |
| static int |
| @@ -1093,8 +1100,8 @@ random_ioctl(struct inode * inode, struc |
| return -EINVAL; |
| if (get_user(size, p++)) |
| return -EFAULT; |
| - retval = random_write(file, (const char __user *) p, |
| - size, &file->f_pos); |
| + retval = write_pool(&input_pool, (const char __user *)p, |
| + size); |
| if (retval < 0) |
| return retval; |
| credit_entropy_store(&input_pool, ent_count); |