On Tue, Nov 29, 2022 at 11:47 AM Samuel Thibault <samuel.thiba...@gnu.org> wrote: > Sergey Bugaev, le mar. 29 nov. 2022 09:22:20 +0300, a ecrit: > > Hello everyone! > > > > I am indeed out of the army, alive and in one piece. > > !! \o/ !! > > I have to say I was very worried, I'm glad that you are back in one > piece.
Thank you so much for caring! I am in fact _so_ glad that my online friends & peers not only remembered me, but actually cared & worried about me throughout all this. Fortunately — while this has been a year of my personal hell, of being mistreated, disrespected, and humiliated — they never sent me to you-know-where. I spent all the time on a military airdrom near Moscow. So there's not that much physical injury that could happen to me, mental health notwithstanding. > > As for the SSH/arc4random issue: I believe a better workaround would > > be for glibc to cache the /dev/urandom port between calls to getrandom > > (), the same way that it caches socket server ports (see > > hurd/hurdsock.c). > > Indeed, that would solve the problem while at the same time optimize > things. 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. The existing code supports GRND_RANDOM and GRND_NONBLOCK; the latter we should still support in some way, the former I'm not sure about, given that urandom and random are the same thing. Or is that a Debian thing that glibc should not rely on? --------------------------- >8 ------------------------------ diff --git a/sysdeps/mach/hurd/getrandom.c b/sysdeps/mach/hurd/getrandom.c index ad2d3ba3..9c0ea5db 100644 --- a/sysdeps/mach/hurd/getrandom.c +++ b/sysdeps/mach/hurd/getrandom.c @@ -16,22 +16,61 @@ 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); + /* Re-check whether the port is still invalid, since someone + * could have reset it while we were waiting. */ + server = random_server; + if (MACH_PORT_VALID (server)) + goto out; + + 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 +83,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) --------------------------- 8< ------------------------------ > I'm wondering, though: does ssh fork-off other processes inside > the chroot, that might get the same issue? I don't think it does. In any case, there's nothing for it to exec inside the chroot, and just forking w/o exec'ing should work, as fork preserves ports. Sergey