Index: nss/lib/freebl/unix_rand.c |
=================================================================== |
--- nss/lib/freebl/unix_rand.c (revision 239365) |
+++ nss/lib/freebl/unix_rand.c (working copy) |
@@ -970,7 +970,8 @@ |
size_t RNG_FileUpdate(const char *fileName, size_t limit) |
{ |
FILE * file; |
- size_t bytes; |
+ int fd; |
+ int bytes; |
size_t fileBytes = 0; |
struct stat stat_buf; |
unsigned char buffer[BUFSIZ]; |
@@ -983,12 +984,22 @@ |
return fileBytes; |
RNG_RandomUpdate(&stat_buf, sizeof(stat_buf)); |
- file = fopen((char *)fileName, "r"); |
+ file = fopen(fileName, "r"); |
if (file != NULL) { |
+ /* Read from the underlying file descriptor directly to bypass stdio |
+ * buffering and avoid reading more bytes than we need from |
+ * /dev/urandom. NOTE: we can't use fread with unbuffered I/O because |
+ * fread may return EOF in unbuffered I/O mode on Android. |
+ * |
+ * Moreover, we read into a buffer of size BUFSIZ, so buffered I/O |
+ * has no performance advantage. */ |
+ fd = fileno(file); |
+ /* 'file' was just opened, so this should not fail. */ |
+ PORT_Assert(fd != -1); |
while (limit > fileBytes) { |
bytes = PR_MIN(sizeof buffer, limit - fileBytes); |
- bytes = fread(buffer, 1, bytes, file); |
- if (bytes == 0) |
+ bytes = read(fd, buffer, bytes); |
+ if (bytes <= 0) |
break; |
RNG_RandomUpdate(buffer, bytes); |
fileBytes += bytes; |
@@ -1020,7 +1031,7 @@ |
FILE * file; |
unsigned char buffer[BUFSIZ]; |
- file = fopen((char *)fileName, "rb"); |
+ file = fopen(fileName, "rb"); |
if (file != NULL) { |
while (fread(buffer, 1, sizeof(buffer), file) > 0) |
; |
@@ -1142,7 +1153,8 @@ |
size_t RNG_SystemRNG(void *dest, size_t maxLen) |
{ |
FILE *file; |
- size_t bytes; |
+ int fd; |
+ int bytes; |
size_t fileBytes = 0; |
unsigned char *buffer = dest; |
@@ -1153,10 +1165,18 @@ |
fflush(stderr); |
abort(); |
} |
+ /* Read from the underlying file descriptor directly to bypass stdio |
+ * buffering and avoid reading more bytes than we need from /dev/urandom. |
+ * NOTE: we can't use fread with unbuffered I/O because fread may return |
+ * EOF in unbuffered I/O mode on Android. |
+ */ |
+ fd = fileno(file); |
+ /* 'file' was just opened, so this should not fail. */ |
+ PORT_Assert(fd != -1); |
while (maxLen > fileBytes) { |
bytes = maxLen - fileBytes; |
- bytes = fread(buffer, 1, bytes, file); |
- if (bytes == 0) |
+ bytes = read(fd, buffer, bytes); |
+ if (bytes <= 0) |
break; |
fileBytes += bytes; |
buffer += bytes; |