On Tue, Nov 29, 2022 at 4:24 PM Sergey Bugaev <buga...@gmail.com> wrote: > Well, here's a preliminary patch. Please don't expect it to be any > good, I must have forgotten all the subtleties of glibc development — > those that I managed to learn in the first place — over the year. That > being said, it builds; I haven't tested whether it works.
...and I already see some of the brokenness. Here's a slightly better version: --------------------------- >8 ------------------------------ diff --git a/sysdeps/mach/hurd/getrandom.c b/sysdeps/mach/hurd/getrandom.c index ad2d3ba3..44bf1e8f 100644 --- a/sysdeps/mach/hurd/getrandom.c +++ b/sysdeps/mach/hurd/getrandom.c @@ -16,22 +16,65 @@ License along with the GNU C Library; if not, see <https://www.gnu.org/licenses/>. */ +#include <hurd.h> #include <sys/random.h> #include <fcntl.h> -#include <unistd.h> -#include <not-cancel.h> + +__libc_rwlock_define_initialized (static, lock); +static file_t random_server; extern char *__trivfs_server_name __attribute__((weak)); +static file_t +get_random_server (int dead) +{ + file_t server; + int flags; + + if (!dead) + { + /* Attempt to use the cached port, if any. */ + __libc_rwlock_rdlock (lock); + server = random_server; + if (MACH_PORT_VALID (server)) + goto out; + + __libc_rwlock_unlock (lock); + } + + __libc_rwlock_wrlock (lock); + + server = random_server; + if (MACH_PORT_VALID (server)) + if (!dead) + /* Someone else has obtained a new port while we were + waiting for the lock. */ + goto out; + else + __mach_port_deallocate (__mach_task_self (), server); + + flags = O_RDONLY | O_NOCTTY; + /* TODO: O_NONBLOCK? */ + server = random_server = __file_name_lookup ("/dev/urandom", flags, 0); + +out: + __libc_rwlock_unlock (lock); + + if (server == MACH_PORT_DEAD) + server = MACH_PORT_NULL; + return server; +} + /* Write up to LENGTH bytes of randomness starting at BUFFER. Return the number of bytes written, or -1 on error. */ ssize_t __getrandom (void *buffer, size_t length, unsigned int flags) { - const char *random_source = "/dev/urandom"; - int open_flags = O_RDONLY | O_CLOEXEC; - size_t amount_read; - int fd; + file_t server; + error_t err; + int dead = 0; + char *data = buffer; + mach_msg_type_number_t nread = length; if (&__trivfs_server_name && __trivfs_server_name && __trivfs_server_name[0] == 'r' @@ -44,19 +87,33 @@ __getrandom (void *buffer, size_t length, unsigned int flags) /* We are random, don't try to read ourselves! */ return length; - if (flags & GRND_RANDOM) - random_source = "/dev/random"; +again: + server = get_random_server (dead); + if (!MACH_PORT_VALID (server)) + return -1; - if (flags & GRND_NONBLOCK) - open_flags |= O_NONBLOCK; + err = __io_read (server, &data, &nread, -1, length); + if (!dead && (err == MACH_SEND_INVALID_DEST || err == MIG_SERVER_DIED)) + { + dead = 1; + goto again; + } - fd = __open_nocancel(random_source, open_flags); - if (fd == -1) - return -1; + if (err) + return __hurd_fail (err); + + if (data != buffer) + { + if (nread > length) + { + __vm_deallocate (__mach_task_self (), (vm_address_t) data, nread); + return __hurd_fail (EGRATUITOUS); + } + memcpy (buffer, data, nread); + __vm_deallocate (__mach_task_self (), (vm_address_t) data, nread); + } - amount_read = __read_nocancel(fd, buffer, length); - __close_nocancel_nostatus(fd); - return amount_read; + return nread; } libc_hidden_def (__getrandom)