diff options
author | Matt Mackall <mpm@selenic.com> | 2007-05-29 22:58:10 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-05-29 23:09:34 -0400 |
commit | 7f397dcdb78d699a20d96bfcfb595a2411a5bbd2 (patch) | |
tree | 7ecb0b2f782a4e18eef80ff638f0469cd4ad0233 | |
parent | 602b6aeefe8932dd8bb15014e8fe6bb25d736361 (diff) |
random: fix seeding with zero entropy
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>
-rw-r--r-- | drivers/char/random.c | 55 |
1 files changed, 31 insertions, 24 deletions
diff --git a/drivers/char/random.c b/drivers/char/random.c index 9705b439448a..0474cac4a84e 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c | |||
@@ -1020,37 +1020,44 @@ random_poll(struct file *file, poll_table * wait) | |||
1020 | return mask; | 1020 | return mask; |
1021 | } | 1021 | } |
1022 | 1022 | ||
1023 | static ssize_t | 1023 | static int |
1024 | random_write(struct file * file, const char __user * buffer, | 1024 | write_pool(struct entropy_store *r, const char __user *buffer, size_t count) |
1025 | size_t count, loff_t *ppos) | ||
1026 | { | 1025 | { |
1027 | int ret = 0; | ||
1028 | size_t bytes; | 1026 | size_t bytes; |
1029 | __u32 buf[16]; | 1027 | __u32 buf[16]; |
1030 | const char __user *p = buffer; | 1028 | const char __user *p = buffer; |
1031 | size_t c = count; | ||
1032 | 1029 | ||
1033 | while (c > 0) { | 1030 | while (count > 0) { |
1034 | bytes = min(c, sizeof(buf)); | 1031 | bytes = min(count, sizeof(buf)); |
1032 | if (copy_from_user(&buf, p, bytes)) | ||
1033 | return -EFAULT; | ||
1035 | 1034 | ||
1036 | bytes -= copy_from_user(&buf, p, bytes); | 1035 | count -= bytes; |
1037 | if (!bytes) { | ||
1038 | ret = -EFAULT; | ||
1039 | break; | ||
1040 | } | ||
1041 | c -= bytes; | ||
1042 | p += bytes; | 1036 | p += bytes; |
1043 | 1037 | ||
1044 | add_entropy_words(&input_pool, buf, (bytes + 3) / 4); | 1038 | add_entropy_words(r, buf, (bytes + 3) / 4); |
1045 | } | ||
1046 | if (p == buffer) { | ||
1047 | return (ssize_t)ret; | ||
1048 | } else { | ||
1049 | struct inode *inode = file->f_path.dentry->d_inode; | ||
1050 | inode->i_mtime = current_fs_time(inode->i_sb); | ||
1051 | mark_inode_dirty(inode); | ||
1052 | return (ssize_t)(p - buffer); | ||
1053 | } | 1039 | } |
1040 | |||
1041 | return 0; | ||
1042 | } | ||
1043 | |||
1044 | static ssize_t | ||
1045 | random_write(struct file * file, const char __user * buffer, | ||
1046 | size_t count, loff_t *ppos) | ||
1047 | { | ||
1048 | size_t ret; | ||
1049 | struct inode *inode = file->f_path.dentry->d_inode; | ||
1050 | |||
1051 | ret = write_pool(&blocking_pool, buffer, count); | ||
1052 | if (ret) | ||
1053 | return ret; | ||
1054 | ret = write_pool(&nonblocking_pool, buffer, count); | ||
1055 | if (ret) | ||
1056 | return ret; | ||
1057 | |||
1058 | inode->i_mtime = current_fs_time(inode->i_sb); | ||
1059 | mark_inode_dirty(inode); | ||
1060 | return (ssize_t)count; | ||
1054 | } | 1061 | } |
1055 | 1062 | ||
1056 | static int | 1063 | static int |
@@ -1089,8 +1096,8 @@ random_ioctl(struct inode * inode, struct file * file, | |||
1089 | return -EINVAL; | 1096 | return -EINVAL; |
1090 | if (get_user(size, p++)) | 1097 | if (get_user(size, p++)) |
1091 | return -EFAULT; | 1098 | return -EFAULT; |
1092 | retval = random_write(file, (const char __user *) p, | 1099 | retval = write_pool(&input_pool, (const char __user *)p, |
1093 | size, &file->f_pos); | 1100 | size); |
1094 | if (retval < 0) | 1101 | if (retval < 0) |
1095 | return retval; | 1102 | return retval; |
1096 | credit_entropy_store(&input_pool, ent_count); | 1103 | credit_entropy_store(&input_pool, ent_count); |