diff options
author | mame <mame@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2017-12-16 00:39:34 +0000 |
---|---|---|
committer | mame <mame@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2017-12-16 00:39:34 +0000 |
commit | 0c2f92daad93c57af1720e3cbafcdcae9bd0cd62 (patch) | |
tree | 4cebeba621f926fb79d28983aa0a7ac981889fa3 /random.c | |
parent | d2333dd92c3076e3d86e5ceff91069a56dcfa8a4 (diff) |
random.c: make sure that Random.urandom returns required-length buffer
getrandom(2) and read(2) (from /dev/urandom) may return a random buffer
whose length is shorter than required. This change makes sure that they
get enough buffer by using a loop.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@61292 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'random.c')
-rw-r--r-- | random.c | 29 |
1 files changed, 20 insertions, 9 deletions
@@ -447,14 +447,21 @@ fill_random_bytes_urandom(void *seed, size_t size) O_RDONLY, 0); struct stat statbuf; ssize_t ret = 0; + size_t offset = 0; if (fd < 0) return -1; rb_update_max_fd(fd); if (fstat(fd, &statbuf) == 0 && S_ISCHR(statbuf.st_mode)) { - ret = read(fd, seed, size); + do { + ret = read(fd, ((char*)seed) + offset, size - offset); + if (ret < 0) { + close(fd); + return -1; + } + offset += (size_t)ret; + } while(offset < size); } close(fd); - if (ret < 0 || (size_t)ret < size) return -1; return 0; } #else @@ -518,16 +525,20 @@ fill_random_bytes_syscall(void *seed, size_t size, int need_secure) static rb_atomic_t try_syscall = 1; if (try_syscall) { long ret; + size_t offset = 0; int flags = 0; if (!need_secure) flags = GRND_NONBLOCK; - errno = 0; - ret = syscall(__NR_getrandom, seed, size, flags); - if (errno == ENOSYS) { - ATOMIC_SET(try_syscall, 0); - return -1; - } - if ((size_t)ret == size) return 0; + do { + errno = 0; + ret = syscall(__NR_getrandom, ((char*)seed) + offset, size - offset, flags); + if (ret == -1) { + ATOMIC_SET(try_syscall, 0); + return -1; + } + offset += (size_t)ret; + } while(offset < size); + return 0; } return -1; } |