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>

authored by Matt Mackall and committed by Linus Torvalds 7f397dcd 602b6aee

+34 -27
+34 -27
drivers/char/random.c
··· 1020 1020 return mask; 1021 1021 } 1022 1022 1023 + static int 1024 + write_pool(struct entropy_store *r, const char __user *buffer, size_t count) 1025 + { 1026 + size_t bytes; 1027 + __u32 buf[16]; 1028 + const char __user *p = buffer; 1029 + 1030 + while (count > 0) { 1031 + bytes = min(count, sizeof(buf)); 1032 + if (copy_from_user(&buf, p, bytes)) 1033 + return -EFAULT; 1034 + 1035 + count -= bytes; 1036 + p += bytes; 1037 + 1038 + add_entropy_words(r, buf, (bytes + 3) / 4); 1039 + } 1040 + 1041 + return 0; 1042 + } 1043 + 1023 1044 static ssize_t 1024 1045 random_write(struct file * file, const char __user * buffer, 1025 1046 size_t count, loff_t *ppos) 1026 1047 { 1027 - int ret = 0; 1028 - size_t bytes; 1029 - __u32 buf[16]; 1030 - const char __user *p = buffer; 1031 - size_t c = count; 1048 + size_t ret; 1049 + struct inode *inode = file->f_path.dentry->d_inode; 1032 1050 1033 - while (c > 0) { 1034 - bytes = min(c, sizeof(buf)); 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; 1035 1057 1036 - bytes -= copy_from_user(&buf, p, bytes); 1037 - if (!bytes) { 1038 - ret = -EFAULT; 1039 - break; 1040 - } 1041 - c -= bytes; 1042 - p += bytes; 1043 - 1044 - add_entropy_words(&input_pool, 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 - } 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 1063 static int ··· 1096 1089 return -EINVAL; 1097 1090 if (get_user(size, p++)) 1098 1091 return -EFAULT; 1099 - retval = random_write(file, (const char __user *) p, 1100 - size, &file->f_pos); 1092 + retval = write_pool(&input_pool, (const char __user *)p, 1093 + size); 1101 1094 if (retval < 0) 1102 1095 return retval; 1103 1096 credit_entropy_store(&input_pool, ent_count);